├── AIO_Client ├── AIO.lua ├── AIO_Client.toc ├── Dep_LibWindow-1.1 │ ├── Changelog-LibWindow-1.1-r12.txt │ ├── LibStub.lua │ ├── LibWindow-1.1.toc │ └── LibWindow-1.1 │ │ └── LibWindow-1.1.lua ├── Dep_Smallfolk │ ├── LICENSE.md │ ├── README.md │ └── smallfolk.lua ├── lualzw-zeros │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ └── lualzw.lua └── queue.lua ├── AIO_Server ├── AIO.lua ├── Dep_LuaSrcDiet │ ├── COPYRIGHT │ ├── COPYRIGHT_Lua51 │ ├── LuaSrcDiet.lua │ ├── README │ ├── llex.lua │ ├── lparser.lua │ ├── optlex.lua │ ├── optparser.lua │ └── technotes.txt ├── Dep_Smallfolk │ ├── LICENSE.md │ ├── README.md │ └── smallfolk.lua ├── Dep_crc32lua │ ├── COPYRIGHT │ └── crc32lua.lua ├── lualzw-zeros │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ └── lualzw.lua └── queue.lua ├── Examples ├── HelloWorld.lua ├── KaevStatTest │ ├── Client.lua │ └── Server.lua ├── PersistentVariables_Client.lua ├── PingPong.lua ├── README.md ├── RunHelloFirst.lua └── TestWindow │ ├── ExampleClient.lua │ └── ExampleServer.lua ├── LICENSE └── README.md /AIO_Client/AIO_Client.toc: -------------------------------------------------------------------------------- 1 | ## Interface: 30300 2 | ## Title: AIO 3 | ## Notes: Allows sending addons from server to client and allows client-server communication. 4 | ## Author: Rochet2 5 | ## SavedVariables: AIO_sv, AIO_sv_Addons 6 | ## SavedVariablesPerCharacter: AIO_sv_char 7 | 8 | #dependencies 9 | Dep_LibWindow-1.1\LibStub.lua 10 | Dep_LibWindow-1.1\LibWindow-1.1\LibWindow-1.1.lua 11 | Dep_Smallfolk\smallfolk.lua 12 | lualzw-zeros\lualzw.lua 13 | queue.lua 14 | 15 | #core 16 | AIO.lua 17 | -------------------------------------------------------------------------------- /AIO_Client/Dep_LibWindow-1.1/Changelog-LibWindow-1.1-r12.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------ 2 | r12 | nevcairiel | 2014-10-14 19:12:48 +0000 (Tue, 14 Oct 2014) | 1 line 3 | Changed paths: 4 | M /trunk/LibWindow-1.1.toc 5 | 6 | Update TOC 7 | ------------------------------------------------------------------------ 8 | r11 | mikk | 2013-03-10 14:27:14 +0000 (Sun, 10 Mar 2013) | 1 line 9 | Changed paths: 10 | M /trunk/LibWindow-1.1.toc 11 | 12 | TOC 50200 13 | ------------------------------------------------------------------------ 14 | -------------------------------------------------------------------------------- /AIO_Client/Dep_LibWindow-1.1/LibStub.lua: -------------------------------------------------------------------------------- 1 | -- $Id: LibStub.lua 76 2007-09-03 01:50:17Z mikk $ 2 | -- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info 3 | -- LibStub is hereby placed in the Public Domain 4 | -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke 5 | local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! 6 | local LibStub = _G[LIBSTUB_MAJOR] 7 | 8 | -- Check to see is this version of the stub is obsolete 9 | if not LibStub or LibStub.minor < LIBSTUB_MINOR then 10 | LibStub = LibStub or {libs = {}, minors = {} } 11 | _G[LIBSTUB_MAJOR] = LibStub 12 | LibStub.minor = LIBSTUB_MINOR 13 | 14 | -- LibStub:NewLibrary(major, minor) 15 | -- major (string) - the major version of the library 16 | -- minor (string or number ) - the minor version of the library 17 | -- 18 | -- returns nil if a newer or same version of the lib is already present 19 | -- returns empty library object or old library object if upgrade is needed 20 | function LibStub:NewLibrary(major, minor) 21 | assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") 22 | minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") 23 | 24 | local oldminor = self.minors[major] 25 | if oldminor and oldminor >= minor then return nil end 26 | self.minors[major], self.libs[major] = minor, self.libs[major] or {} 27 | return self.libs[major], oldminor 28 | end 29 | 30 | -- LibStub:GetLibrary(major, [silent]) 31 | -- major (string) - the major version of the library 32 | -- silent (boolean) - if true, library is optional, silently return nil if its not found 33 | -- 34 | -- throws an error if the library can not be found (except silent is set) 35 | -- returns the library object if found 36 | function LibStub:GetLibrary(major, silent) 37 | if not self.libs[major] and not silent then 38 | error(("Cannot find a library instance of %q."):format(tostring(major)), 2) 39 | end 40 | return self.libs[major], self.minors[major] 41 | end 42 | 43 | -- LibStub:IterateLibraries() 44 | -- 45 | -- Returns an iterator for the currently registered libraries 46 | function LibStub:IterateLibraries() 47 | return pairs(self.libs) 48 | end 49 | 50 | setmetatable(LibStub, { __call = LibStub.GetLibrary }) 51 | end 52 | -------------------------------------------------------------------------------- /AIO_Client/Dep_LibWindow-1.1/LibWindow-1.1.toc: -------------------------------------------------------------------------------- 1 | ## Interface: 60000 2 | ## LoadOnDemand: 1 3 | ## Title: Lib: Window-1.1 4 | ## Version: 1.1.12 5 | ## Notes: A library that handles the basics of "window" style frames 6 | ## Author: Mikk 7 | ## eMail: dpsgnome@mail.com 8 | ## X-Category: Library 9 | ## X-License: Public Domain 10 | ## X-Curse-Packaged-Version: r12 11 | ## X-Curse-Project-Name: LibWindow-1.1 12 | ## X-Curse-Project-ID: libwindow-1-1 13 | ## X-Curse-Repository-ID: wow/libwindow-1-1/mainline 14 | 15 | LibStub.lua 16 | LibWindow-1.1\LibWindow-1.1.lua 17 | -------------------------------------------------------------------------------- /AIO_Client/Dep_LibWindow-1.1/LibWindow-1.1/LibWindow-1.1.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Name: LibWindow-1.1 3 | Revision: $Rev: 8 $ 4 | Author(s): Mikk (dpsgnome@mail.com) 5 | Website: http://old.wowace.com/wiki/LibWindow-1.1 6 | Documentation: http://old.wowace.com/wiki/LibWindow-1.1 7 | SVN: http://svn.wowace.com/root/trunk/WindowLib/Window-1.0 8 | Description: A library that handles the basics of "window" style frames: scaling, smart position saving, dragging.. 9 | Dependencies: none 10 | License: Public Domain 11 | ]] 12 | 13 | local MAJOR = "LibWindow-1.1" 14 | local MINOR = tonumber(("$Revision: 8 $"):match("(%d+)")) 15 | 16 | local lib = LibStub:NewLibrary(MAJOR,MINOR) 17 | if not lib then return end 18 | 19 | local min,max,abs = min,max,abs 20 | local pairs = pairs 21 | local tostring = tostring 22 | local UIParent,GetScreenWidth,GetScreenHeight,IsAltKeyDown = UIParent,GetScreenWidth,GetScreenHeight,IsAltKeyDown 23 | -- GLOBALS: error, ChatFrame1, assert 24 | 25 | local function print(msg) ChatFrame1:AddMessage(MAJOR..": "..tostring(msg)) end 26 | 27 | lib.utilFrame = lib.utilFrame or CreateFrame("Frame") 28 | lib.delayedSavePosition = lib.delayedSavePosition or {} 29 | lib.windowData = lib.windowData or {} 30 | --[frameref]={ 31 | -- names={optional names data from .RegisterConfig()} 32 | -- storage= -- tableref where config data is read/written 33 | -- altEnable=true/false 34 | --} 35 | 36 | 37 | lib.embeds = lib.embeds or {} 38 | 39 | local mixins = {} -- "FuncName"=true 40 | 41 | 42 | 43 | --------------------------------------------------------- 44 | -- UTILITIES 45 | --------------------------------------------------------- 46 | 47 | 48 | local function getStorageName(frame, name) 49 | local names = lib.windowData[frame].names 50 | if names then 51 | if names[name] then 52 | return names[name] 53 | end 54 | if names.prefix then 55 | return names.prefix .. name; 56 | end 57 | end 58 | return name; 59 | end 60 | 61 | local function setStorage(frame, name, value) 62 | lib.windowData[frame].storage[getStorageName(frame, name)] = value 63 | end 64 | 65 | local function getStorage(frame, name) 66 | return lib.windowData[frame].storage[getStorageName(frame, name)] 67 | end 68 | 69 | 70 | lib.utilFrame:SetScript("OnUpdate", function(this) 71 | this:Hide() 72 | for frame,_ in pairs(lib.delayedSavePosition) do 73 | lib.delayedSavePosition[frame] = nil 74 | lib.SavePosition(frame) 75 | end 76 | end) 77 | 78 | local function queueSavePosition(frame) 79 | lib.delayedSavePosition[frame] = true 80 | lib.utilFrame:Show() 81 | end 82 | 83 | 84 | --------------------------------------------------------- 85 | -- IMPORTANT APIS 86 | --------------------------------------------------------- 87 | 88 | mixins["RegisterConfig"]=true 89 | function lib.RegisterConfig(frame, storage, names) 90 | if not lib.windowData[frame] then 91 | lib.windowData[frame] = {} 92 | end 93 | lib.windowData[frame].names = names 94 | lib.windowData[frame].storage = storage 95 | 96 | --[[ debug 97 | frame.tx = frame:CreateTexture() 98 | frame.tx:SetTexture(0,0,0, 0.4) 99 | frame.tx:SetAllPoints(frame) 100 | frame.tx:Show() 101 | ]] 102 | end 103 | 104 | 105 | 106 | 107 | --------------------------------------------------------- 108 | -- POSITIONING AND SCALING 109 | --------------------------------------------------------- 110 | 111 | local nilParent = { 112 | GetWidth = function() 113 | return GetScreenWidth() * UIParent:GetScale() 114 | end, 115 | GetHeight = function() 116 | return GetScreenHeight() * UIParent:GetScale() 117 | end, 118 | GetScale = function() 119 | return 1 120 | end, 121 | } 122 | 123 | mixins["SavePosition"]=true 124 | function lib.SavePosition(frame) 125 | local parent = frame:GetParent() or nilParent 126 | -- No, this won't work very well with frames that aren't parented to nil or UIParent 127 | local s = frame:GetScale() 128 | local left,top = frame:GetLeft()*s, frame:GetTop()*s 129 | local right,bottom = frame:GetRight()*s, frame:GetBottom()*s 130 | local pwidth, pheight = parent:GetWidth(), parent:GetHeight() 131 | 132 | local x,y,point; 133 | if left < (pwidth-right) and left < abs((left+right)/2 - pwidth/2) then 134 | x = left; 135 | point="LEFT"; 136 | elseif (pwidth-right) < abs((left+right)/2 - pwidth/2) then 137 | x = right-pwidth; 138 | point="RIGHT"; 139 | else 140 | x = (left+right)/2 - pwidth/2; 141 | point=""; 142 | end 143 | 144 | if bottom < (pheight-top) and bottom < abs((bottom+top)/2 - pheight/2) then 145 | y = bottom; 146 | point="BOTTOM"..point; 147 | elseif (pheight-top) < abs((bottom+top)/2 - pheight/2) then 148 | y = top-pheight; 149 | point="TOP"..point; 150 | else 151 | y = (bottom+top)/2 - pheight/2; 152 | -- point=""..point; 153 | end 154 | 155 | if point=="" then 156 | point = "CENTER" 157 | end 158 | 159 | setStorage(frame, "x", x) 160 | setStorage(frame, "y", y) 161 | setStorage(frame, "point", point) 162 | setStorage(frame, "scale", s) 163 | 164 | frame:ClearAllPoints() 165 | frame:SetPoint(point, frame:GetParent(), point, x/s, y/s); 166 | end 167 | 168 | 169 | mixins["RestorePosition"]=true 170 | function lib.RestorePosition(frame) 171 | local x = getStorage(frame, "x") 172 | local y = getStorage(frame, "y") 173 | local point = getStorage(frame, "point") 174 | 175 | local s = getStorage(frame, "scale") 176 | if s then 177 | (frame.lw11origSetScale or frame.SetScale)(frame,s) 178 | else 179 | s = frame:GetScale() 180 | end 181 | 182 | if not x or not y then -- nothing stored in config yet, smack it in the center 183 | x=0; y=0; point="CENTER" 184 | end 185 | 186 | x = x/s 187 | y = y/s 188 | 189 | frame:ClearAllPoints() 190 | if not point and y==0 then -- errr why did i do this check again? must have been a reason, but i can't remember it =/ 191 | point="CENTER" 192 | end 193 | 194 | if not point then -- we have position, but no point, which probably means we're going from data stored by the addon itself before LibWindow was added to it. It was PROBABLY topleft->bottomleft anchored. Most do it that way. 195 | frame:SetPoint("TOPLEFT", frame:GetParent(), "BOTTOMLEFT", x, y) 196 | -- make it compute a better attachpoint (on next update) 197 | queueSavePosition(frame) 198 | return 199 | end 200 | 201 | frame:SetPoint(point, frame:GetParent(), point, x, y) 202 | end 203 | 204 | 205 | mixins["SetScale"]=true 206 | function lib.SetScale(frame, scale) 207 | setStorage(frame, "scale", scale); 208 | (frame.lw11origSetScale or frame.SetScale)(frame,scale) 209 | lib.RestorePosition(frame) 210 | end 211 | 212 | 213 | 214 | --------------------------------------------------------- 215 | -- DRAG SUPPORT 216 | --------------------------------------------------------- 217 | 218 | 219 | function lib.OnDragStart(frame) 220 | lib.windowData[frame].isDragging = true 221 | frame:StartMoving() 222 | end 223 | 224 | 225 | function lib.OnDragStop(frame) 226 | frame:StopMovingOrSizing() 227 | lib.SavePosition(frame) 228 | lib.windowData[frame].isDragging = false 229 | if lib.windowData[frame].altEnable and not IsAltKeyDown() then 230 | frame:EnableMouse(false) 231 | end 232 | end 233 | 234 | local function onDragStart(...) return lib.OnDragStart(...) end -- upgradable 235 | local function onDragStop(...) return lib.OnDragStop(...) end -- upgradable 236 | 237 | mixins["MakeDraggable"]=true 238 | function lib.MakeDraggable(frame) 239 | assert(lib.windowData[frame]) 240 | frame:SetMovable(true) 241 | frame:SetScript("OnDragStart", onDragStart) 242 | frame:SetScript("OnDragStop", onDragStop) 243 | frame:RegisterForDrag("LeftButton") 244 | end 245 | 246 | 247 | --------------------------------------------------------- 248 | -- MOUSEWHEEL 249 | --------------------------------------------------------- 250 | 251 | function lib.OnMouseWheel(frame, dir) 252 | local scale = getStorage(frame, "scale") 253 | if dir<0 then 254 | scale=max(scale*0.9, 0.1) 255 | else 256 | scale=min(scale/0.9, 3) 257 | end 258 | lib.SetScale(frame, scale) 259 | end 260 | 261 | local function onMouseWheel(...) return lib.OnMouseWheel(...) end -- upgradable 262 | 263 | mixins["EnableMouseWheelScaling"]=true 264 | function lib.EnableMouseWheelScaling(frame) 265 | frame:SetScript("OnMouseWheel", onMouseWheel) 266 | end 267 | 268 | 269 | --------------------------------------------------------- 270 | -- ENABLEMOUSE-ON-ALT 271 | --------------------------------------------------------- 272 | 273 | lib.utilFrame:SetScript("OnEvent", function(this, event, key, state) 274 | if event=="MODIFIER_STATE_CHANGED" then 275 | if key == "LALT" or key == "RALT" then 276 | for frame,_ in pairs(lib.altEnabledFrames) do 277 | if not lib.windowData[frame].isDragging then -- if it's already dragging, it'll disable mouse on DragStop instead 278 | frame:EnableMouse(state == 1) 279 | end 280 | end 281 | end 282 | end 283 | end) 284 | 285 | mixins["EnableMouseOnAlt"]=true 286 | function lib.EnableMouseOnAlt(frame) 287 | assert(lib.windowData[frame]) 288 | lib.windowData[frame].altEnable = true 289 | frame:EnableMouse(not not IsAltKeyDown()) 290 | if not lib.altEnabledFrames then 291 | lib.altEnabledFrames = {} 292 | lib.utilFrame:RegisterEvent("MODIFIER_STATE_CHANGED") 293 | end 294 | lib.altEnabledFrames[frame] = true 295 | end 296 | 297 | 298 | 299 | --------------------------------------------------------- 300 | -- Embed support (into FRAMES, not addons!) 301 | --------------------------------------------------------- 302 | 303 | function lib:Embed(target) 304 | if not target or not target[0] or not target.GetObjectType then 305 | error("Usage: LibWindow:Embed(frame)", 1) 306 | end 307 | target.lw11origSetScale = target.SetScale 308 | for name, _ in pairs(mixins) do 309 | target[name] = self[name] 310 | end 311 | lib.embeds[target] = true 312 | return target 313 | end 314 | 315 | for target, _ in pairs(lib.embeds) do 316 | lib:Embed(target) 317 | end 318 | -------------------------------------------------------------------------------- /AIO_Client/Dep_Smallfolk/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Robin Wellner 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /AIO_Client/Dep_Smallfolk/README.md: -------------------------------------------------------------------------------- 1 | Smallfolk 2 | ========= 3 | 4 | Smallfolk is a reasonably fast, robust, richtly-featured table serialization 5 | library for Lua. It was specifically written to allow complex data structures 6 | to be loaded from unsafe sources for [LÖVE](http://love2d.org/) games, but can 7 | be used anywhere. 8 | 9 | You use, distribute and extend Smallfolk under the terms of the MIT license. 10 | 11 | Usage 12 | ----- 13 | 14 | Smallfolk is very simple and easy to use: 15 | 16 | ```lua 17 | local smallfolk = require 'smallfolk' 18 | 19 | print(smallfolk.dumps({"Hello", world = true})) 20 | print(smallfolk.loads('{"foo":"bar"}').foo) 21 | -- prints: 22 | -- {"Hello","world":t} 23 | -- bar 24 | ``` 25 | 26 | Fast 27 | ---- 28 | 29 | Using Serpent's benchmark code, Smallfolk's serialization speed is comparable 30 | to that of Ser (and Ser is 33% faster than Serpent). 31 | 32 | It should be noted that deserialization is much slower in Smallfolk than in 33 | most other serialization libraries, because it parses the input itself instead 34 | of handing it over to Lua. However, if you use LuaJIT this difference is much 35 | less, and it is not noticable for small outputs. By default, Smallfolk rejects 36 | inputs that are too large, to prevent DOS attacks. 37 | 38 | Robust 39 | ------ 40 | 41 | Sometimes you have strange, non-euclidean geometries in your table 42 | constructions. It happens, I don't judge. Smallfolk can deal with that, where 43 | some other serialization libraries (or anything that produces JSON) cry "Iä! 44 | Iä! Cthulhu fhtagn!" and give up — or worse, silently produce incorrect 45 | data. 46 | 47 | ```lua 48 | local smallfolk = require 'smallfolk' 49 | 50 | local cthulhu = {{}, {}, {}} 51 | cthulhu.fhtagn = cthulhu 52 | cthulhu[1][cthulhu[2]] = cthulhu[3] 53 | cthulhu[2][cthulhu[1]] = cthulhu[2] 54 | cthulhu[3][cthulhu[3]] = cthulhu 55 | print(smallfolk.dumps(cthulhu)) 56 | -- prints: 57 | -- {{{@2:@3}:{@4:@1}},@3,@4,"fhtagn":@1} 58 | ``` 59 | 60 | Secure 61 | ------ 62 | 63 | Smallfolk doesn't run arbitrary Lua code, so you can safely use it when you 64 | want to read data from an untrusted source. 65 | 66 | Compact 67 | ------- 68 | 69 | Smallfolk creates really small output files compared to something like Ser when 70 | it encounters a lot of non-tree-like data, by using numbered references rather 71 | than item assignment. 72 | 73 | Tested 74 | ------ 75 | 76 | Check out `tests.lua` to see how Smallfolk behaves with all kinds of inputs. 77 | 78 | Reference 79 | --------- 80 | 81 | ###`smallfolk.dumps(object)` 82 | 83 | Returns an 8-bit string representation of `object`. Throws an error if `object` 84 | contains any types that cannot be serialised (userdata, functions and threads). 85 | 86 | ###`smallfolk.loads(string[, maxsize=10000])` 87 | 88 | Returns an object whose representation would be `string`. If the length of 89 | `string` is larger than `maxsize`, no deserialization is attempted and instead 90 | an error is thrown. If `string` is not a valid representation of any object, 91 | an error is thrown. 92 | 93 | See also 94 | -------- 95 | 96 | * [Ser](https://github.com/gvx/Ser): for trusted-source serialization 97 | * [Lady](https://github.com/gvx/Lady): for trusted-source savegames 98 | -------------------------------------------------------------------------------- /AIO_Client/Dep_Smallfolk/smallfolk.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | Smallfolk = M 3 | local expect_object, dump_object 4 | local error, tostring, pairs, type, floor, huge, concat = error, tostring, pairs, type, math.floor, math.huge, table.concat 5 | 6 | local dump_type = {} 7 | 8 | function dump_type:string(nmemo, memo, acc) 9 | local nacc = #acc 10 | acc[nacc + 1] = '"' 11 | acc[nacc + 2] = self:gsub('"', '""') 12 | acc[nacc + 3] = '"' 13 | return nmemo 14 | end 15 | 16 | function dump_type:number(nmemo, memo, acc) 17 | acc[#acc + 1] = ("%.17g"):format(self) 18 | return nmemo 19 | end 20 | 21 | function dump_type:table(nmemo, memo, acc) 22 | --[[ 23 | if memo[self] then 24 | acc[#acc + 1] = '@' 25 | acc[#acc + 1] = tostring(memo[self]) 26 | return nmemo 27 | end 28 | nmemo = nmemo + 1 29 | ]] 30 | memo[self] = nmemo 31 | acc[#acc + 1] = '{' 32 | local nself = #self 33 | for i = 1, nself do -- don't use ipairs here, we need the gaps 34 | nmemo = dump_object(self[i], nmemo, memo, acc) 35 | acc[#acc + 1] = ',' 36 | end 37 | for k, v in pairs(self) do 38 | if type(k) ~= 'number' or floor(k) ~= k or k < 1 or k > nself then 39 | nmemo = dump_object(k, nmemo, memo, acc) 40 | acc[#acc + 1] = ':' 41 | nmemo = dump_object(v, nmemo, memo, acc) 42 | acc[#acc + 1] = ',' 43 | end 44 | end 45 | acc[#acc] = acc[#acc] == '{' and '{}' or '}' 46 | return nmemo 47 | end 48 | 49 | function dump_object(object, nmemo, memo, acc) 50 | if object == true then 51 | acc[#acc + 1] = 't' 52 | elseif object == false then 53 | acc[#acc + 1] = 'f' 54 | elseif object == nil then 55 | acc[#acc + 1] = 'n' 56 | elseif object ~= object then 57 | if (''..object):sub(1,1) == '-' then 58 | acc[#acc + 1] = 'N' 59 | else 60 | acc[#acc + 1] = 'Q' 61 | end 62 | elseif object == huge then 63 | acc[#acc + 1] = 'I' 64 | elseif object == -huge then 65 | acc[#acc + 1] = 'i' 66 | else 67 | local t = type(object) 68 | if not dump_type[t] then 69 | error('cannot dump type ' .. t) 70 | end 71 | return dump_type[t](object, nmemo, memo, acc) 72 | end 73 | return nmemo 74 | end 75 | 76 | function M.dumps(object) 77 | local nmemo = 0 78 | local memo = {} 79 | local acc = {} 80 | dump_object(object, nmemo, memo, acc) 81 | return concat(acc) 82 | end 83 | 84 | local function invalid(i) 85 | error('invalid input at position ' .. i) 86 | end 87 | 88 | local nonzero_digit = {['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true, ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true} 89 | local is_digit = {['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true, ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true} 90 | local function expect_number(string, start) 91 | local i = start 92 | local head = string:sub(i, i) 93 | if head == '-' then 94 | i = i + 1 95 | head = string:sub(i, i) 96 | end 97 | if nonzero_digit[head] then 98 | repeat 99 | i = i + 1 100 | head = string:sub(i, i) 101 | until not is_digit[head] 102 | elseif head == '0' then 103 | i = i + 1 104 | head = string:sub(i, i) 105 | else 106 | invalid(i) 107 | end 108 | if head == '.' then 109 | local oldi = i 110 | repeat 111 | i = i + 1 112 | head = string:sub(i, i) 113 | until not is_digit[head] 114 | if i == oldi + 1 then 115 | invalid(i) 116 | end 117 | end 118 | if head == 'e' or head == 'E' then 119 | i = i + 1 120 | head = string:sub(i, i) 121 | if head == '+' or head == '-' then 122 | i = i + 1 123 | head = string:sub(i, i) 124 | end 125 | if not is_digit[head] then 126 | invalid(i) 127 | end 128 | repeat 129 | i = i + 1 130 | head = string:sub(i, i) 131 | until not is_digit[head] 132 | end 133 | return tonumber(string:sub(start, i - 1)), i 134 | end 135 | 136 | local expect_object_head = { 137 | t = function(string, i) return true, i end, 138 | f = function(string, i) return false, i end, 139 | n = function(string, i) return nil, i end, 140 | Q = function(string, i) return -(0/0), i end, 141 | N = function(string, i) return 0/0, i end, 142 | I = function(string, i) return 1/0, i end, 143 | i = function(string, i) return -1/0, i end, 144 | ['"'] = function(string, i) 145 | local nexti = i - 1 146 | repeat 147 | nexti = string:find('"', nexti + 1, true) + 1 148 | until string:sub(nexti, nexti) ~= '"' 149 | return string:sub(i, nexti - 2):gsub('""', '"'), nexti 150 | end, 151 | ['0'] = function(string, i) 152 | return expect_number(string, i - 1) 153 | end, 154 | ['{'] = function(string, i, tables) 155 | local nt, k, v = {} 156 | local j = 1 157 | tables[#tables + 1] = nt 158 | if string:sub(i, i) == '}' then 159 | return nt, i + 1 160 | end 161 | while true do 162 | k, i = expect_object(string, i, tables) 163 | if string:sub(i, i) == ':' then 164 | v, i = expect_object(string, i + 1, tables) 165 | nt[k] = v 166 | else 167 | nt[j] = k 168 | j = j + 1 169 | end 170 | local head = string:sub(i, i) 171 | if head == ',' then 172 | i = i + 1 173 | elseif head == '}' then 174 | return nt, i + 1 175 | else 176 | invalid(i) 177 | end 178 | end 179 | end, 180 | --[[ 181 | ['@'] = function(string, i, tables) 182 | local match = string:match('^%d+', i) 183 | local ref = tonumber(match) 184 | if tables[ref] then 185 | return tables[ref], i + #match 186 | end 187 | invalid(i) 188 | end, 189 | ]] 190 | } 191 | expect_object_head['1'] = expect_object_head['0'] 192 | expect_object_head['2'] = expect_object_head['0'] 193 | expect_object_head['3'] = expect_object_head['0'] 194 | expect_object_head['4'] = expect_object_head['0'] 195 | expect_object_head['5'] = expect_object_head['0'] 196 | expect_object_head['6'] = expect_object_head['0'] 197 | expect_object_head['7'] = expect_object_head['0'] 198 | expect_object_head['8'] = expect_object_head['0'] 199 | expect_object_head['9'] = expect_object_head['0'] 200 | expect_object_head['-'] = expect_object_head['0'] 201 | expect_object_head['.'] = expect_object_head['0'] 202 | 203 | expect_object = function(string, i, tables) 204 | local head = string:sub(i, i) 205 | if expect_object_head[head] then 206 | return expect_object_head[head](string, i + 1, tables) 207 | end 208 | invalid(i) 209 | end 210 | 211 | function M.loads(string, maxsize) 212 | if #string > (maxsize or 10000) then 213 | error 'input too large' 214 | end 215 | return (expect_object(string, 1, {})) 216 | end 217 | 218 | return M 219 | -------------------------------------------------------------------------------- /AIO_Client/lualzw-zeros/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Lua sources 2 | luac.out 3 | 4 | # luarocks build files 5 | *.src.rock 6 | *.zip 7 | *.tar.gz 8 | 9 | # Object files 10 | *.o 11 | *.os 12 | *.ko 13 | *.obj 14 | *.elf 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Libraries 21 | *.lib 22 | *.a 23 | *.la 24 | *.lo 25 | *.def 26 | *.exp 27 | 28 | # Shared objects (inc. Windows DLLs) 29 | *.dll 30 | *.so 31 | *.so.* 32 | *.dylib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | *.i*86 39 | *.x86_64 40 | *.hex 41 | 42 | -------------------------------------------------------------------------------- /AIO_Client/lualzw-zeros/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /AIO_Client/lualzw-zeros/README.md: -------------------------------------------------------------------------------- 1 | # lualzw 2 | A relatively fast LZW compression algorithm in pure lua 3 | 4 | # encoding and decoding 5 | Lossless compression for any text. The more repetition in the text, the better. 6 | 7 | 16 bit encoding is used. So each 8 bit character is encoded as 16 bit. 8 | This means that the dictionary size is 65280. 9 | 10 | Any special characters like `äöå` that are represented with multiple characters are supported. The special characters are split up into single characters that are then encoded and decoded. 11 | 12 | While compressing, the algorithm checks if the result size gets over the input. If it does, then the input is not compressed and the algorithm returns the input prematurely as the compressed result. 13 | 14 | The `zeros` branch contains a version that does not add additional null `\0` characters to the input when encoding. Any existing null characters in input string are preserved as nulls however so make sure your input does not contain nulls. 15 | 16 | # usage 17 | ```lua 18 | local lualzw = require("lualzw") 19 | 20 | local input = "foofoofoofoofoofoofoofoofoo" 21 | local compressed = assert(lualzw.compress(input)) 22 | local decompressed = assert(lualzw.decompress(compressed)) 23 | assert(input == decompressed) 24 | ``` 25 | 26 | # errors 27 | Returns nil and an error message when the algorithm fails to compress or decompress. 28 | 29 | # speed 30 | Times are in seconds. 31 | Both have the same generated input. 32 | The values are an average of 10 tries. 33 | 34 | Note that compressing random generated inputs results usually in bigger result than original. In these cases the algorithms do not compress and return input instead and thus compression result is 100% of input. 35 | 36 | lualzw is at an advantage in cases where compression cannot be done as it stops prematurely and LibCompress does not. 37 | Also lualzw is at an advantage in cases where compression can be done as it has a larger dictionary in use. 38 | 39 | Input: 1000000 random generated bytes converted into string 40 | 41 | algorithm|compress|decompress|result % of input 42 | ---------|--------|----------|------------- 43 | lualzw|0.6622|0.0003|100 44 | LibCompress|2.1983|0.0024|100 45 | 46 | Input: 1000000 random generated bytes in ASCII range converted into string 47 | 48 | algorithm|compress|decompress|result % of input 49 | ---------|--------|----------|------------- 50 | lualzw|0.812|0.0022|100 51 | LibCompress|1.782|0.0007|100 52 | 53 | Input: 1000000 random generated repeating bytes converted into string 54 | 55 | algorithm|compress|decompress|result % of input 56 | ---------|--------|----------|------------- 57 | lualzw|0.3975|0.0262|4.5001 58 | LibCompress|0.3907|0.0264|6.6997 59 | 60 | Input: 1000000 of same character 61 | 62 | algorithm|compress|decompress|result % of input 63 | ---------|--------|----------|------------- 64 | lualzw|0.7045|0.0026|0.2829 65 | LibCompress|0.6418|0.0038|0.4241 66 | 67 | Input: "ymn32h8hm8ekrwjkrn9f" repeated 50000 times. In total 1000000 bytes 68 | 69 | algorithm|compress|decompress|result % of input 70 | ---------|--------|----------|------------- 71 | lualzw|0.4788|0.0088|1.2629 72 | LibCompress|0.4426|0.0093|1.8905 73 | -------------------------------------------------------------------------------- /AIO_Client/lualzw-zeros/lualzw.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | MIT License 3 | 4 | Copyright (c) 2016 Rochet2 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | ]] 24 | 25 | local char = string.char 26 | local type = type 27 | local select = select 28 | local sub = string.sub 29 | local tconcat = table.concat 30 | 31 | local basedictcompress = {} 32 | local basedictdecompress = {} 33 | for i = 0, 255 do 34 | local ic, iic = char(i), char(i, 1) 35 | basedictcompress[ic] = iic 36 | basedictdecompress[iic] = ic 37 | end 38 | 39 | local function dictAddA(str, dict, a, b) 40 | if a >= 256 then 41 | a, b = 1, b+1 42 | if b >= 256 then 43 | dict = {} 44 | b = 2 45 | end 46 | end 47 | dict[str] = char(a,b) 48 | a = a+1 49 | return dict, a, b 50 | end 51 | 52 | local function compress(input) 53 | if type(input) ~= "string" then 54 | return nil, "string expected, got "..type(input) 55 | end 56 | local len = #input 57 | if len <= 1 then 58 | return "u"..input 59 | end 60 | 61 | local dict = {} 62 | local a, b = 1, 2 63 | 64 | local result = {"c"} 65 | local resultlen = 1 66 | local n = 2 67 | local word = "" 68 | for i = 1, len do 69 | local c = sub(input, i, i) 70 | local wc = word..c 71 | if not (basedictcompress[wc] or dict[wc]) then 72 | local write = basedictcompress[word] or dict[word] 73 | if not write then 74 | return nil, "algorithm error, could not fetch word" 75 | end 76 | result[n] = write 77 | resultlen = resultlen + #write 78 | n = n+1 79 | if len <= resultlen then 80 | return "u"..input 81 | end 82 | dict, a, b = dictAddA(wc, dict, a, b) 83 | word = c 84 | else 85 | word = wc 86 | end 87 | end 88 | result[n] = basedictcompress[word] or dict[word] 89 | resultlen = resultlen+#result[n] 90 | n = n+1 91 | if len <= resultlen then 92 | return "u"..input 93 | end 94 | return tconcat(result) 95 | end 96 | 97 | local function dictAddB(str, dict, a, b) 98 | if a >= 256 then 99 | a, b = 1, b+1 100 | if b >= 256 then 101 | dict = {} 102 | b = 2 103 | end 104 | end 105 | dict[char(a,b)] = str 106 | a = a+1 107 | return dict, a, b 108 | end 109 | 110 | local function decompress(input) 111 | if type(input) ~= "string" then 112 | return nil, "string expected, got "..type(input) 113 | end 114 | 115 | if #input < 1 then 116 | return nil, "invalid input - not a compressed string" 117 | end 118 | 119 | local control = sub(input, 1, 1) 120 | if control == "u" then 121 | return sub(input, 2) 122 | elseif control ~= "c" then 123 | return nil, "invalid input - not a compressed string" 124 | end 125 | input = sub(input, 2) 126 | local len = #input 127 | 128 | if len < 2 then 129 | return nil, "invalid input - not a compressed string" 130 | end 131 | 132 | local dict = {} 133 | local a, b = 1, 2 134 | 135 | local result = {} 136 | local n = 1 137 | local last = sub(input, 1, 2) 138 | result[n] = basedictdecompress[last] or dict[last] 139 | n = n+1 140 | for i = 3, len, 2 do 141 | local code = sub(input, i, i+1) 142 | local lastStr = basedictdecompress[last] or dict[last] 143 | if not lastStr then 144 | return nil, "could not find last from dict. Invalid input?" 145 | end 146 | local toAdd = basedictdecompress[code] or dict[code] 147 | if toAdd then 148 | result[n] = toAdd 149 | n = n+1 150 | dict, a, b = dictAddB(lastStr..sub(toAdd, 1, 1), dict, a, b) 151 | else 152 | local tmp = lastStr..sub(lastStr, 1, 1) 153 | result[n] = tmp 154 | n = n+1 155 | dict, a, b = dictAddB(tmp, dict, a, b) 156 | end 157 | last = code 158 | end 159 | return tconcat(result) 160 | end 161 | 162 | lualzw = { 163 | compress = compress, 164 | decompress = decompress, 165 | } 166 | return lualzw 167 | -------------------------------------------------------------------------------- /AIO_Client/queue.lua: -------------------------------------------------------------------------------- 1 | local Queue = {} 2 | function Queue.__index(que, key) 3 | return Queue[key] 4 | end 5 | 6 | function NewQueue() 7 | local t = {first = 0, last = -1} 8 | setmetatable(t, Queue) 9 | return t 10 | end 11 | 12 | function Queue.pushleft(que, value) 13 | local first = que.first - 1 14 | que.first = first 15 | que[first] = value 16 | return first 17 | end 18 | 19 | function Queue.pushright(que, value) 20 | local last = que.last + 1 21 | que.last = last 22 | que[last] = value 23 | return last 24 | end 25 | 26 | function Queue.popleft(que) 27 | local first = que.first 28 | if first > que.last then error("que is empty") end 29 | local value = que[first] 30 | que[first] = nil -- to allow garbage collection 31 | que.first = first + 1 32 | return value 33 | end 34 | 35 | function Queue.popright(que) 36 | local last = que.last 37 | if que.first > last then error("que is empty") end 38 | local value = que[last] 39 | que[last] = nil -- to allow garbage collection 40 | que.last = last - 1 41 | return value 42 | end 43 | 44 | function Queue.peekleft(que) 45 | return que[que.first] 46 | end 47 | 48 | function Queue.peekright(que) 49 | return que[que.last] 50 | end 51 | 52 | function Queue.empty(que) 53 | return que.last < que.first 54 | end 55 | 56 | function Queue.size(que) 57 | return que.last - que.first + 1 58 | end 59 | 60 | function Queue.clear(que) 61 | local l, r = self:getrange() 62 | for i = l, r do 63 | que[idx] = nil 64 | end 65 | que.first, que.last = 0, -1 66 | end 67 | 68 | function Queue.get(que, idx) 69 | if idx < que.first or idx > que.last then 70 | return 71 | end 72 | return que[idx] 73 | end 74 | 75 | function Queue.getrange(que) 76 | return que.first, que.last 77 | end 78 | 79 | function Queue.gettable(que) 80 | return que 81 | end 82 | 83 | return NewQueue 84 | -------------------------------------------------------------------------------- /AIO_Server/Dep_LuaSrcDiet/COPYRIGHT: -------------------------------------------------------------------------------- 1 | LuaSrcDiet License 2 | ------------------ 3 | 4 | LuaSrcDiet is licensed under the terms of the MIT license reproduced 5 | below. This means that LuaSrcDiet is free software and can be used for 6 | both academic and commercial purposes at absolutely no cost. 7 | 8 | Parts of LuaSrcDiet is based on Lua 5 code. See COPYRIGHT_Lua51 9 | (Lua 5.1.3) for Lua 5 license information. 10 | 11 | For details and rationale, see http://www.lua.org/license.html . 12 | 13 | =============================================================================== 14 | 15 | Copyright (C) 2005-2008 Kein-Hong Man 16 | Lua 5.1.3 Copyright (C) 1994-2008 Lua.org, PUC-Rio. 17 | 18 | Permission is hereby granted, free of charge, to any person obtaining a copy 19 | of this software and associated documentation files (the "Software"), to deal 20 | in the Software without restriction, including without limitation the rights 21 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 22 | copies of the Software, and to permit persons to whom the Software is 23 | furnished to do so, subject to the following conditions: 24 | 25 | The above copyright notice and this permission notice shall be included in 26 | all copies or substantial portions of the Software. 27 | 28 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 29 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 30 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 31 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 32 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 33 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 34 | THE SOFTWARE. 35 | 36 | =============================================================================== 37 | 38 | (end of COPYRIGHT) 39 | -------------------------------------------------------------------------------- /AIO_Server/Dep_LuaSrcDiet/COPYRIGHT_Lua51: -------------------------------------------------------------------------------- 1 | Lua License 2 | ----------- 3 | 4 | Lua is licensed under the terms of the MIT license reproduced below. 5 | This means that Lua is free software and can be used for both academic 6 | and commercial purposes at absolutely no cost. 7 | 8 | For details and rationale, see http://www.lua.org/license.html . 9 | 10 | =============================================================================== 11 | 12 | Copyright (C) 1994-2008 Lua.org, PUC-Rio. 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy 15 | of this software and associated documentation files (the "Software"), to deal 16 | in the Software without restriction, including without limitation the rights 17 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | copies of the Software, and to permit persons to whom the Software is 19 | furnished to do so, subject to the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included in 22 | all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 | THE SOFTWARE. 31 | 32 | =============================================================================== 33 | 34 | (end of COPYRIGHT) 35 | -------------------------------------------------------------------------------- /AIO_Server/Dep_LuaSrcDiet/LuaSrcDiet.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | --[[-------------------------------------------------------------------- 3 | 4 | LuaSrcDiet 5 | Compresses Lua source code by removing unnecessary characters. 6 | For Lua 5.1.x source code. 7 | 8 | Copyright (c) 2008 Kein-Hong Man 9 | The COPYRIGHT file describes the conditions 10 | under which this software may be distributed. 11 | 12 | See the ChangeLog for more information. 13 | 14 | ----------------------------------------------------------------------]] 15 | 16 | --[[-------------------------------------------------------------------- 17 | -- NOTES: 18 | -- * Remember to update version and date information below (MSG_TITLE) 19 | -- * TODO: to implement pcall() to properly handle lexer etc. errors 20 | -- * TODO: verify token stream or double-check binary chunk? 21 | -- * TODO: need some automatic testing for a semblance of sanity 22 | -- * TODO: the plugin module is highly experimental and unstable 23 | ----------------------------------------------------------------------]] 24 | 25 | -- standard libraries, functions 26 | local string = string 27 | local math = math 28 | local table = table 29 | local require = require 30 | local print = print 31 | local sub = string.sub 32 | local gmatch = string.gmatch 33 | 34 | -- support modules 35 | local llex = require "llex" 36 | local lparser = require "lparser" 37 | local optlex = require "optlex" 38 | local optparser = require "optparser" 39 | local plugin 40 | 41 | --[[-------------------------------------------------------------------- 42 | -- messages and textual data 43 | ----------------------------------------------------------------------]] 44 | 45 | local MSG_TITLE = [[ 46 | LuaSrcDiet: Puts your Lua 5.1 source code on a diet 47 | Version 0.11.2 (20080608) Copyright (c) 2005-2008 Kein-Hong Man 48 | The COPYRIGHT file describes the conditions under which this 49 | software may be distributed. 50 | ]] 51 | 52 | local MSG_USAGE = [[ 53 | usage: LuaSrcDiet [options] [filenames] 54 | 55 | example: 56 | >LuaSrcDiet myscript.lua -o myscript_.lua 57 | 58 | options: 59 | -v, --version prints version information 60 | -h, --help prints usage information 61 | -o specify file name to write output 62 | -s suffix for output files (default '_') 63 | --keep keep block comment with inside 64 | --plugin run in plugin/ directory 65 | - stop handling arguments 66 | 67 | (optimization levels) 68 | --none all optimizations off (normalizes EOLs only) 69 | --basic lexer-based optimizations only 70 | --maximum maximize reduction of source 71 | 72 | (informational) 73 | --quiet process files quietly 74 | --read-only read file and print token stats only 75 | --dump-lexer dump raw tokens from lexer to stdout 76 | --dump-parser dump variable tracking tables from parser 77 | --details extra info (strings, numbers, locals) 78 | 79 | features (to disable, insert 'no' prefix like --noopt-comments): 80 | %s 81 | default settings: 82 | %s]] 83 | 84 | ------------------------------------------------------------------------ 85 | -- optimization options, for ease of switching on and off 86 | -- * positive to enable optimization, negative (no) to disable 87 | -- * these options should follow --opt-* and --noopt-* style for now 88 | ------------------------------------------------------------------------ 89 | 90 | local OPTION = [[ 91 | --opt-comments,'remove comments and block comments' 92 | --opt-whitespace,'remove whitespace excluding EOLs' 93 | --opt-emptylines,'remove empty lines' 94 | --opt-eols,'all above, plus remove unnecessary EOLs' 95 | --opt-strings,'optimize strings and long strings' 96 | --opt-numbers,'optimize numbers' 97 | --opt-locals,'optimize local variable names' 98 | --opt-entropy,'tries to reduce symbol entropy of locals' 99 | ]] 100 | 101 | -- preset configuration 102 | local DEFAULT_CONFIG = [[ 103 | --opt-comments --opt-whitespace --opt-emptylines 104 | --opt-numbers --opt-locals 105 | ]] 106 | -- override configurations: MUST explicitly enable/disable everything 107 | local BASIC_CONFIG = [[ 108 | --opt-comments --opt-whitespace --opt-emptylines 109 | --noopt-eols --noopt-strings --noopt-numbers 110 | --noopt-locals 111 | ]] 112 | local MAXIMUM_CONFIG = [[ 113 | --opt-comments --opt-whitespace --opt-emptylines 114 | --opt-eols --opt-strings --opt-numbers 115 | --opt-locals --opt-entropy 116 | ]] 117 | local NONE_CONFIG = [[ 118 | --noopt-comments --noopt-whitespace --noopt-emptylines 119 | --noopt-eols --noopt-strings --noopt-numbers 120 | --noopt-locals 121 | ]] 122 | 123 | local DEFAULT_SUFFIX = "_" -- default suffix for file renaming 124 | local PLUGIN_SUFFIX = "plugin/" -- relative location of plugins 125 | 126 | --[[-------------------------------------------------------------------- 127 | -- startup and initialize option list handling 128 | ----------------------------------------------------------------------]] 129 | 130 | -- simple error message handler; change to error if traceback wanted 131 | local function die(msg) 132 | print("LuaSrcDiet: "..msg); os.exit() 133 | end 134 | --die = error--DEBUG 135 | 136 | --if not string.match(_VERSION, "5.1", 1, 1) then -- sanity check 137 | -- die("requires Lua 5.1 to run") 138 | --end 139 | 140 | ------------------------------------------------------------------------ 141 | -- prepares text for list of optimizations, prepare lookup table 142 | ------------------------------------------------------------------------ 143 | 144 | local MSG_OPTIONS = "" 145 | do 146 | local WIDTH = 24 147 | local o = {} 148 | for op, desc in gmatch(OPTION, "%s*([^,]+),'([^']+)'") do 149 | local msg = " "..op 150 | msg = msg..string.rep(" ", WIDTH - #msg)..desc.."\n" 151 | MSG_OPTIONS = MSG_OPTIONS..msg 152 | o[op] = true 153 | o["--no"..sub(op, 3)] = true 154 | end 155 | OPTION = o -- replace OPTION with lookup table 156 | end 157 | 158 | MSG_USAGE = string.format(MSG_USAGE, MSG_OPTIONS, DEFAULT_CONFIG) 159 | 160 | ------------------------------------------------------------------------ 161 | -- global variable initialization, option set handling 162 | ------------------------------------------------------------------------ 163 | 164 | local suffix = DEFAULT_SUFFIX -- file suffix 165 | local option = {} -- program options 166 | local stat_c, stat_l -- statistics tables 167 | 168 | -- function to set option lookup table based on a text list of options 169 | -- note: additional forced settings for --opt-eols is done in optlex.lua 170 | local function set_options(CONFIG) 171 | for op in gmatch(CONFIG, "(%-%-%S+)") do 172 | if sub(op, 3, 4) == "no" and -- handle negative options 173 | OPTION["--"..sub(op, 5)] then 174 | option[sub(op, 5)] = false 175 | else 176 | option[sub(op, 3)] = true 177 | end 178 | end 179 | end 180 | 181 | --[[-------------------------------------------------------------------- 182 | -- support functions 183 | ----------------------------------------------------------------------]] 184 | 185 | -- list of token types, parser-significant types are up to TTYPE_GRAMMAR 186 | -- while the rest are not used by parsers; arranged for stats display 187 | local TTYPES = { 188 | "TK_KEYWORD", "TK_NAME", "TK_NUMBER", -- grammar 189 | "TK_STRING", "TK_LSTRING", "TK_OP", 190 | "TK_EOS", 191 | "TK_COMMENT", "TK_LCOMMENT", -- non-grammar 192 | "TK_EOL", "TK_SPACE", 193 | } 194 | local TTYPE_GRAMMAR = 7 195 | 196 | local EOLTYPES = { -- EOL names for token dump 197 | ["\n"] = "LF", ["\r"] = "CR", 198 | ["\n\r"] = "LFCR", ["\r\n"] = "CRLF", 199 | } 200 | 201 | ------------------------------------------------------------------------ 202 | -- read source code from file 203 | ------------------------------------------------------------------------ 204 | 205 | local function load_file(fname) 206 | local INF = io.open(fname, "rb") 207 | if not INF then die("cannot open \""..fname.."\" for reading") end 208 | local dat = INF:read("*a") 209 | if not dat then die("cannot read from \""..fname.."\"") end 210 | INF:close() 211 | print("loadf ", type(dat)) 212 | return dat 213 | end 214 | 215 | ------------------------------------------------------------------------ 216 | -- save source code to file 217 | ------------------------------------------------------------------------ 218 | 219 | local function save_file(fname, dat) 220 | local OUTF = io.open(fname, "wb") 221 | if not OUTF then die("cannot open \""..fname.."\" for writing") end 222 | local status = OUTF:write(dat) 223 | if not status then die("cannot write to \""..fname.."\"") end 224 | OUTF:close() 225 | print("loadf ", type(dat)) 226 | end 227 | 228 | ------------------------------------------------------------------------ 229 | -- functions to deal with statistics 230 | ------------------------------------------------------------------------ 231 | 232 | -- initialize statistics table 233 | local function stat_init() 234 | stat_c, stat_l = {}, {} 235 | for i = 1, #TTYPES do 236 | local ttype = TTYPES[i] 237 | stat_c[ttype], stat_l[ttype] = 0, 0 238 | end 239 | end 240 | 241 | -- add a token to statistics table 242 | local function stat_add(tok, seminfo) 243 | stat_c[tok] = stat_c[tok] + 1 244 | stat_l[tok] = stat_l[tok] + #seminfo 245 | end 246 | 247 | -- do totals for statistics table, return average table 248 | local function stat_calc() 249 | local function avg(c, l) -- safe average function 250 | if c == 0 then return 0 end 251 | return l / c 252 | end 253 | local stat_a = {} 254 | local c, l = 0, 0 255 | for i = 1, TTYPE_GRAMMAR do -- total grammar tokens 256 | local ttype = TTYPES[i] 257 | c = c + stat_c[ttype]; l = l + stat_l[ttype] 258 | end 259 | stat_c.TOTAL_TOK, stat_l.TOTAL_TOK = c, l 260 | stat_a.TOTAL_TOK = avg(c, l) 261 | c, l = 0, 0 262 | for i = 1, #TTYPES do -- total all tokens 263 | local ttype = TTYPES[i] 264 | c = c + stat_c[ttype]; l = l + stat_l[ttype] 265 | stat_a[ttype] = avg(stat_c[ttype], stat_l[ttype]) 266 | end 267 | stat_c.TOTAL_ALL, stat_l.TOTAL_ALL = c, l 268 | stat_a.TOTAL_ALL = avg(c, l) 269 | return stat_a 270 | end 271 | 272 | --[[-------------------------------------------------------------------- 273 | -- main tasks 274 | ----------------------------------------------------------------------]] 275 | 276 | ------------------------------------------------------------------------ 277 | -- a simple token dumper, minimal translation of seminfo data 278 | ------------------------------------------------------------------------ 279 | 280 | local function dump_tokens(srcfl) 281 | -------------------------------------------------------------------- 282 | -- load file and process source input into tokens 283 | -------------------------------------------------------------------- 284 | local z = load_file(srcfl) 285 | llex.init(z) 286 | llex.llex() 287 | local toklist, seminfolist = llex.tok, llex.seminfo 288 | -------------------------------------------------------------------- 289 | -- display output 290 | -------------------------------------------------------------------- 291 | for i = 1, #toklist do 292 | local tok, seminfo = toklist[i], seminfolist[i] 293 | if tok == "TK_OP" and string.byte(seminfo) < 32 then 294 | seminfo = "(".. string.byte(seminfo)..")" 295 | elseif tok == "TK_EOL" then 296 | seminfo = EOLTYPES[seminfo] 297 | else 298 | seminfo = "'"..seminfo.."'" 299 | end 300 | print(tok.." "..seminfo) 301 | end--for 302 | end 303 | 304 | ---------------------------------------------------------------------- 305 | -- parser dump; dump globalinfo and localinfo tables 306 | ---------------------------------------------------------------------- 307 | 308 | local function dump_parser(srcfl) 309 | local print = print 310 | -------------------------------------------------------------------- 311 | -- load file and process source input into tokens 312 | -------------------------------------------------------------------- 313 | local z = load_file(srcfl) 314 | llex.init(z) 315 | llex.llex() 316 | local toklist, seminfolist, toklnlist 317 | = llex.tok, llex.seminfo, llex.tokln 318 | -------------------------------------------------------------------- 319 | -- do parser optimization here 320 | -------------------------------------------------------------------- 321 | lparser.init(toklist, seminfolist, toklnlist) 322 | local globalinfo, localinfo = lparser.parser() 323 | -------------------------------------------------------------------- 324 | -- display output 325 | -------------------------------------------------------------------- 326 | local hl = string.rep("-", 72) 327 | print("*** Local/Global Variable Tracker Tables ***") 328 | print(hl.."\n GLOBALS\n"..hl) 329 | -- global tables have a list of xref numbers only 330 | for i = 1, #globalinfo do 331 | local obj = globalinfo[i] 332 | local msg = "("..i..") '"..obj.name.."' -> " 333 | local xref = obj.xref 334 | for j = 1, #xref do msg = msg..xref[j].." " end 335 | print(msg) 336 | end 337 | -- local tables have xref numbers and a few other special 338 | -- numbers that are specially named: decl (declaration xref), 339 | -- act (activation xref), rem (removal xref) 340 | print(hl.."\n LOCALS (decl=declared act=activated rem=removed)\n"..hl) 341 | for i = 1, #localinfo do 342 | local obj = localinfo[i] 343 | local msg = "("..i..") '"..obj.name.."' decl:"..obj.decl.. 344 | " act:"..obj.act.." rem:"..obj.rem 345 | if obj.isself then 346 | msg = msg.." isself" 347 | end 348 | msg = msg.." -> " 349 | local xref = obj.xref 350 | for j = 1, #xref do msg = msg..xref[j].." " end 351 | print(msg) 352 | end 353 | print(hl.."\n") 354 | end 355 | 356 | ------------------------------------------------------------------------ 357 | -- reads source file(s) and reports some statistics 358 | ------------------------------------------------------------------------ 359 | 360 | local function read_only(srcfl) 361 | local print = print 362 | -------------------------------------------------------------------- 363 | -- load file and process source input into tokens 364 | -------------------------------------------------------------------- 365 | local z = load_file(srcfl) 366 | llex.init(z) 367 | llex.llex() 368 | local toklist, seminfolist = llex.tok, llex.seminfo 369 | print(MSG_TITLE) 370 | print("Statistics for: "..srcfl.."\n") 371 | -------------------------------------------------------------------- 372 | -- collect statistics 373 | -------------------------------------------------------------------- 374 | stat_init() 375 | for i = 1, #toklist do 376 | local tok, seminfo = toklist[i], seminfolist[i] 377 | stat_add(tok, seminfo) 378 | end--for 379 | local stat_a = stat_calc() 380 | -------------------------------------------------------------------- 381 | -- display output 382 | -------------------------------------------------------------------- 383 | local fmt = string.format 384 | local function figures(tt) 385 | return stat_c[tt], stat_l[tt], stat_a[tt] 386 | end 387 | local tabf1, tabf2 = "%-16s%8s%8s%10s", "%-16s%8d%8d%10.2f" 388 | local hl = string.rep("-", 42) 389 | print(fmt(tabf1, "Lexical", "Input", "Input", "Input")) 390 | print(fmt(tabf1, "Elements", "Count", "Bytes", "Average")) 391 | print(hl) 392 | for i = 1, #TTYPES do 393 | local ttype = TTYPES[i] 394 | print(fmt(tabf2, ttype, figures(ttype))) 395 | if ttype == "TK_EOS" then print(hl) end 396 | end 397 | print(hl) 398 | print(fmt(tabf2, "Total Elements", figures("TOTAL_ALL"))) 399 | print(hl) 400 | print(fmt(tabf2, "Total Tokens", figures("TOTAL_TOK"))) 401 | print(hl.."\n") 402 | end 403 | 404 | ------------------------------------------------------------------------ 405 | -- process source file(s), write output and reports some statistics 406 | ------------------------------------------------------------------------ 407 | 408 | local function process_file(srcfl, destfl) 409 | local function print(...) -- handle quiet option 410 | if option.QUIET then return end 411 | _G.print(...) 412 | end 413 | if plugin and plugin.init then -- plugin init 414 | option.EXIT = false 415 | plugin.init(option, srcfl, destfl) 416 | if option.EXIT then return end 417 | end 418 | print(MSG_TITLE) -- title message 419 | -------------------------------------------------------------------- 420 | -- load file and process source input into tokens 421 | -------------------------------------------------------------------- 422 | local z = load_file(srcfl) 423 | if plugin and plugin.post_load then -- plugin post-load 424 | z = plugin.post_load(z) or z 425 | if option.EXIT then return end 426 | end 427 | llex.init(z) 428 | llex.llex() 429 | local toklist, seminfolist, toklnlist 430 | = llex.tok, llex.seminfo, llex.tokln 431 | if plugin and plugin.post_lex then -- plugin post-lex 432 | plugin.post_lex(toklist, seminfolist, toklnlist) 433 | if option.EXIT then return end 434 | end 435 | -------------------------------------------------------------------- 436 | -- collect 'before' statistics 437 | -------------------------------------------------------------------- 438 | stat_init() 439 | for i = 1, #toklist do 440 | local tok, seminfo = toklist[i], seminfolist[i] 441 | stat_add(tok, seminfo) 442 | end--for 443 | local stat1_a = stat_calc() 444 | local stat1_c, stat1_l = stat_c, stat_l 445 | -------------------------------------------------------------------- 446 | -- do parser optimization here 447 | -------------------------------------------------------------------- 448 | if option["opt-locals"] then 449 | optparser.print = print -- hack 450 | lparser.init(toklist, seminfolist, toklnlist) 451 | local globalinfo, localinfo = lparser.parser() 452 | if plugin and plugin.post_parse then -- plugin post-parse 453 | plugin.post_parse(globalinfo, localinfo) 454 | if option.EXIT then return end 455 | end 456 | optparser.optimize(option, toklist, seminfolist, globalinfo, localinfo) 457 | if plugin and plugin.post_optparse then -- plugin post-optparse 458 | plugin.post_optparse() 459 | if option.EXIT then return end 460 | end 461 | end 462 | -------------------------------------------------------------------- 463 | -- do lexer optimization here, save output file 464 | -------------------------------------------------------------------- 465 | optlex.print = print -- hack 466 | toklist, seminfolist, toklnlist 467 | = optlex.optimize(option, toklist, seminfolist, toklnlist) 468 | if plugin and plugin.post_optlex then -- plugin post-optlex 469 | plugin.post_optlex(toklist, seminfolist, toklnlist) 470 | if option.EXIT then return end 471 | end 472 | local dat = table.concat(seminfolist) 473 | -- depending on options selected, embedded EOLs in long strings and 474 | -- long comments may not have been translated to \n, tack a warning 475 | if string.find(dat, "\r\n", 1, 1) or 476 | string.find(dat, "\n\r", 1, 1) then 477 | optlex.warn.mixedeol = true 478 | end 479 | -- save optimized source stream to output file 480 | save_file(destfl, dat) 481 | -------------------------------------------------------------------- 482 | -- collect 'after' statistics 483 | -------------------------------------------------------------------- 484 | stat_init() 485 | for i = 1, #toklist do 486 | local tok, seminfo = toklist[i], seminfolist[i] 487 | stat_add(tok, seminfo) 488 | end--for 489 | local stat_a = stat_calc() 490 | -------------------------------------------------------------------- 491 | -- display output 492 | -------------------------------------------------------------------- 493 | -- print("Statistics for: "..srcfl.." -> "..destfl.."\n") 494 | -- local fmt = string.format 495 | -- local function figures(tt) 496 | -- return stat1_c[tt], stat1_l[tt], stat1_a[tt], 497 | -- stat_c[tt], stat_l[tt], stat_a[tt] 498 | -- end 499 | -- local tabf1, tabf2 = "%-16s%8s%8s%10s%8s%8s%10s", 500 | -- "%-16s%8d%8d%10.2f%8d%8d%10.2f" 501 | -- local hl = string.rep("-", 68) 502 | -- print("*** lexer-based optimizations summary ***\n"..hl) 503 | -- print(fmt(tabf1, "Lexical", 504 | -- "Input", "Input", "Input", 505 | -- "Output", "Output", "Output")) 506 | -- print(fmt(tabf1, "Elements", 507 | -- "Count", "Bytes", "Average", 508 | -- "Count", "Bytes", "Average")) 509 | -- print(hl) 510 | -- for i = 1, #TTYPES do 511 | -- local ttype = TTYPES[i] 512 | -- print(fmt(tabf2, ttype, figures(ttype))) 513 | -- if ttype == "TK_EOS" then print(hl) end 514 | -- end 515 | -- print(hl) 516 | -- print(fmt(tabf2, "Total Elements", figures("TOTAL_ALL"))) 517 | -- print(hl) 518 | -- print(fmt(tabf2, "Total Tokens", figures("TOTAL_TOK"))) 519 | -- print(hl) 520 | -------------------------------------------------------------------- 521 | -- report warning flags from optimizing process 522 | -------------------------------------------------------------------- 523 | if optlex.warn.lstring then 524 | print("* WARNING: "..optlex.warn.lstring) 525 | elseif optlex.warn.mixedeol then 526 | print("* WARNING: ".."output still contains some CRLF or LFCR line endings") 527 | end 528 | print() 529 | end 530 | 531 | local function process_code(code, config) 532 | option.QUIET = true 533 | if config == 1 then 534 | set_options(DEFAULT_CONFIG) 535 | elseif config == 2 then 536 | set_options(BASIC_CONFIG) 537 | elseif config == 3 then 538 | set_options(MAXIMUM_CONFIG) 539 | else 540 | set_options(NONE_CONFIG) 541 | end 542 | 543 | local function print(...) -- handle quiet option 544 | if option.QUIET then return end 545 | _G.print(...) 546 | end 547 | -- if plugin and plugin.init then -- plugin init 548 | -- option.EXIT = false 549 | -- plugin.init(option, srcfl, destfl) 550 | -- if option.EXIT then return end 551 | -- end 552 | print(MSG_TITLE) -- title message 553 | -------------------------------------------------------------------- 554 | -- load file and process source input into tokens 555 | -------------------------------------------------------------------- 556 | local z = code -- load_file(srcfl) 557 | if plugin and plugin.post_load then -- plugin post-load 558 | z = plugin.post_load(z) or z 559 | if option.EXIT then return end 560 | end 561 | llex.init(z) 562 | llex.llex() 563 | local toklist, seminfolist, toklnlist 564 | = llex.tok, llex.seminfo, llex.tokln 565 | if plugin and plugin.post_lex then -- plugin post-lex 566 | plugin.post_lex(toklist, seminfolist, toklnlist) 567 | if option.EXIT then return end 568 | end 569 | -------------------------------------------------------------------- 570 | -- collect 'before' statistics 571 | -------------------------------------------------------------------- 572 | stat_init() 573 | for i = 1, #toklist do 574 | local tok, seminfo = toklist[i], seminfolist[i] 575 | stat_add(tok, seminfo) 576 | end--for 577 | local stat1_a = stat_calc() 578 | local stat1_c, stat1_l = stat_c, stat_l 579 | -------------------------------------------------------------------- 580 | -- do parser optimization here 581 | -------------------------------------------------------------------- 582 | if option["opt-locals"] then 583 | optparser.print = print -- hack 584 | lparser.init(toklist, seminfolist, toklnlist) 585 | local globalinfo, localinfo = lparser.parser() 586 | if plugin and plugin.post_parse then -- plugin post-parse 587 | plugin.post_parse(globalinfo, localinfo) 588 | if option.EXIT then return end 589 | end 590 | optparser.optimize(option, toklist, seminfolist, globalinfo, localinfo) 591 | if plugin and plugin.post_optparse then -- plugin post-optparse 592 | plugin.post_optparse() 593 | if option.EXIT then return end 594 | end 595 | end 596 | -------------------------------------------------------------------- 597 | -- do lexer optimization here, save output file 598 | -------------------------------------------------------------------- 599 | optlex.print = print -- hack 600 | toklist, seminfolist, toklnlist 601 | = optlex.optimize(option, toklist, seminfolist, toklnlist) 602 | if plugin and plugin.post_optlex then -- plugin post-optlex 603 | plugin.post_optlex(toklist, seminfolist, toklnlist) 604 | if option.EXIT then return end 605 | end 606 | local dat = table.concat(seminfolist) 607 | -- depending on options selected, embedded EOLs in long strings and 608 | -- long comments may not have been translated to \n, tack a warning 609 | if string.find(dat, "\r\n", 1, 1) or 610 | string.find(dat, "\n\r", 1, 1) then 611 | optlex.warn.mixedeol = true 612 | end 613 | -- save optimized source stream to output file 614 | -- save_file(destfl, dat) 615 | -------------------------------------------------------------------- 616 | -- collect 'after' statistics 617 | -------------------------------------------------------------------- 618 | -- stat_init() 619 | -- for i = 1, #toklist do 620 | -- local tok, seminfo = toklist[i], seminfolist[i] 621 | -- stat_add(tok, seminfo) 622 | -- end--for 623 | -- local stat_a = stat_calc() 624 | -------------------------------------------------------------------- 625 | -- display output 626 | -------------------------------------------------------------------- 627 | -- print("Statistics for: "..srcfl.." -> "..destfl.."\n") 628 | -- local fmt = string.format 629 | -- local function figures(tt) 630 | -- return stat1_c[tt], stat1_l[tt], stat1_a[tt], 631 | -- stat_c[tt], stat_l[tt], stat_a[tt] 632 | -- end 633 | -- local tabf1, tabf2 = "%-16s%8s%8s%10s%8s%8s%10s", 634 | -- "%-16s%8d%8d%10.2f%8d%8d%10.2f" 635 | -- local hl = string.rep("-", 68) 636 | -- print("*** lexer-based optimizations summary ***\n"..hl) 637 | -- print(fmt(tabf1, "Lexical", 638 | -- "Input", "Input", "Input", 639 | -- "Output", "Output", "Output")) 640 | -- print(fmt(tabf1, "Elements", 641 | -- "Count", "Bytes", "Average", 642 | -- "Count", "Bytes", "Average")) 643 | -- print(hl) 644 | -- for i = 1, #TTYPES do 645 | -- local ttype = TTYPES[i] 646 | -- print(fmt(tabf2, ttype, figures(ttype))) 647 | -- if ttype == "TK_EOS" then print(hl) end 648 | -- end 649 | -- print(hl) 650 | -- print(fmt(tabf2, "Total Elements", figures("TOTAL_ALL"))) 651 | -- print(hl) 652 | -- print(fmt(tabf2, "Total Tokens", figures("TOTAL_TOK"))) 653 | -- print(hl) 654 | -------------------------------------------------------------------- 655 | -- report warning flags from optimizing process 656 | -------------------------------------------------------------------- 657 | if optlex.warn.lstring then 658 | print("* WARNING: "..optlex.warn.lstring) 659 | elseif optlex.warn.mixedeol then 660 | print("* WARNING: ".."output still contains some CRLF or LFCR line endings") 661 | end 662 | print() 663 | return dat 664 | end 665 | 666 | --[[-------------------------------------------------------------------- 667 | -- main functions 668 | ----------------------------------------------------------------------]] 669 | 670 | local arg = {...} -- program arguments 671 | local fspec = {} 672 | set_options(DEFAULT_CONFIG) -- set to default options at beginning 673 | 674 | ------------------------------------------------------------------------ 675 | -- per-file handling, ship off to tasks 676 | ------------------------------------------------------------------------ 677 | 678 | local function do_files(fspec) 679 | for _, srcfl in ipairs(fspec) do 680 | local destfl 681 | ------------------------------------------------------------------ 682 | -- find and replace extension for filenames 683 | ------------------------------------------------------------------ 684 | local extb, exte = string.find(srcfl, "%.[^%.%\\%/]*$") 685 | local basename, extension = srcfl, "" 686 | if extb and extb > 1 then 687 | basename = sub(srcfl, 1, extb - 1) 688 | extension = sub(srcfl, extb, exte) 689 | end 690 | destfl = basename..suffix..extension 691 | if #fspec == 1 and option.OUTPUT_FILE then 692 | destfl = option.OUTPUT_FILE 693 | end 694 | if srcfl == destfl then 695 | die("output filename identical to input filename") 696 | end 697 | ------------------------------------------------------------------ 698 | -- perform requested operations 699 | ------------------------------------------------------------------ 700 | if option.DUMP_LEXER then 701 | dump_tokens(srcfl) 702 | elseif option.DUMP_PARSER then 703 | dump_parser(srcfl) 704 | elseif option.READ_ONLY then 705 | read_only(srcfl) 706 | else 707 | process_file(srcfl, destfl) 708 | end 709 | end--for 710 | end 711 | 712 | ------------------------------------------------------------------------ 713 | -- main function (entry point is after this definition) 714 | ------------------------------------------------------------------------ 715 | 716 | local function main() 717 | local argn, i = #arg, 1 718 | if argn == 0 then 719 | option.HELP = true 720 | end 721 | -------------------------------------------------------------------- 722 | -- handle arguments 723 | -------------------------------------------------------------------- 724 | while i <= argn do 725 | local o, p = arg[i], arg[i + 1] 726 | local dash = string.match(o, "^%-%-?") 727 | if dash == "-" then -- single-dash options 728 | if o == "-h" then 729 | option.HELP = true; break 730 | elseif o == "-v" then 731 | option.VERSION = true; break 732 | elseif o == "-s" then 733 | if not p then die("-s option needs suffix specification") end 734 | suffix = p 735 | i = i + 1 736 | elseif o == "-o" then 737 | if not p then die("-o option needs a file name") end 738 | option.OUTPUT_FILE = p 739 | i = i + 1 740 | elseif o == "-" then 741 | break -- ignore rest of args 742 | else 743 | die("unrecognized option "..o) 744 | end 745 | elseif dash == "--" then -- double-dash options 746 | if o == "--help" then 747 | option.HELP = true; break 748 | elseif o == "--version" then 749 | option.VERSION = true; break 750 | elseif o == "--keep" then 751 | if not p then die("--keep option needs a string to match for") end 752 | option.KEEP = p 753 | i = i + 1 754 | elseif o == "--plugin" then 755 | if not p then die("--plugin option needs a module name") end 756 | if option.PLUGIN then die("only one plugin can be specified") end 757 | option.PLUGIN = p 758 | plugin = require(PLUGIN_SUFFIX..p) 759 | i = i + 1 760 | elseif o == "--quiet" then 761 | option.QUIET = true 762 | elseif o == "--read-only" then 763 | option.READ_ONLY = true 764 | elseif o == "--basic" then 765 | set_options(BASIC_CONFIG) 766 | elseif o == "--maximum" then 767 | set_options(MAXIMUM_CONFIG) 768 | elseif o == "--none" then 769 | set_options(NONE_CONFIG) 770 | elseif o == "--dump-lexer" then 771 | option.DUMP_LEXER = true 772 | elseif o == "--dump-parser" then 773 | option.DUMP_PARSER = true 774 | elseif o == "--details" then 775 | option.DETAILS = true 776 | elseif OPTION[o] then -- lookup optimization options 777 | set_options(o) 778 | else 779 | die("unrecognized option "..o) 780 | end 781 | else 782 | fspec[#fspec + 1] = o -- potential filename 783 | end 784 | i = i + 1 785 | end--while 786 | if option.HELP then 787 | print(MSG_TITLE..MSG_USAGE); return true 788 | elseif option.VERSION then 789 | print(MSG_TITLE); return true 790 | end 791 | if #fspec > 0 then 792 | if #fspec > 1 and option.OUTPUT_FILE then 793 | die("with -o, only one source file can be specified") 794 | end 795 | do_files(fspec) 796 | return true 797 | else 798 | die("nothing to do!") 799 | end 800 | end 801 | 802 | -- entry point -> main() -> do_files() 803 | -- if not main() then 804 | -- die("Please run with option -h or --help for usage information") 805 | -- end 806 | 807 | -- end of script 808 | 809 | return process_code 810 | -------------------------------------------------------------------------------- /AIO_Server/Dep_LuaSrcDiet/README: -------------------------------------------------------------------------------- 1 | 2 | LuaSrcDiet 3 | Compresses Lua source code by removing unnecessary characters. 4 | 5 | Copyright (c) 2005-2008 Kein-Hong Man 6 | The COPYRIGHT file describes the conditions 7 | under which this software may be distributed. 8 | 9 | http://luaforge.net/projects/luasrcdiet/ 10 | http://luasrcdiet.luaforge.net/ 11 | 12 | -- 13 | 14 | For the older unmaintained version of LuaSrcDiet for Lua 5.0.2 sources, 15 | please see the 5.0/README file. 16 | 17 | -- 18 | 19 | PREVIEW NOTES 20 | 21 | See also: http://luasrcdiet.luaforge.net/ 22 | 23 | The 0.11.0 release of LuaSrcDiet has a local variable name optimizer. 24 | Local variable names are renamed into the shortest possible names. In 25 | addition, variable names are reused whenever possible, reducing the 26 | number of unique variable names. Several hundred local variable names 27 | can be reduced into 53 or less unique names, which allows all locals 28 | to be single-character in length. 29 | 30 | The local variable name optimizer uses a full parser of Lua 5.1 source 31 | code, thus it can rename all local variables, including function 32 | parameters. It should handle the implicit "self" parameter gracefully. 33 | The optimizer needs more testing, but is already able to optimize the 34 | LuaSrcDiet sources itself and generate correct Lua output. 35 | 36 | String and number token optimizations are also performed, apart from the 37 | usual whitespace, line ending and comment removal. Numbers can switch 38 | between different formats. Strings can be simplified and can switch 39 | delimiters between " or ' characters. 40 | 41 | Most options can also be enabled or disabled separately, for maximum 42 | flexibility. If you need to keep a copyright message in the optimized 43 | output, the --keep option can keep block comments that contain a certain 44 | string. 45 | 46 | For samples, see the sample/ directory. Performance statistics can be 47 | found in the sample/statistics.txt file. Preliminary test samples for 48 | strings and numbers can also be found in the sample/ directory. 49 | 50 | Priority for future work: 51 | (a) automatic tests for lexer/parser optimizations 52 | (b) integrity checking, token stream check or binary chunk check 53 | 54 | -- 55 | 56 | INTRODUCTION 57 | 58 | ... 59 | 60 | WARNING! Locals optimization does NOT have support for 'arg' vararg 61 | functions (LUA_COMPAT_VARARG). 62 | 63 | -- 64 | 65 | WHAT'S NEW 66 | 67 | Major changes for version 0.11.2 (see the ChangeLog as well): 68 | * improved local variable name allocation, more efficient now 69 | * added experimental --plugin option with an example plugin script 70 | * added a SLOC plugin to count SLOC for Lua 5.1 source files 71 | * added a HTML plugin to see globals and locals marked 72 | 73 | Major changes for version 0.11.1 (see the ChangeLog as well): 74 | * --detail option for more string, number and local variable info 75 | * fixed a local rename bug that generates names that are keywords 76 | * added explanatory notes on local variable optimization 77 | * added --opt-entropy option for locals to reduce symbol entropy 78 | 79 | Major changes for version 0.11.0 (see the ChangeLog as well): 80 | * Local variable name optimization. 81 | * Many options and sample output added. 82 | 83 | Major changes for version 0.10.2 (see the ChangeLog as well): 84 | * Aggressive optimizations for string and number tokens. 85 | * Minor bug fixes. 86 | 87 | Major changes for version 0.10.1 (see the ChangeLog as well): 88 | * Totally rewritten for Lua 5.1.x. 89 | 90 | -- 91 | 92 | USAGE OPTIONS 93 | 94 | ... 95 | 96 | Example of summary data display: 97 | 98 | Statistics for: LuaSrcDiet.lua -> sample/LuaSrcDiet.lua 99 | 100 | *** local variable optimization summary *** 101 | ---------------------------------------------------------- 102 | Variable Unique Decl. Token Size Average 103 | Types Names Count Count Bytes Bytes 104 | ---------------------------------------------------------- 105 | Global 10 0 19 95 5.00 106 | ---------------------------------------------------------- 107 | Local (in) 88 153 683 3340 4.89 108 | TOTAL (in) 98 153 702 3435 4.89 109 | ---------------------------------------------------------- 110 | Local (out) 32 153 683 683 1.00 111 | TOTAL (out) 42 153 702 778 1.11 112 | ---------------------------------------------------------- 113 | 114 | *** lexer-based optimizations summary *** 115 | -------------------------------------------------------------------- 116 | Lexical Input Input Input Output Output Output 117 | Elements Count Bytes Average Count Bytes Average 118 | -------------------------------------------------------------------- 119 | TK_KEYWORD 374 1531 4.09 374 1531 4.09 120 | TK_NAME 795 3963 4.98 795 1306 1.64 121 | TK_NUMBER 54 59 1.09 54 59 1.09 122 | TK_STRING 152 1725 11.35 152 1717 11.30 123 | TK_LSTRING 7 1976 282.29 7 1976 282.29 124 | TK_OP 997 1092 1.10 997 1092 1.10 125 | TK_EOS 1 0 0.00 1 0 0.00 126 | -------------------------------------------------------------------- 127 | TK_COMMENT 140 6884 49.17 1 18 18.00 128 | TK_LCOMMENT 7 1723 246.14 0 0 0.00 129 | TK_EOL 543 543 1.00 197 197 1.00 130 | TK_SPACE 1270 2465 1.94 263 263 1.00 131 | -------------------------------------------------------------------- 132 | Total Elements 4340 21961 5.06 2841 8159 2.87 133 | -------------------------------------------------------------------- 134 | Total Tokens 2380 10346 4.35 2380 7681 3.23 135 | -------------------------------------------------------------------- 136 | 137 | -- 138 | 139 | USING LUASRCDIET 140 | 141 | ... 142 | 143 | Please see the command line help or see sample/Makefile for examples. 144 | 145 | This is experimental software and nothing has been done yet on a proper 146 | installation scheme for use with normal work. A thousand apologies... 147 | 148 | -- 149 | 150 | CODE SIZE REDUCTION 151 | 152 | ... 153 | 154 | -- 155 | 156 | OTHER OPTIONS 157 | 158 | ... 159 | 160 | -- 161 | 162 | BEHAVIOUR NOTES 163 | 164 | * embedded line endings in strings and long strings always 165 | normalized to LF 166 | * will not optimize trailing spaces in long strings, only warns 167 | * scientific notation generated in number optimzation is not in 168 | canonical form, this may or may not be a bad thing, so feedback 169 | is welcome 170 | 171 | -- 172 | 173 | ACKNOWLEDGEMENTS 174 | 175 | Thanks to the LuaForge people for hosting this. 176 | Developed on SciTE http://www.scintilla.org/. Two thumbs up. 177 | 178 | -- 179 | 180 | FEEDBACK 181 | 182 | Feedback and contributions are welcome. Your name will be acknowledged, 183 | as long as you are willing to comply with COPYRIGHT. If your material is 184 | self-contained, you can retain a copyright notice for those material in 185 | your own name, as long as you use the same Lua 5/MIT-style copyright. 186 | 187 | My alternative e-mail address is: keinhong AT gmail DOT com 188 | 189 | Enjoy!! 190 | 191 | Kein-Hong Man (esq.) 192 | Kuala Lumpur 193 | Malaysia 20080603 194 | -------------------------------------------------------------------------------- /AIO_Server/Dep_LuaSrcDiet/llex.lua: -------------------------------------------------------------------------------- 1 | --[[-------------------------------------------------------------------- 2 | 3 | base.llex.lua: Lua 5.1 lexical analyzer in Lua 4 | This file is part of LuaSrcDiet, based on Yueliang material. 5 | 6 | Copyright (c) 2008 Kein-Hong Man 7 | The COPYRIGHT file describes the conditions 8 | under which this software may be distributed. 9 | 10 | See the ChangeLog for more information. 11 | 12 | ----------------------------------------------------------------------]] 13 | 14 | --[[-------------------------------------------------------------------- 15 | -- NOTES: 16 | -- * This is a version of the native 5.1.x lexer from Yueliang 0.4.0, 17 | -- with significant modifications to handle LuaSrcDiet's needs: 18 | -- (1) base.llex.error is an optional error function handler 19 | -- (2) base.seminfo for strings include their delimiters and no 20 | -- translation operations are performed on them 21 | -- * ADDED shbang handling has been added to support executable scripts 22 | -- * NO localized decimal point replacement magic 23 | -- * NO limit to number of lines 24 | -- * NO support for compatible long strings (LUA_COMPAT_LSTR) 25 | -- * Please read technotes.txt for more technical details. 26 | ----------------------------------------------------------------------]] 27 | 28 | local base = {} 29 | -- local base = _G 30 | -- local string = require "string" 31 | -- module "base.llex" 32 | 33 | local find = string.find 34 | local match = string.match 35 | local sub = string.sub 36 | 37 | ---------------------------------------------------------------------- 38 | -- initialize keyword list, variables 39 | ---------------------------------------------------------------------- 40 | 41 | local kw = {} 42 | for v in string.gmatch([[ 43 | and break do else elseif end false for function if in 44 | local nil not or repeat return then true until while]], "%S+") do 45 | kw[v] = true 46 | end 47 | 48 | -- NOTE: see init() for module variables (externally visible): 49 | -- base.tok, base.seminfo, base.tokln 50 | 51 | local z, -- source stream 52 | sourceid, -- name of source 53 | I, -- position of lexer 54 | buff, -- buffer for strings 55 | ln -- line number 56 | 57 | ---------------------------------------------------------------------- 58 | -- add information to token listing 59 | ---------------------------------------------------------------------- 60 | 61 | local function addtoken(token, info) 62 | local i = #base.tok + 1 63 | base.tok[i] = token 64 | base.seminfo[i] = info 65 | base.tokln[i] = ln 66 | end 67 | 68 | ---------------------------------------------------------------------- 69 | -- handles line number incrementation and end-of-line characters 70 | ---------------------------------------------------------------------- 71 | 72 | local function inclinenumber(i, is_tok) 73 | local sub = sub 74 | local old = sub(z, i, i) 75 | i = i + 1 -- skip '\n' or '\r' 76 | local c = sub(z, i, i) 77 | if (c == "\n" or c == "\r") and (c ~= old) then 78 | i = i + 1 -- skip '\n\r' or '\r\n' 79 | old = old..c 80 | end 81 | if is_tok then addtoken("TK_EOL", old) end 82 | ln = ln + 1 83 | I = i 84 | return i 85 | end 86 | 87 | ---------------------------------------------------------------------- 88 | -- initialize lexer for given source _z and source name _sourceid 89 | ---------------------------------------------------------------------- 90 | 91 | function base.init(_z, _sourceid) 92 | z = _z -- source 93 | sourceid = _sourceid -- name of source 94 | I = 1 -- lexer's position in source 95 | ln = 1 -- line number 96 | base.tok = {} -- lexed token list* 97 | base.seminfo = {} -- lexed semantic information list* 98 | base.tokln = {} -- line numbers for messages* 99 | -- (*) externally visible thru' module 100 | -------------------------------------------------------------------- 101 | -- initial processing (shbang handling) 102 | -------------------------------------------------------------------- 103 | local p, _, q, r = find(z, "^(#[^\r\n]*)(\r?\n?)") 104 | if p then -- skip first line 105 | I = I + #q 106 | addtoken("TK_COMMENT", q) 107 | if #r > 0 then inclinenumber(I, true) end 108 | end 109 | end 110 | 111 | ---------------------------------------------------------------------- 112 | -- returns a chunk name or id, no truncation for long names 113 | ---------------------------------------------------------------------- 114 | 115 | function base.chunkid() 116 | if sourceid and match(sourceid, "^[=@]") then 117 | return sub(sourceid, 2) -- remove first char 118 | end 119 | return "[string]" 120 | end 121 | 122 | ---------------------------------------------------------------------- 123 | -- formats error message and throws error 124 | -- * a simplified version, does not report what token was responsible 125 | ---------------------------------------------------------------------- 126 | 127 | function base.errorline(s, line) 128 | local e = error or base.error 129 | e(string.format("%s:%d: %s", base.chunkid(), line or ln, s)) 130 | end 131 | 132 | ------------------------------------------------------------------------ 133 | -- count separators ("=") in a long string delimiter 134 | ------------------------------------------------------------------------ 135 | 136 | local function skip_sep(i) 137 | local sub = sub 138 | local s = sub(z, i, i) 139 | i = i + 1 140 | local count = #match(z, "=*", i) -- note, take the length 141 | i = i + count 142 | I = i 143 | return (sub(z, i, i) == s) and count or (-count) - 1 144 | end 145 | 146 | ---------------------------------------------------------------------- 147 | -- reads a long string or long comment 148 | ---------------------------------------------------------------------- 149 | 150 | local function read_long_string(is_str, sep) 151 | local i = I + 1 -- skip 2nd '[' 152 | local sub = sub 153 | local c = sub(z, i, i) 154 | if c == "\r" or c == "\n" then -- string starts with a newline? 155 | i = inclinenumber(i) -- skip it 156 | end 157 | local j = i 158 | while true do 159 | local p, q, r = find(z, "([\r\n%]])", i) -- (long range) 160 | if not p then 161 | base.errorline(is_str and "unfinished long string" or 162 | "unfinished long comment") 163 | end 164 | i = p 165 | if r == "]" then -- delimiter test 166 | if skip_sep(i) == sep then 167 | buff = sub(z, buff, I) 168 | I = I + 1 -- skip 2nd ']' 169 | return buff 170 | end 171 | i = I 172 | else -- newline 173 | buff = buff.."\n" 174 | i = inclinenumber(i) 175 | end 176 | end--while 177 | end 178 | 179 | ---------------------------------------------------------------------- 180 | -- reads a string 181 | ---------------------------------------------------------------------- 182 | 183 | local function read_string(del) 184 | local i = I 185 | local find = find 186 | local sub = sub 187 | while true do 188 | local p, q, r = find(z, "([\n\r\\\"\'])", i) -- (long range) 189 | if p then 190 | if r == "\n" or r == "\r" then 191 | base.errorline("unfinished string") 192 | end 193 | i = p 194 | if r == "\\" then -- handle escapes 195 | i = i + 1 196 | r = sub(z, i, i) 197 | if r == "" then break end -- (EOZ error) 198 | p = find("abfnrtv\n\r", r, 1, true) 199 | ------------------------------------------------------ 200 | if p then -- special escapes 201 | if p > 7 then 202 | i = inclinenumber(i) 203 | else 204 | i = i + 1 205 | end 206 | ------------------------------------------------------ 207 | elseif find(r, "%D") then -- other non-digits 208 | i = i + 1 209 | ------------------------------------------------------ 210 | else -- \xxx sequence 211 | local p, q, s = find(z, "^(%d%d?%d?)", i) 212 | i = q + 1 213 | if s + 1 > 256 then -- UCHAR_MAX 214 | base.errorline("escape sequence too large") 215 | end 216 | ------------------------------------------------------ 217 | end--if p 218 | else 219 | i = i + 1 220 | if r == del then -- ending delimiter 221 | I = i 222 | return sub(z, buff, i - 1) -- return string 223 | end 224 | end--if r 225 | else 226 | break -- (error) 227 | end--if p 228 | end--while 229 | base.errorline("unfinished string") 230 | end 231 | 232 | ------------------------------------------------------------------------ 233 | -- main lexer function 234 | ------------------------------------------------------------------------ 235 | 236 | function base.llex() 237 | local find = find 238 | local match = match 239 | while true do--outer 240 | local i = I 241 | -- inner loop allows break to be used to nicely section tests 242 | while true do--inner 243 | ---------------------------------------------------------------- 244 | local p, _, r = find(z, "^([_%a][_%w]*)", i) 245 | if p then 246 | I = i + #r 247 | if kw[r] then 248 | addtoken("TK_KEYWORD", r) -- reserved word (keyword) 249 | else 250 | addtoken("TK_NAME", r) -- identifier 251 | end 252 | break -- (continue) 253 | end 254 | ---------------------------------------------------------------- 255 | local p, _, r = find(z, "^(%.?)%d", i) 256 | if p then -- numeral 257 | if r == "." then i = i + 1 end 258 | local _, q, r = find(z, "^%d*[%.%d]*([eE]?)", i) 259 | i = q + 1 260 | if #r == 1 then -- optional exponent 261 | if match(z, "^[%+%-]", i) then -- optional sign 262 | i = i + 1 263 | end 264 | end 265 | local _, q = find(z, "^[_%w]*", i) 266 | I = q + 1 267 | local v = sub(z, p, q) -- string equivalent 268 | if not tonumber(v) then -- handles hex test also 269 | base.errorline("malformed number") 270 | end 271 | addtoken("TK_NUMBER", v) 272 | break -- (continue) 273 | end 274 | ---------------------------------------------------------------- 275 | local p, q, r, t = find(z, "^((%s)[ \t\v\f]*)", i) 276 | if p then 277 | if t == "\n" or t == "\r" then -- newline 278 | inclinenumber(i, true) 279 | else 280 | I = q + 1 -- whitespace 281 | addtoken("TK_SPACE", r) 282 | end 283 | break -- (continue) 284 | end 285 | ---------------------------------------------------------------- 286 | local r = match(z, "^%p", i) 287 | if r then 288 | buff = i 289 | local p = find("-[\"\'.=<>~", r, 1, true) 290 | if p then 291 | -- two-level if block for punctuation/symbols 292 | -------------------------------------------------------- 293 | if p <= 2 then 294 | if p == 1 then -- minus 295 | local c = match(z, "^%-%-(%[?)", i) 296 | if c then 297 | i = i + 2 298 | local sep = -1 299 | if c == "[" then 300 | sep = skip_sep(i) 301 | end 302 | if sep >= 0 then -- long comment 303 | addtoken("TK_LCOMMENT", read_long_string(false, sep)) 304 | else -- short comment 305 | I = find(z, "[\n\r]", i) or (#z + 1) 306 | addtoken("TK_COMMENT", sub(z, buff, I - 1)) 307 | end 308 | break -- (continue) 309 | end 310 | -- (fall through for "-") 311 | else -- [ or long string 312 | local sep = skip_sep(i) 313 | if sep >= 0 then 314 | addtoken("TK_LSTRING", read_long_string(true, sep)) 315 | elseif sep == -1 then 316 | addtoken("TK_OP", "[") 317 | else 318 | base.errorline("invalid long string delimiter") 319 | end 320 | break -- (continue) 321 | end 322 | -------------------------------------------------------- 323 | elseif p <= 5 then 324 | if p < 5 then -- strings 325 | I = i + 1 326 | addtoken("TK_STRING", read_string(r)) 327 | break -- (continue) 328 | end 329 | r = match(z, "^%.%.?%.?", i) -- .|..|... dots 330 | -- (fall through) 331 | -------------------------------------------------------- 332 | else -- relational 333 | r = match(z, "^%p=?", i) 334 | -- (fall through) 335 | end 336 | end 337 | I = i + #r 338 | addtoken("TK_OP", r) -- for other symbols, fall through 339 | break -- (continue) 340 | end 341 | ---------------------------------------------------------------- 342 | local r = sub(z, i, i) 343 | if r ~= "" then 344 | I = i + 1 345 | addtoken("TK_OP", r) -- other single-char tokens 346 | break 347 | end 348 | addtoken("TK_EOS", "") -- end of stream, 349 | return base -- exit here 350 | ---------------------------------------------------------------- 351 | end--while inner 352 | end--while outer 353 | end 354 | 355 | return base 356 | -------------------------------------------------------------------------------- /AIO_Server/Dep_LuaSrcDiet/optparser.lua: -------------------------------------------------------------------------------- 1 | --[[-------------------------------------------------------------------- 2 | 3 | optparser.lua: does parser-based optimizations 4 | This file is part of LuaSrcDiet. 5 | 6 | Copyright (c) 2008 Kein-Hong Man 7 | The COPYRIGHT file describes the conditions 8 | under which this software may be distributed. 9 | 10 | See the ChangeLog for more information. 11 | 12 | ----------------------------------------------------------------------]] 13 | 14 | --[[-------------------------------------------------------------------- 15 | -- NOTES: 16 | -- * For more parser-based optimization ideas, see the TODO items or 17 | -- look at technotes.txt. 18 | -- * The processing load is quite significant, but since this is an 19 | -- off-line text processor, I believe we can wait a few seconds. 20 | -- * TODO: might process "local a,a,a" wrongly... need tests! 21 | -- * TODO: remove position handling if overlapped locals (rem < 0) 22 | -- needs more study, to check behaviour 23 | -- * TODO: there are probably better ways to do allocation, e.g. by 24 | -- choosing better methods to sort and pick locals... 25 | -- * TODO: we don't need 53*63 two-letter identifiers; we can make 26 | -- do with significantly less depending on how many that are really 27 | -- needed and improve entropy; e.g. 13 needed -> choose 4*4 instead 28 | ----------------------------------------------------------------------]] 29 | 30 | local base = {} 31 | -- local base = _G 32 | -- local string = require "string" 33 | -- local table = require "table" 34 | -- module "optparser" 35 | 36 | ---------------------------------------------------------------------- 37 | -- Letter frequencies for reducing symbol entropy (fixed version) 38 | -- * Might help a wee bit when the output file is compressed 39 | -- * See Wikipedia: http://en.wikipedia.org/wiki/Letter_frequencies 40 | -- * We use letter frequencies according to a Linotype keyboard, plus 41 | -- the underscore, and both lower case and upper case letters. 42 | -- * The arrangement below (LC, underscore, %d, UC) is arbitrary. 43 | -- * This is certainly not optimal, but is quick-and-dirty and the 44 | -- process has no significant overhead 45 | ---------------------------------------------------------------------- 46 | 47 | local LETTERS = "etaoinshrdlucmfwypvbgkqjxz_ETAOINSHRDLUCMFWYPVBGKQJXZ" 48 | local ALPHANUM = "etaoinshrdlucmfwypvbgkqjxz_0123456789ETAOINSHRDLUCMFWYPVBGKQJXZ" 49 | 50 | -- names or identifiers that must be skipped 51 | -- * the first two lines are for keywords 52 | local SKIP_NAME = {} 53 | for v in string.gmatch([[ 54 | and break do else elseif end false for function if in 55 | local nil not or repeat return then true until while 56 | self]], "%S+") do 57 | SKIP_NAME[v] = true 58 | end 59 | 60 | ------------------------------------------------------------------------ 61 | -- variables and data structures 62 | ------------------------------------------------------------------------ 63 | 64 | local toklist, seminfolist, -- token lists 65 | globalinfo, localinfo, -- variable information tables 66 | globaluniq, localuniq, -- unique name tables 67 | var_new, -- index of new variable names 68 | varlist -- list of output variables 69 | 70 | ---------------------------------------------------------------------- 71 | -- preprocess information table to get lists of unique names 72 | ---------------------------------------------------------------------- 73 | 74 | local function preprocess(infotable) 75 | local uniqtable = {} 76 | for i = 1, #infotable do -- enumerate info table 77 | local obj = infotable[i] 78 | local name = obj.name 79 | -------------------------------------------------------------------- 80 | if not uniqtable[name] then -- not found, start an entry 81 | uniqtable[name] = { 82 | decl = 0, token = 0, size = 0, 83 | } 84 | end 85 | -------------------------------------------------------------------- 86 | local uniq = uniqtable[name] -- count declarations, tokens, size 87 | uniq.decl = uniq.decl + 1 88 | local xref = obj.xref 89 | local xcount = #xref 90 | uniq.token = uniq.token + xcount 91 | uniq.size = uniq.size + xcount * #name 92 | -------------------------------------------------------------------- 93 | if obj.decl then -- if local table, create first,last pairs 94 | obj.id = i 95 | obj.xcount = xcount 96 | if xcount > 1 then -- if ==1, means local never accessed 97 | obj.first = xref[2] 98 | obj.last = xref[xcount] 99 | end 100 | -------------------------------------------------------------------- 101 | else -- if global table, add a back ref 102 | uniq.id = i 103 | end 104 | -------------------------------------------------------------------- 105 | end--for 106 | return uniqtable 107 | end 108 | 109 | ---------------------------------------------------------------------- 110 | -- calculate actual symbol frequencies, in order to reduce entropy 111 | -- * this may help further reduce the size of compressed sources 112 | -- * note that since parsing optimizations is put before lexing 113 | -- optimizations, the frequency table is not exact! 114 | -- * yes, this will miss --keep block comments too... 115 | ---------------------------------------------------------------------- 116 | 117 | local function recalc_for_entropy(option) 118 | local byte = string.byte 119 | local char = string.char 120 | -- table of token classes to accept in calculating symbol frequency 121 | local ACCEPT = { 122 | TK_KEYWORD = true, TK_NAME = true, TK_NUMBER = true, 123 | TK_STRING = true, TK_LSTRING = true, 124 | } 125 | if not option["opt-comments"] then 126 | ACCEPT.TK_COMMENT = true 127 | ACCEPT.TK_LCOMMENT = true 128 | end 129 | -------------------------------------------------------------------- 130 | -- create a new table and remove any original locals by filtering 131 | -------------------------------------------------------------------- 132 | local filtered = {} 133 | for i = 1, #toklist do 134 | filtered[i] = seminfolist[i] 135 | end 136 | for i = 1, #localinfo do -- enumerate local info table 137 | local obj = localinfo[i] 138 | local xref = obj.xref 139 | for j = 1, obj.xcount do 140 | local p = xref[j] 141 | filtered[p] = "" -- remove locals 142 | end 143 | end 144 | -------------------------------------------------------------------- 145 | local freq = {} -- reset symbol frequency table 146 | for i = 0, 255 do freq[i] = 0 end 147 | for i = 1, #toklist do -- gather symbol frequency 148 | local tok, info = toklist[i], filtered[i] 149 | if ACCEPT[tok] then 150 | for j = 1, #info do 151 | local c = byte(info, j) 152 | freq[c] = freq[c] + 1 153 | end 154 | end--if 155 | end--for 156 | -------------------------------------------------------------------- 157 | -- function to re-sort symbols according to actual frequencies 158 | -------------------------------------------------------------------- 159 | local function resort(symbols) 160 | local symlist = {} 161 | for i = 1, #symbols do -- prepare table to sort 162 | local c = byte(symbols, i) 163 | symlist[i] = { c = c, freq = freq[c], } 164 | end 165 | table.sort(symlist, -- sort selected symbols 166 | function(v1, v2) 167 | return v1.freq > v2.freq 168 | end 169 | ) 170 | local charlist = {} -- reconstitute the string 171 | for i = 1, #symlist do 172 | charlist[i] = char(symlist[i].c) 173 | end 174 | return table.concat(charlist) 175 | end 176 | -------------------------------------------------------------------- 177 | LETTERS = resort(LETTERS) -- change letter arrangement 178 | ALPHANUM = resort(ALPHANUM) 179 | end 180 | 181 | ---------------------------------------------------------------------- 182 | -- returns a string containing a new local variable name to use, and 183 | -- a flag indicating whether it collides with a global variable 184 | -- * trapping keywords and other names like 'self' is done elsewhere 185 | ---------------------------------------------------------------------- 186 | 187 | local function new_var_name() 188 | local var 189 | local cletters, calphanum = #LETTERS, #ALPHANUM 190 | local v = var_new 191 | if v < cletters then -- single char 192 | v = v + 1 193 | var = string.sub(LETTERS, v, v) 194 | else -- longer names 195 | local range, sz = cletters, 1 -- calculate # chars fit 196 | repeat 197 | v = v - range 198 | range = range * calphanum 199 | sz = sz + 1 200 | until range > v 201 | local n = v % cletters -- left side cycles faster 202 | v = (v - n) / cletters -- do first char first 203 | n = n + 1 204 | var = string.sub(LETTERS, n, n) 205 | while sz > 1 do 206 | local m = v % calphanum 207 | v = (v - m) / calphanum 208 | m = m + 1 209 | var = var..string.sub(ALPHANUM, m, m) 210 | sz = sz - 1 211 | end 212 | end 213 | var_new = var_new + 1 214 | return var, globaluniq[var] ~= nil 215 | end 216 | 217 | ---------------------------------------------------------------------- 218 | -- calculate and print some statistics 219 | -- * probably better in main source, put here for now 220 | ---------------------------------------------------------------------- 221 | 222 | local function stats_summary(globaluniq, localuniq, afteruniq, option) 223 | local fmt = string.format 224 | local opt_details = option.DETAILS 225 | local uniq_g , uniq_li, uniq_lo, uniq_ti, uniq_to, -- stats needed 226 | decl_g, decl_li, decl_lo, decl_ti, decl_to, 227 | token_g, token_li, token_lo, token_ti, token_to, 228 | size_g, size_li, size_lo, size_ti, size_to 229 | = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 231 | local function avg(c, l) -- safe average function 232 | if c == 0 then return 0 end 233 | return l / c 234 | end 235 | -------------------------------------------------------------------- 236 | -- collect statistics (note: globals do not have declarations!) 237 | -------------------------------------------------------------------- 238 | for name, uniq in pairs(globaluniq) do 239 | uniq_g = uniq_g + 1 240 | token_g = token_g + uniq.token 241 | size_g = size_g + uniq.size 242 | end 243 | for name, uniq in pairs(localuniq) do 244 | uniq_li = uniq_li + 1 245 | decl_li = decl_li + uniq.decl 246 | token_li = token_li + uniq.token 247 | size_li = size_li + uniq.size 248 | end 249 | for name, uniq in pairs(afteruniq) do 250 | uniq_lo = uniq_lo + 1 251 | decl_lo = decl_lo + uniq.decl 252 | token_lo = token_lo + uniq.token 253 | size_lo = size_lo + uniq.size 254 | end 255 | uniq_ti = uniq_g + uniq_li 256 | decl_ti = decl_g + decl_li 257 | token_ti = token_g + token_li 258 | size_ti = size_g + size_li 259 | uniq_to = uniq_g + uniq_lo 260 | decl_to = decl_g + decl_lo 261 | token_to = token_g + token_lo 262 | size_to = size_g + size_lo 263 | -------------------------------------------------------------------- 264 | -- detailed stats: global list 265 | -------------------------------------------------------------------- 266 | if opt_details then 267 | local sorted = {} -- sort table of unique global names by size 268 | for name, uniq in pairs(globaluniq) do 269 | uniq.name = name 270 | sorted[#sorted + 1] = uniq 271 | end 272 | table.sort(sorted, 273 | function(v1, v2) 274 | return v1.size > v2.size 275 | end 276 | ) 277 | local tabf1, tabf2 = "%8s%8s%10s %s", "%8d%8d%10.2f %s" 278 | local hl = string.rep("-", 44) 279 | print("*** global variable list (sorted by size) ***\n"..hl) 280 | print(fmt(tabf1, "Token", "Input", "Input", "Global")) 281 | print(fmt(tabf1, "Count", "Bytes", "Average", "Name")) 282 | print(hl) 283 | for i = 1, #sorted do 284 | local uniq = sorted[i] 285 | print(fmt(tabf2, uniq.token, uniq.size, avg(uniq.token, uniq.size), uniq.name)) 286 | end 287 | print(hl) 288 | print(fmt(tabf2, token_g, size_g, avg(token_g, size_g), "TOTAL")) 289 | print(hl.."\n") 290 | -------------------------------------------------------------------- 291 | -- detailed stats: local list 292 | -------------------------------------------------------------------- 293 | local tabf1, tabf2 = "%8s%8s%8s%10s%8s%10s %s", "%8d%8d%8d%10.2f%8d%10.2f %s" 294 | local hl = string.rep("-", 70) 295 | print("*** local variable list (sorted by allocation order) ***\n"..hl) 296 | print(fmt(tabf1, "Decl.", "Token", "Input", "Input", "Output", "Output", "Global")) 297 | print(fmt(tabf1, "Count", "Count", "Bytes", "Average", "Bytes", "Average", "Name")) 298 | print(hl) 299 | for i = 1, #varlist do -- iterate according to order assigned 300 | local name = varlist[i] 301 | local uniq = afteruniq[name] 302 | local old_t, old_s = 0, 0 303 | for j = 1, #localinfo do -- find corresponding old names and calculate 304 | local obj = localinfo[j] 305 | if obj.name == name then 306 | old_t = old_t + obj.xcount 307 | old_s = old_s + obj.xcount * #obj.oldname 308 | end 309 | end 310 | print(fmt(tabf2, uniq.decl, uniq.token, old_s, avg(old_t, old_s), 311 | uniq.size, avg(uniq.token, uniq.size), name)) 312 | end 313 | print(hl) 314 | print(fmt(tabf2, decl_lo, token_lo, size_li, avg(token_li, size_li), 315 | size_lo, avg(token_lo, size_lo), "TOTAL")) 316 | print(hl.."\n") 317 | end--if opt_details 318 | -------------------------------------------------------------------- 319 | -- display output 320 | -------------------------------------------------------------------- 321 | -- local tabf1, tabf2 = "%-16s%8s%8s%8s%8s%10s", "%-16s%8d%8d%8d%8d%10.2f" 322 | -- local hl = string.rep("-", 58) 323 | -- print("*** local variable optimization summary ***\n"..hl) 324 | -- print(fmt(tabf1, "Variable", "Unique", "Decl.", "Token", "Size", "Average")) 325 | -- print(fmt(tabf1, "Types", "Names", "Count", "Count", "Bytes", "Bytes")) 326 | -- print(hl) 327 | -- print(fmt(tabf2, "Global", uniq_g, decl_g, token_g, size_g, avg(token_g, size_g))) 328 | -- print(hl) 329 | -- print(fmt(tabf2, "Local (in)", uniq_li, decl_li, token_li, size_li, avg(token_li, size_li))) 330 | -- print(fmt(tabf2, "TOTAL (in)", uniq_ti, decl_ti, token_ti, size_ti, avg(token_ti, size_ti))) 331 | -- print(hl) 332 | -- print(fmt(tabf2, "Local (out)", uniq_lo, decl_lo, token_lo, size_lo, avg(token_lo, size_lo))) 333 | -- print(fmt(tabf2, "TOTAL (out)", uniq_to, decl_to, token_to, size_to, avg(token_to, size_to))) 334 | -- print(hl.."\n") 335 | end 336 | 337 | ---------------------------------------------------------------------- 338 | -- main entry point 339 | -- * does only local variable optimization for now 340 | ---------------------------------------------------------------------- 341 | 342 | function base.optimize(option, _toklist, _seminfolist, _globalinfo, _localinfo) 343 | -- set tables 344 | toklist, seminfolist, globalinfo, localinfo 345 | = _toklist, _seminfolist, _globalinfo, _localinfo 346 | var_new = 0 -- reset variable name allocator 347 | varlist = {} 348 | ------------------------------------------------------------------ 349 | -- preprocess global/local tables, handle entropy reduction 350 | ------------------------------------------------------------------ 351 | globaluniq = preprocess(globalinfo) 352 | localuniq = preprocess(localinfo) 353 | if option["opt-entropy"] then -- for entropy improvement 354 | recalc_for_entropy(option) 355 | end 356 | ------------------------------------------------------------------ 357 | -- build initial declared object table, then sort according to 358 | -- token count, this might help assign more tokens to more common 359 | -- variable names such as 'e' thus possibly reducing entropy 360 | -- * an object knows its localinfo index via its 'id' field 361 | -- * special handling for "self" special local (parameter) here 362 | ------------------------------------------------------------------ 363 | local object = {} 364 | for i = 1, #localinfo do 365 | object[i] = localinfo[i] 366 | end 367 | table.sort(object, -- sort largest first 368 | function(v1, v2) 369 | return v1.xcount > v2.xcount 370 | end 371 | ) 372 | ------------------------------------------------------------------ 373 | -- the special "self" function parameters must be preserved 374 | -- * the allocator below will never use "self", so it is safe to 375 | -- keep those implicit declarations as-is 376 | ------------------------------------------------------------------ 377 | local temp, j, gotself = {}, 1, false 378 | for i = 1, #object do 379 | local obj = object[i] 380 | if not obj.isself then 381 | temp[j] = obj 382 | j = j + 1 383 | else 384 | gotself = true 385 | end 386 | end 387 | object = temp 388 | ------------------------------------------------------------------ 389 | -- a simple first-come first-served heuristic name allocator, 390 | -- note that this is in no way optimal... 391 | -- * each object is a local variable declaration plus existence 392 | -- * the aim is to assign short names to as many tokens as possible, 393 | -- so the following tries to maximize name reuse 394 | -- * note that we preserve sort order 395 | ------------------------------------------------------------------ 396 | local nobject = #object 397 | while nobject > 0 do 398 | local varname, gcollide 399 | repeat 400 | varname, gcollide = new_var_name() -- collect a variable name 401 | until not SKIP_NAME[varname] -- skip all special names 402 | varlist[#varlist + 1] = varname -- keep a list 403 | local oleft = nobject 404 | ------------------------------------------------------------------ 405 | -- if variable name collides with an existing global, the name 406 | -- cannot be used by a local when the name is accessed as a global 407 | -- during which the local is alive (between 'act' to 'rem'), so 408 | -- we drop objects that collides with the corresponding global 409 | ------------------------------------------------------------------ 410 | if gcollide then 411 | -- find the xref table of the global 412 | local gref = globalinfo[globaluniq[varname].id].xref 413 | local ngref = #gref 414 | -- enumerate for all current objects; all are valid at this point 415 | for i = 1, nobject do 416 | local obj = object[i] 417 | local act, rem = obj.act, obj.rem -- 'live' range of local 418 | -- if rem < 0, it is a -id to a local that had the same name 419 | -- so follow rem to extend it; does this make sense? 420 | while rem < 0 do 421 | rem = localinfo[-rem].rem 422 | end 423 | local drop 424 | for j = 1, ngref do 425 | local p = gref[j] 426 | if p >= act and p <= rem then drop = true end -- in range? 427 | end 428 | if drop then 429 | obj.skip = true 430 | oleft = oleft - 1 431 | end 432 | end--for 433 | end--if gcollide 434 | ------------------------------------------------------------------ 435 | -- now the first unassigned local (since it's sorted) will be the 436 | -- one with the most tokens to rename, so we set this one and then 437 | -- eliminate all others that collides, then any locals that left 438 | -- can then reuse the same variable name; this is repeated until 439 | -- all local declaration that can use this name is assigned 440 | -- * the criteria for local-local reuse/collision is: 441 | -- A is the local with a name already assigned 442 | -- B is the unassigned local under consideration 443 | -- => anytime A is accessed, it cannot be when B is 'live' 444 | -- => to speed up things, we have first/last accesses noted 445 | ------------------------------------------------------------------ 446 | while oleft > 0 do 447 | local i = 1 448 | while object[i].skip do -- scan for first object 449 | i = i + 1 450 | end 451 | ------------------------------------------------------------------ 452 | -- first object is free for assignment of the variable name 453 | -- [first,last] gives the access range for collision checking 454 | ------------------------------------------------------------------ 455 | oleft = oleft - 1 456 | local obja = object[i] 457 | i = i + 1 458 | obja.newname = varname 459 | obja.skip = true 460 | obja.done = true 461 | local first, last = obja.first, obja.last 462 | local xref = obja.xref 463 | ------------------------------------------------------------------ 464 | -- then, scan all the rest and drop those colliding 465 | -- if A was never accessed then it'll never collide with anything 466 | -- otherwise trivial skip if: 467 | -- * B was activated after A's last access (last < act) 468 | -- * B was removed before A's first access (first > rem) 469 | -- if not, see detailed skip below... 470 | ------------------------------------------------------------------ 471 | if first and oleft > 0 then -- must have at least 1 access 472 | local scanleft = oleft 473 | while scanleft > 0 do 474 | while object[i].skip do -- next valid object 475 | i = i + 1 476 | end 477 | scanleft = scanleft - 1 478 | local objb = object[i] 479 | i = i + 1 480 | local act, rem = objb.act, objb.rem -- live range of B 481 | -- if rem < 0, extend range of rem thru' following local 482 | while rem < 0 do 483 | rem = localinfo[-rem].rem 484 | end 485 | -------------------------------------------------------- 486 | if not(last < act or first > rem) then -- possible collision 487 | -------------------------------------------------------- 488 | -- B is activated later than A or at the same statement, 489 | -- this means for no collision, A cannot be accessed when B 490 | -- is alive, since B overrides A (or is a peer) 491 | -------------------------------------------------------- 492 | if act >= obja.act then 493 | for j = 1, obja.xcount do -- ... then check every access 494 | local p = xref[j] 495 | if p >= act and p <= rem then -- A accessed when B live! 496 | oleft = oleft - 1 497 | objb.skip = true 498 | break 499 | end 500 | end--for 501 | -------------------------------------------------------- 502 | -- A is activated later than B, this means for no collision, 503 | -- A's access is okay since it overrides B, but B's last 504 | -- access need to be earlier than A's activation time 505 | -------------------------------------------------------- 506 | else 507 | if objb.last and objb.last >= obja.act then 508 | oleft = oleft - 1 509 | objb.skip = true 510 | end 511 | end 512 | end 513 | -------------------------------------------------------- 514 | if oleft == 0 then break end 515 | end 516 | end--if first 517 | ------------------------------------------------------------------ 518 | end--while 519 | ------------------------------------------------------------------ 520 | -- after assigning all possible locals to one variable name, the 521 | -- unassigned locals/objects have the skip field reset and the table 522 | -- is compacted, to hopefully reduce iteration time 523 | ------------------------------------------------------------------ 524 | local temp, j = {}, 1 525 | for i = 1, nobject do 526 | local obj = object[i] 527 | if not obj.done then 528 | obj.skip = false 529 | temp[j] = obj 530 | j = j + 1 531 | end 532 | end 533 | object = temp -- new compacted object table 534 | nobject = #object -- objects left to process 535 | ------------------------------------------------------------------ 536 | end--while 537 | ------------------------------------------------------------------ 538 | -- after assigning all locals with new variable names, we can 539 | -- patch in the new names, and reprocess to get 'after' stats 540 | ------------------------------------------------------------------ 541 | for i = 1, #localinfo do -- enumerate all locals 542 | local obj = localinfo[i] 543 | local xref = obj.xref 544 | if obj.newname then -- if got new name, patch it in 545 | for j = 1, obj.xcount do 546 | local p = xref[j] -- xrefs indexes the token list 547 | seminfolist[p] = obj.newname 548 | end 549 | obj.name, obj.oldname -- adjust names 550 | = obj.newname, obj.name 551 | else 552 | obj.oldname = obj.name -- for cases like 'self' 553 | end 554 | end 555 | ------------------------------------------------------------------ 556 | -- deal with statistics output 557 | ------------------------------------------------------------------ 558 | if gotself then -- add 'self' to end of list 559 | varlist[#varlist + 1] = "self" 560 | end 561 | local afteruniq = preprocess(localinfo) 562 | stats_summary(globaluniq, localuniq, afteruniq, option) 563 | ------------------------------------------------------------------ 564 | end 565 | 566 | return base 567 | -------------------------------------------------------------------------------- /AIO_Server/Dep_LuaSrcDiet/technotes.txt: -------------------------------------------------------------------------------- 1 | Tech Notes for LuaSrcDiet 2 | ========================= 3 | 4 | The following are notes on the optimization process for easy reference. 5 | 6 | 7 | Miscellaneous Ideas, TODO Stuff 8 | =============================== 9 | 10 | Other Ideas: 11 | (a) remove unused locals that can be removed in the source 12 | (b) remove declarations using nil 13 | (c) remove table constructor elements using nil 14 | (d) extra optional semicolon removal 15 | (e) extra comma or semicolon removal in table constructors 16 | (f) special number forms: using ^ and * to shorten constants: 1^16 17 | (g) simple declaration of locals that can be merged: local a,b,c,d 18 | (h) warn of opportunity for using a local to zap a bunch of globals 19 | (i) warn of trailing whitespace in strings or long strings 20 | (j) spaces to tabs in comments/long comments/long strings 21 | (k) convert long strings to normal strings, vice versa 22 | (l) simplify logical or relational operator expression 23 | 24 | 25 | Modified Lexer Output 26 | ===================== 27 | 28 | The lexer is works almost exactly like llex.c in 'normal' Lua. Instead 29 | of returning one token on each call, the lexer processes the entire 30 | string (from an entire file) and returns. Two lists (tokens and semantic 31 | information items) are set up in the module for use by the caller. 32 | 33 | For maximum flexibility during processing, the lexer returns non-grammar 34 | lexical elements as tokens too. Non-grammar elements, such as comments, 35 | whitespace, line endings, are classified along with 'normal' tokens. The 36 | lexer classifies 7 kinds of grammar tokens and 4 kinds of non-grammar 37 | tokens: 38 | 39 | --------------------------------------------------------------------- 40 | TOKEN CLASS DESCRIPTION 41 | --------------------------------------------------------------------- 42 | "TK_KEYWORD" keywords 43 | "TK_NAME" identifiers 44 | "TK_NUMBER" numbers (unconverted, kept in original form) 45 | "TK_STRING" strings (no translation is done, includes delimiters) 46 | "TK_LSTRING" long strings (no translation is done, includes delimiters) 47 | "TK_OP" operators and punctuation (most single-char, some double) 48 | "TK_EOS" end-of-stream (there is only one for each file/stream) 49 | --------------------------------------------------------------------- 50 | "TK_SPACE" whitespace (generally, spaces, \t, \v and \f) 51 | "TK_COMMENT" comments (includes delimiters, also includes special 52 | first line shbang, which is handled specially in the 53 | optimizer) 54 | "TK_LCOMMENT" block comments (includes delimiters) 55 | "TK_EOL" end-of-lines (excludes those embedded in strings) 56 | --------------------------------------------------------------------- 57 | 58 | 59 | Table for Lexer-Based Optimizations 60 | =================================== 61 | 62 | We aim to keep lexer-based optimizations free of parser considerations, 63 | i.e. we allow for generalized optimization of token sequences. The table 64 | below considers the requirements for all combinations of significant 65 | tokens. Other tokens are whitespace-like. Comments can be considered to 66 | be a special kind of whitespace, e.g. a short comment needs to have a 67 | following EOL token, if we do not want to optimize away short comments. 68 | 69 | FIRST SECOND TOKEN 70 | TOKEN | 71 | | V 72 | V Keyword Name Number String LString Oper 73 | -------------------------------------------------------- 74 | Keyword [S] [S] [S] 0 0 0 75 | Name [S] [S] [S] 0 0 0 76 | Number [S] [S] [S] 0 0 [1] 77 | String 0 0 0 0 0 0 78 | LString 0 0 0 0 0 0 79 | Oper 0 0 [1] 0 0 [2] 80 | -------------------------------------------------------- 81 | 82 | [S] = need at least one whitespace (set as either a space or keep EOL) 83 | 84 | [1] = need a space if operator is a '.', all others okay; a '+' or '-' 85 | is used as part of a floating-point spec, but there does not 86 | appear to be any way of creating a float by joining with number 87 | with a a '+' or '-' plus another number, because an 'e' has to 88 | be somewhere in the first token, this can't be done 89 | 90 | [2] = normally there cannot be consecutive operators, but we plan to 91 | allow for generalized optimization of token sequences, i.e. even 92 | sequences that are grammatically illegal; so disallow adjacent 93 | operators if: 94 | (a) the first is in [=<>] and the second is '=' 95 | (b) disallow dot sequences to be adjacent, but "..." first okay 96 | (c) disallow '[' followed by '=' or '[' (not optimal) 97 | 98 | Also, a minus '-' cannot preceed a Comment or LComment, because comments 99 | start with a '--' prefix. Apart from that, all Comment or LComment 100 | tokens can be set abut with a real token. 101 | 102 | 103 | Sequence of Lexer-Based Optimization Process 104 | ============================================ 105 | 106 | *** TODO *** 107 | 108 | 109 | Description of Locals Optimization 110 | ================================== 111 | 112 | VARIABLE TRACKING AND LOCAL VARIABLE RENAMING 113 | 114 | (A) TK_NAME token class considerations 115 | -------------------------------------- 116 | 117 | A TK_NAME token means a number of things, and some of these cannot be 118 | renamed. We are interested in the use of TK_NAME in the following: 119 | 120 | (a) global variable access 121 | (b) local variable declaration, includes local statements, local 122 | functions, function parameters, implicit "self" local, etc. 123 | (c) local variable access, including upvalue access 124 | 125 | TK_NAME is also used in parts of grammar as constant strings -- these 126 | tokens cannot be optimized without user assistance. These include: 127 | 128 | (d) as the key in key=value pairs in table construction 129 | (e) as field or method names in a:b or a.b syntax forms 130 | 131 | For local variable name optimization, we do not need to consider (d) and 132 | (e), and while global variables cannot be renamed (since we do not have 133 | support for user assistance), they need to be considered as part of 134 | Lua's variable access scheme. 135 | 136 | (B) Lifetime of a local variable 137 | -------------------------------- 138 | 139 | Take the following example: 140 | 141 | local string, table = string, table 142 | 143 | In the example, the two locals are assigned the values of the globals 144 | with the same names. Therefore, when Lua encounters the declaration 145 | portion: 146 | 147 | local string, table 148 | 149 | The parser cannot immediately make the two local variable available to 150 | following code. In the parser and code generator, locals are inactive 151 | when its entry is created. They are activated only when the function 152 | adjustlocalvars() is called to activate the appropriate local variables. 153 | 154 | In the example, the two local variables are activated only after the 155 | whole statement has been parsed, that is, after the last "table" token. 156 | Hence, the statement works as expected. Also, once the two local 157 | variables goes out of scope, removevars() is called to deactivate them, 158 | allowing other variables of the same name to become visible again. 159 | 160 | Another example worth mentioning is: 161 | 162 | local a, a, a, = 1, 2, 3 163 | 164 | The above will assign 3 to 'a'. 165 | 166 | Thus, when optimizing local variable names, (1) we need to consider 167 | accesses of global variable names affecting the namespace, (2) for the 168 | local variable names themselves, we need to consider when they are 169 | declared, activated and removed, and (3) within the 'live' time of 170 | locals, we need to know when they are accessed (since locals that are 171 | never accessed don't really matter.) 172 | 173 | (C) Local variable tracking 174 | --------------------------- 175 | 176 | Every local variable declaration is considered an object to be renamed. 177 | 178 | From the parser, we have the original name of the local variable, the 179 | token positions for declaration, activation and removal, and the token 180 | position for all the TK_NAME tokens which references this local. All 181 | instances of the implicit "self" local variable are flagged as such. 182 | 183 | In addition to local variable information, all global variable accesses 184 | are tabled, one object entry for one name, and each object has a 185 | corresponding list of token positions for the TK_NAME tokens, which is 186 | where the global variables were accessed. 187 | 188 | The key criteria is: Our act of renaming cannot change the visibility of 189 | any of these locals and globals at the time they are accessed. 190 | 191 | Of course, if every variable has a unique name, then there is no need 192 | for a name allocation algorithm, as there will be no conflict. But, in 193 | order to maximize utilization of short identifier names, we want to 194 | reuse the names as much as possible. In addition, fewer names will 195 | likely reduce symbol entropy and may slightly improve compressibility of 196 | the source code. 197 | 198 | (D) Name allocation theory 199 | -------------------------- 200 | 201 | To understand the renaming algorithm, first we need to establish how 202 | different local and global variables can operate happily without 203 | interfering with each other. 204 | 205 | Consider three objects, local object A, local object B and global object 206 | G. A and B involve declaration, activation and removal, and within the 207 | period it is active, there may be zero or more accesses of the local. 208 | For G, there are only global variable accesses to look into. 209 | 210 | Assume that we have assigned a new name to A and we wish to consider its 211 | effects on other locals and globals, for which we choose B and G as 212 | examples. We assume local B has not been assigned a new name as we 213 | expect our algorithm to take care of collisions. 214 | 215 | A's lifetime is something like this: 216 | 217 | Decl Act Rem 218 | + +-------------------------------+ 219 | ------------------------------------------------- 220 | 221 | where 'Decl' is the time of declaration, 'Act' is the time of 222 | activation, and 'Rem' is the time of removal. Between 'Act' and 'Rem', 223 | the local is alive or 'live' and Lua can see it if its corresponding 224 | TK_NAME identifier comes up. 225 | 226 | Decl Act Rem 227 | + +-------------------------------+ 228 | ------------------------------------------------- 229 | * * * * 230 | (1) (2) (3) (4) 231 | 232 | Recall that the key criteria is to not change the visibility of globals 233 | and locals. Consider local and global accesses at (1), (2), (3) and (4). 234 | 235 | A global G of the same name as A will only collide at (3), where Lua 236 | will see A and not G. Since G must be accessed at (3) according to what 237 | the parser says, and we cannot modify the positions of 'Decl', 'Act' and 238 | 'Rem', it follows that A cannot have the same name as G. 239 | 240 | Decl Act Rem 241 | + +-----------------------+ 242 | --------------------------------- 243 | (1)+ +---+ (2)+ +---+ (3)+ +---+ (4)+ +---+ 244 | --------- --------- --------- --------- 245 | 246 | For the case of A and B having the same names and colliding, consider 247 | the cases for which B is at (1), (2), (3) or (4) in the above. 248 | 249 | (1) and (4) means that A and B are completely isolated from each other, 250 | hence in the two cases, A and B can safely use the same variable names. 251 | To be specific, since we have assigned A, B is considered completely 252 | isolated from A if B's Activation-to-Removal period is isolated from 253 | the time of A's first access to last access, meaning B's active time 254 | will never affect any of A's accesses. 255 | 256 | For (2) and (3), we have two cases where we need to consider which one 257 | has been activated first. For (2), B is active before A, so A cannot 258 | impose on B. But A's accesses are valid while B is active, since A can 259 | override B. For no collision in the case of (2), we simply need to 260 | ensure that the last access of B occurs before A is activated. 261 | 262 | For (3), B is activated before A, hence B can override A's accesses. For 263 | no collision, all of A's accesses cannot happen while B is active. Thus 264 | position (3) follows the "A is never accessed when B is active" rule in 265 | a general way. Local variables of a child function are in the position 266 | of (3). To illustrate, the local B can use the same name as local A and 267 | live in a child function or block scope if each time A is accessed, Lua 268 | sees A and not B. So we have to check all accesses of A and see whether 269 | they collide with the active period of B. Now if A was never accessed, 270 | then B can be active anywhere. 271 | 272 | The above appears to resolve all sorts of cases where the active times 273 | of A and B overlap. If there is a more simple scheme, do let me know. 274 | Note that in the above, the allocator does not need to know how locals 275 | are separated according to function prototypes. Perhaps the allocator 276 | can be simplified if knowledge of function structure is utilized. 277 | 278 | (E) Name allocation algorithm 279 | ----------------------------- 280 | 281 | To begin with, the name generator is mostly separate from the name 282 | allocation algorithm. The name generator returns the next shortest name 283 | for the algorithm to apply to local variables. To attempt to reduce 284 | symbol entropy (which benefit compression algorithms), the name 285 | generator follows English frequent letter usage. Later, there may be an 286 | option to calculate an actual symbol entropy table from the input data. 287 | 288 | Since there are 53 one-character identifiers and (53*63-4) two-character 289 | identifiers (minus a few keywords), there isn't a pressing need to 290 | optimally maximize name reuse. Sample files show that we can eventually 291 | get 20 tokens per identifier name, thus a source file can have over 1000 292 | local variable tokens that are all single character in length. 293 | 294 | In theory, we should need no more than 260 local identifiers by default. 295 | Why? Since LUAI_MAXVARS is 200 and LUAI_MAXUPVALUES is 60, at any block 296 | scope, there can be at most (LUAI_MAXVARS + LUAI_MAXUPVALUES) locals 297 | referenced, or 260. Also, those from outer scopes not referenced in 298 | inner scopes can reuse identifiers. The net effect of this is that a 299 | local variable name allocation method should not allocate more than 260 300 | identifier names for locals. 301 | 302 | The current algorithm is a simple first-come first-served scheme: 303 | 304 | (a) One local object that use the most tokens is named first. 305 | (b) Any other non-conflicting locals with respect to the first 306 | object are assigned the same name. 307 | (c) Assigned locals are removed and the procedure is repeated for 308 | objects that have not been assigned new names. (a) to (c) 309 | repeats until no local objects are left. 310 | 311 | In addition, there are a few extra issues to take care of: 312 | 313 | (d) Implicit "self" locals that have been flagged as such are 314 | already "assigned to" and so they are left unmodified. 315 | (e) The name generator skips "self" to avoid conflicts. This 316 | is not optimal but it is unlikely a script will use so many 317 | local variables as to reach "self". 318 | (f) Keywords are also skipped for the name generator. 319 | (g) Global name conflict resolution. 320 | 321 | For (g), global name conflict resolution is handled just after the new 322 | name is generated. The name can still be used for some locals even if it 323 | conflicts with other locals. To remove conflicts, global variable 324 | accesses for the particular identifier name is checked. Any local 325 | variables that are active when a global access is made is marked to be 326 | skipped. The rest of the local objects can then use that name. 327 | 328 | The algorithm has special handling for locals that use the same name in 329 | the same scope. For example: 330 | 331 | local foo = 10 -- (1) 332 | ... 333 | local foo = 20 -- (2) 334 | ... 335 | print(e) 336 | 337 | Since we are considering name visibility, the first 'foo' does not 338 | really cease to exist when the second 'foo' is declared, because if we 339 | were to make that assumption, and the first 'foo' is removed before (2), 340 | then I should be able to use 'e' as the name for the first 'foo' and 341 | after (2), it should not conflict with variables in the outer scope 342 | with the same name. To illustrate: 343 | 344 | local e = 10 -- 'foo ' renamed to 'e' 345 | ... 346 | local t = 20 -- error if we assumed 'e' removed here 347 | ... 348 | print(e) 349 | 350 | Since 'e' is a global in the example, we now have an error as the 351 | name as been taken over by a local. Thus, the first 'foo' local must 352 | have its active time extend to the end of the current scope. If there 353 | is no conflict between the first and second 'foo', the algorithm may 354 | still assign the same names to them. 355 | 356 | The current fix to deal with the above chains local objects in order to 357 | find the removal position. Practically, the parser can be modified to 358 | simplify this. 359 | 360 | 361 | END. 362 | -------------------------------------------------------------------------------- /AIO_Server/Dep_Smallfolk/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Robin Wellner 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /AIO_Server/Dep_Smallfolk/README.md: -------------------------------------------------------------------------------- 1 | Smallfolk 2 | ========= 3 | 4 | Smallfolk is a reasonably fast, robust, richtly-featured table serialization 5 | library for Lua. It was specifically written to allow complex data structures 6 | to be loaded from unsafe sources for [LÖVE](http://love2d.org/) games, but can 7 | be used anywhere. 8 | 9 | You use, distribute and extend Smallfolk under the terms of the MIT license. 10 | 11 | Usage 12 | ----- 13 | 14 | Smallfolk is very simple and easy to use: 15 | 16 | ```lua 17 | local smallfolk = require 'smallfolk' 18 | 19 | print(smallfolk.dumps({"Hello", world = true})) 20 | print(smallfolk.loads('{"foo":"bar"}').foo) 21 | -- prints: 22 | -- {"Hello","world":t} 23 | -- bar 24 | ``` 25 | 26 | Fast 27 | ---- 28 | 29 | Using Serpent's benchmark code, Smallfolk's serialization speed is comparable 30 | to that of Ser (and Ser is 33% faster than Serpent). 31 | 32 | It should be noted that deserialization is much slower in Smallfolk than in 33 | most other serialization libraries, because it parses the input itself instead 34 | of handing it over to Lua. However, if you use LuaJIT this difference is much 35 | less, and it is not noticable for small outputs. By default, Smallfolk rejects 36 | inputs that are too large, to prevent DOS attacks. 37 | 38 | Robust 39 | ------ 40 | 41 | Sometimes you have strange, non-euclidean geometries in your table 42 | constructions. It happens, I don't judge. Smallfolk can deal with that, where 43 | some other serialization libraries (or anything that produces JSON) cry "Iä! 44 | Iä! Cthulhu fhtagn!" and give up — or worse, silently produce incorrect 45 | data. 46 | 47 | ```lua 48 | local smallfolk = require 'smallfolk' 49 | 50 | local cthulhu = {{}, {}, {}} 51 | cthulhu.fhtagn = cthulhu 52 | cthulhu[1][cthulhu[2]] = cthulhu[3] 53 | cthulhu[2][cthulhu[1]] = cthulhu[2] 54 | cthulhu[3][cthulhu[3]] = cthulhu 55 | print(smallfolk.dumps(cthulhu)) 56 | -- prints: 57 | -- {{{@2:@3}:{@4:@1}},@3,@4,"fhtagn":@1} 58 | ``` 59 | 60 | Secure 61 | ------ 62 | 63 | Smallfolk doesn't run arbitrary Lua code, so you can safely use it when you 64 | want to read data from an untrusted source. 65 | 66 | Compact 67 | ------- 68 | 69 | Smallfolk creates really small output files compared to something like Ser when 70 | it encounters a lot of non-tree-like data, by using numbered references rather 71 | than item assignment. 72 | 73 | Tested 74 | ------ 75 | 76 | Check out `tests.lua` to see how Smallfolk behaves with all kinds of inputs. 77 | 78 | Reference 79 | --------- 80 | 81 | ###`smallfolk.dumps(object)` 82 | 83 | Returns an 8-bit string representation of `object`. Throws an error if `object` 84 | contains any types that cannot be serialised (userdata, functions and threads). 85 | 86 | ###`smallfolk.loads(string[, maxsize=10000])` 87 | 88 | Returns an object whose representation would be `string`. If the length of 89 | `string` is larger than `maxsize`, no deserialization is attempted and instead 90 | an error is thrown. If `string` is not a valid representation of any object, 91 | an error is thrown. 92 | 93 | See also 94 | -------- 95 | 96 | * [Ser](https://github.com/gvx/Ser): for trusted-source serialization 97 | * [Lady](https://github.com/gvx/Lady): for trusted-source savegames 98 | -------------------------------------------------------------------------------- /AIO_Server/Dep_Smallfolk/smallfolk.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | Smallfolk = M 3 | local expect_object, dump_object 4 | local error, tostring, pairs, type, floor, huge, concat = error, tostring, pairs, type, math.floor, math.huge, table.concat 5 | 6 | local dump_type = {} 7 | 8 | function dump_type:string(nmemo, memo, acc) 9 | local nacc = #acc 10 | acc[nacc + 1] = '"' 11 | acc[nacc + 2] = self:gsub('"', '""') 12 | acc[nacc + 3] = '"' 13 | return nmemo 14 | end 15 | 16 | function dump_type:number(nmemo, memo, acc) 17 | acc[#acc + 1] = ("%.17g"):format(self) 18 | return nmemo 19 | end 20 | 21 | function dump_type:table(nmemo, memo, acc) 22 | --[[ 23 | if memo[self] then 24 | acc[#acc + 1] = '@' 25 | acc[#acc + 1] = tostring(memo[self]) 26 | return nmemo 27 | end 28 | nmemo = nmemo + 1 29 | ]] 30 | memo[self] = nmemo 31 | acc[#acc + 1] = '{' 32 | local nself = #self 33 | for i = 1, nself do -- don't use ipairs here, we need the gaps 34 | nmemo = dump_object(self[i], nmemo, memo, acc) 35 | acc[#acc + 1] = ',' 36 | end 37 | for k, v in pairs(self) do 38 | if type(k) ~= 'number' or floor(k) ~= k or k < 1 or k > nself then 39 | nmemo = dump_object(k, nmemo, memo, acc) 40 | acc[#acc + 1] = ':' 41 | nmemo = dump_object(v, nmemo, memo, acc) 42 | acc[#acc + 1] = ',' 43 | end 44 | end 45 | acc[#acc] = acc[#acc] == '{' and '{}' or '}' 46 | return nmemo 47 | end 48 | 49 | function dump_object(object, nmemo, memo, acc) 50 | if object == true then 51 | acc[#acc + 1] = 't' 52 | elseif object == false then 53 | acc[#acc + 1] = 'f' 54 | elseif object == nil then 55 | acc[#acc + 1] = 'n' 56 | elseif object ~= object then 57 | if (''..object):sub(1,1) == '-' then 58 | acc[#acc + 1] = 'N' 59 | else 60 | acc[#acc + 1] = 'Q' 61 | end 62 | elseif object == huge then 63 | acc[#acc + 1] = 'I' 64 | elseif object == -huge then 65 | acc[#acc + 1] = 'i' 66 | else 67 | local t = type(object) 68 | if not dump_type[t] then 69 | error('cannot dump type ' .. t) 70 | end 71 | return dump_type[t](object, nmemo, memo, acc) 72 | end 73 | return nmemo 74 | end 75 | 76 | function M.dumps(object) 77 | local nmemo = 0 78 | local memo = {} 79 | local acc = {} 80 | dump_object(object, nmemo, memo, acc) 81 | return concat(acc) 82 | end 83 | 84 | local function invalid(i) 85 | error('invalid input at position ' .. i) 86 | end 87 | 88 | local nonzero_digit = {['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true, ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true} 89 | local is_digit = {['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true, ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true} 90 | local function expect_number(string, start) 91 | local i = start 92 | local head = string:sub(i, i) 93 | if head == '-' then 94 | i = i + 1 95 | head = string:sub(i, i) 96 | end 97 | if nonzero_digit[head] then 98 | repeat 99 | i = i + 1 100 | head = string:sub(i, i) 101 | until not is_digit[head] 102 | elseif head == '0' then 103 | i = i + 1 104 | head = string:sub(i, i) 105 | else 106 | invalid(i) 107 | end 108 | if head == '.' then 109 | local oldi = i 110 | repeat 111 | i = i + 1 112 | head = string:sub(i, i) 113 | until not is_digit[head] 114 | if i == oldi + 1 then 115 | invalid(i) 116 | end 117 | end 118 | if head == 'e' or head == 'E' then 119 | i = i + 1 120 | head = string:sub(i, i) 121 | if head == '+' or head == '-' then 122 | i = i + 1 123 | head = string:sub(i, i) 124 | end 125 | if not is_digit[head] then 126 | invalid(i) 127 | end 128 | repeat 129 | i = i + 1 130 | head = string:sub(i, i) 131 | until not is_digit[head] 132 | end 133 | return tonumber(string:sub(start, i - 1)), i 134 | end 135 | 136 | local expect_object_head = { 137 | t = function(string, i) return true, i end, 138 | f = function(string, i) return false, i end, 139 | n = function(string, i) return nil, i end, 140 | Q = function(string, i) return -(0/0), i end, 141 | N = function(string, i) return 0/0, i end, 142 | I = function(string, i) return 1/0, i end, 143 | i = function(string, i) return -1/0, i end, 144 | ['"'] = function(string, i) 145 | local nexti = i - 1 146 | repeat 147 | nexti = string:find('"', nexti + 1, true) + 1 148 | until string:sub(nexti, nexti) ~= '"' 149 | return string:sub(i, nexti - 2):gsub('""', '"'), nexti 150 | end, 151 | ['0'] = function(string, i) 152 | return expect_number(string, i - 1) 153 | end, 154 | ['{'] = function(string, i, tables) 155 | local nt, k, v = {} 156 | local j = 1 157 | tables[#tables + 1] = nt 158 | if string:sub(i, i) == '}' then 159 | return nt, i + 1 160 | end 161 | while true do 162 | k, i = expect_object(string, i, tables) 163 | if string:sub(i, i) == ':' then 164 | v, i = expect_object(string, i + 1, tables) 165 | nt[k] = v 166 | else 167 | nt[j] = k 168 | j = j + 1 169 | end 170 | local head = string:sub(i, i) 171 | if head == ',' then 172 | i = i + 1 173 | elseif head == '}' then 174 | return nt, i + 1 175 | else 176 | invalid(i) 177 | end 178 | end 179 | end, 180 | --[[ 181 | ['@'] = function(string, i, tables) 182 | local match = string:match('^%d+', i) 183 | local ref = tonumber(match) 184 | if tables[ref] then 185 | return tables[ref], i + #match 186 | end 187 | invalid(i) 188 | end, 189 | ]] 190 | } 191 | expect_object_head['1'] = expect_object_head['0'] 192 | expect_object_head['2'] = expect_object_head['0'] 193 | expect_object_head['3'] = expect_object_head['0'] 194 | expect_object_head['4'] = expect_object_head['0'] 195 | expect_object_head['5'] = expect_object_head['0'] 196 | expect_object_head['6'] = expect_object_head['0'] 197 | expect_object_head['7'] = expect_object_head['0'] 198 | expect_object_head['8'] = expect_object_head['0'] 199 | expect_object_head['9'] = expect_object_head['0'] 200 | expect_object_head['-'] = expect_object_head['0'] 201 | expect_object_head['.'] = expect_object_head['0'] 202 | 203 | expect_object = function(string, i, tables) 204 | local head = string:sub(i, i) 205 | if expect_object_head[head] then 206 | return expect_object_head[head](string, i + 1, tables) 207 | end 208 | invalid(i) 209 | end 210 | 211 | function M.loads(string, maxsize) 212 | if #string > (maxsize or 10000) then 213 | error 'input too large' 214 | end 215 | return (expect_object(string, 1, {})) 216 | end 217 | 218 | return M 219 | -------------------------------------------------------------------------------- /AIO_Server/Dep_crc32lua/COPYRIGHT: -------------------------------------------------------------------------------- 1 | lua-digest-crc32lua License 2 | 3 | =============================================================================== 4 | 5 | Copyright (C) 2008, David Manura. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | 25 | =============================================================================== 26 | -------------------------------------------------------------------------------- /AIO_Server/Dep_crc32lua/crc32lua.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | 3 | LUA MODULE 4 | 5 | digest.crc32 - CRC-32 checksum implemented entirely in Lua. 6 | 7 | SYNOPSIS 8 | 9 | local CRC = require 'digest.crc32lua' 10 | print(CRC.crc32 'test') --> 0xD87F7E0C or -662733300 11 | 12 | assert(CRC.crc32('st', CRC.crc32('te')) == CRC.crc32 'test') 13 | 14 | DESCRIPTION 15 | 16 | This can be used to compute CRC-32 checksums on strings. 17 | This is similar to [1-2]. 18 | 19 | API 20 | 21 | Note: in the functions below, checksums are 32-bit integers stored in 22 | numbers. The number format currently depends on the bit 23 | implementation--see DESIGN NOTES below. 24 | 25 | CRC.crc32_byte(byte [, crc]) --> rcrc 26 | 27 | Returns CRC-32 checksum `rcrc` of byte `byte` (number 0..255) appended to 28 | a string with CRC-32 checksum `crc`. `crc` defaults to 0 (empty string) 29 | if omitted. 30 | 31 | CRC.crc32_string(s, crc) --> bcrc 32 | 33 | Returns CRC-32 checksum `rcrc` of string `s` appended to 34 | a string with CRC-32 checksum `crc`. `crc` defaults to 0 (empty string) 35 | if omitted. 36 | 37 | CRC.crc32(o, crc) --> bcrc 38 | 39 | This invokes `crc32_byte` if `o` is a byte or `crc32_string` if `o` 40 | is a string. 41 | 42 | CRC.bit 43 | 44 | This contains the underlying bit library used by the module. It 45 | should be considered a read-only copy. 46 | 47 | DESIGN NOTES 48 | 49 | Currently, this module exposes the underlying bit array implementation in CRC 50 | checksums returned. In BitOp, bit arrays are 32-bit signed integer numbers 51 | (may be negative). In Lua 5.2 'bit32' and 'bit.numberlua', bit arrays are 52 | 32-bit unsigned integer numbers (non-negative). This is subject to change 53 | in the future but is currently done due to (unconfirmed) performance 54 | implications. 55 | 56 | On platforms with 64-bit numbers, one way to normalize CRC 57 | checksums to be unsigned is to do `crcvalue % 2^32`, 58 | 59 | The name of this module is inspired by Perl `Digest::CRC*`. 60 | 61 | DEPENDENCIES 62 | 63 | Requires one of the following bit libraries: 64 | 65 | BitOp "bit" -- bitop.luajit.org -- This is included in LuaJIT and also available 66 | for Lua 5.1/5.2. This provides the fastest performance in LuaJIT. 67 | Lua 5.2 "bit32" -- www.lua.org/manual/5.2 -- This is provided in Lua 5.2 68 | and is preferred in 5.2 (unless "bit" also happens to be installed). 69 | "bit.numberlua" (>=000.003) -- https://github.com/davidm/lua-bit-numberlua 70 | This is slowest and used as a last resort. 71 | It is only a few times slower than "bit32" though. 72 | 73 | DOWNLOAD/INSTALLATION 74 | 75 | If using LuaRocks: 76 | luarocks install lua-digest-crc32lua 77 | 78 | Otherwise, download . 79 | Alternately, if using git: 80 | git clone git://github.com/davidm/lua-digest-crc32lua.git 81 | cd lua-digest-crc32lua 82 | Optionally unpack: 83 | ./util.mk 84 | or unpack and install in LuaRocks: 85 | ./util.mk install 86 | 87 | REFERENCES 88 | 89 | [1] http://www.axlradius.com/freestuff/CRC32.java 90 | [2] http://www.gamedev.net/reference/articles/article1941.asp 91 | [3] http://java.sun.com/j2se/1.5.0/docs/api/java/util/zip/CRC32.html 92 | [4] http://www.dsource.org/projects/tango/docs/current/tango.io.digest.Crc32.html 93 | [5] http://pydoc.org/1.5.2/zlib.html#-crc32 94 | [6] http://www.python.org/doc/2.5.2/lib/module-binascii.html 95 | 96 | LICENSE 97 | 98 | (c) 2008-2011 David Manura. Licensed under the same terms as Lua (MIT). 99 | 100 | Permission is hereby granted, free of charge, to any person obtaining a copy 101 | of this software and associated documentation files (the "Software"), to deal 102 | in the Software without restriction, including without limitation the rights 103 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 104 | copies of the Software, and to permit persons to whom the Software is 105 | furnished to do so, subject to the following conditions: 106 | 107 | The above copyright notice and this permission notice shall be included in 108 | all copies or substantial portions of the Software. 109 | 110 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 111 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 112 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 113 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 114 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 115 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 116 | THE SOFTWARE. 117 | (end license) 118 | 119 | --]] 120 | 121 | 122 | local M = {_TYPE='module', _NAME='digest.crc32', _VERSION='0.3.20111128'} 123 | 124 | local type = type 125 | local require = require 126 | local setmetatable = setmetatable 127 | 128 | --[[ 129 | Requires the first module listed that exists, else raises like `require`. 130 | If a non-string is encountered, it is returned. 131 | Second return value is module name loaded (or ''). 132 | --]] 133 | local function requireany(...) 134 | local errs = {} 135 | for _,name in ipairs{...} do 136 | if type(name) ~= 'string' then return name, '' end 137 | local ok, mod = pcall(require, name) 138 | if ok then return mod, name end 139 | errs[#errs+1] = mod 140 | end 141 | error(table.concat(errs, '\n'), 2) 142 | end 143 | 144 | local bit, name_ = requireany('bit', 'bit32', 'bit.numberlua', 'bit53') 145 | local bxor = bit.bxor 146 | local bnot = bit.bnot 147 | local band = bit.band 148 | local rshift = bit.rshift 149 | 150 | -- CRC-32-IEEE 802.3 (V.42) 151 | local POLY = 0xEDB88320 152 | 153 | -- Memoize function pattern (like http://lua-users.org/wiki/FuncTables ). 154 | local function memoize(f) 155 | local mt = {} 156 | local t = setmetatable({}, mt) 157 | function mt:__index(k) 158 | local v = f(k); t[k] = v 159 | return v 160 | end 161 | return t 162 | end 163 | 164 | -- CRC table. 165 | local crc_table = memoize(function(i) 166 | local crc = i 167 | for _=1,8 do 168 | local b = band(crc, 1) 169 | crc = rshift(crc, 1) 170 | if b == 1 then crc = bxor(crc, POLY) end 171 | end 172 | return crc 173 | end) 174 | 175 | 176 | function M.crc32_byte(byte, crc) 177 | crc = bnot(crc or 0) 178 | local v1 = rshift(crc, 8) 179 | local v2 = crc_table[bxor(crc % 256, byte)] 180 | return bnot(bxor(v1, v2)) 181 | end 182 | local M_crc32_byte = M.crc32_byte 183 | 184 | 185 | function M.crc32_string(s, crc) 186 | crc = crc or 0 187 | for i=1,#s do 188 | crc = M_crc32_byte(s:byte(i), crc) 189 | end 190 | return crc 191 | end 192 | local M_crc32_string = M.crc32_string 193 | 194 | 195 | function M.crc32(s, crc) 196 | if type(s) == 'string' then 197 | return M_crc32_string(s, crc) 198 | else 199 | return M_crc32_byte(s, crc) 200 | end 201 | end 202 | 203 | 204 | M.bit = bit -- bit library used 205 | 206 | 207 | return M 208 | -------------------------------------------------------------------------------- /AIO_Server/lualzw-zeros/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Lua sources 2 | luac.out 3 | 4 | # luarocks build files 5 | *.src.rock 6 | *.zip 7 | *.tar.gz 8 | 9 | # Object files 10 | *.o 11 | *.os 12 | *.ko 13 | *.obj 14 | *.elf 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Libraries 21 | *.lib 22 | *.a 23 | *.la 24 | *.lo 25 | *.def 26 | *.exp 27 | 28 | # Shared objects (inc. Windows DLLs) 29 | *.dll 30 | *.so 31 | *.so.* 32 | *.dylib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | *.i*86 39 | *.x86_64 40 | *.hex 41 | 42 | -------------------------------------------------------------------------------- /AIO_Server/lualzw-zeros/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /AIO_Server/lualzw-zeros/README.md: -------------------------------------------------------------------------------- 1 | # lualzw 2 | A relatively fast LZW compression algorithm in pure lua 3 | 4 | # encoding and decoding 5 | Lossless compression for any text. The more repetition in the text, the better. 6 | 7 | 16 bit encoding is used. So each 8 bit character is encoded as 16 bit. 8 | This means that the dictionary size is 65280. 9 | 10 | Any special characters like `äöå` that are represented with multiple characters are supported. The special characters are split up into single characters that are then encoded and decoded. 11 | 12 | While compressing, the algorithm checks if the result size gets over the input. If it does, then the input is not compressed and the algorithm returns the input prematurely as the compressed result. 13 | 14 | The `zeros` branch contains a version that does not add additional null `\0` characters to the input when encoding. Any existing null characters in input string are preserved as nulls however so make sure your input does not contain nulls. 15 | 16 | # usage 17 | ```lua 18 | local lualzw = require("lualzw") 19 | 20 | local input = "foofoofoofoofoofoofoofoofoo" 21 | local compressed = assert(lualzw.compress(input)) 22 | local decompressed = assert(lualzw.decompress(compressed)) 23 | assert(input == decompressed) 24 | ``` 25 | 26 | # errors 27 | Returns nil and an error message when the algorithm fails to compress or decompress. 28 | 29 | # speed 30 | Times are in seconds. 31 | Both have the same generated input. 32 | The values are an average of 10 tries. 33 | 34 | Note that compressing random generated inputs results usually in bigger result than original. In these cases the algorithms do not compress and return input instead and thus compression result is 100% of input. 35 | 36 | lualzw is at an advantage in cases where compression cannot be done as it stops prematurely and LibCompress does not. 37 | Also lualzw is at an advantage in cases where compression can be done as it has a larger dictionary in use. 38 | 39 | Input: 1000000 random generated bytes converted into string 40 | 41 | algorithm|compress|decompress|result % of input 42 | ---------|--------|----------|------------- 43 | lualzw|0.6622|0.0003|100 44 | LibCompress|2.1983|0.0024|100 45 | 46 | Input: 1000000 random generated bytes in ASCII range converted into string 47 | 48 | algorithm|compress|decompress|result % of input 49 | ---------|--------|----------|------------- 50 | lualzw|0.812|0.0022|100 51 | LibCompress|1.782|0.0007|100 52 | 53 | Input: 1000000 random generated repeating bytes converted into string 54 | 55 | algorithm|compress|decompress|result % of input 56 | ---------|--------|----------|------------- 57 | lualzw|0.3975|0.0262|4.5001 58 | LibCompress|0.3907|0.0264|6.6997 59 | 60 | Input: 1000000 of same character 61 | 62 | algorithm|compress|decompress|result % of input 63 | ---------|--------|----------|------------- 64 | lualzw|0.7045|0.0026|0.2829 65 | LibCompress|0.6418|0.0038|0.4241 66 | 67 | Input: "ymn32h8hm8ekrwjkrn9f" repeated 50000 times. In total 1000000 bytes 68 | 69 | algorithm|compress|decompress|result % of input 70 | ---------|--------|----------|------------- 71 | lualzw|0.4788|0.0088|1.2629 72 | LibCompress|0.4426|0.0093|1.8905 73 | -------------------------------------------------------------------------------- /AIO_Server/lualzw-zeros/lualzw.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | MIT License 3 | 4 | Copyright (c) 2016 Rochet2 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | ]] 24 | 25 | local char = string.char 26 | local type = type 27 | local select = select 28 | local sub = string.sub 29 | local tconcat = table.concat 30 | 31 | local basedictcompress = {} 32 | local basedictdecompress = {} 33 | for i = 0, 255 do 34 | local ic, iic = char(i), char(i, 1) 35 | basedictcompress[ic] = iic 36 | basedictdecompress[iic] = ic 37 | end 38 | 39 | local function dictAddA(str, dict, a, b) 40 | if a >= 256 then 41 | a, b = 1, b+1 42 | if b >= 256 then 43 | dict = {} 44 | b = 2 45 | end 46 | end 47 | dict[str] = char(a,b) 48 | a = a+1 49 | return dict, a, b 50 | end 51 | 52 | local function compress(input) 53 | if type(input) ~= "string" then 54 | return nil, "string expected, got "..type(input) 55 | end 56 | local len = #input 57 | if len <= 1 then 58 | return "u"..input 59 | end 60 | 61 | local dict = {} 62 | local a, b = 1, 2 63 | 64 | local result = {"c"} 65 | local resultlen = 1 66 | local n = 2 67 | local word = "" 68 | for i = 1, len do 69 | local c = sub(input, i, i) 70 | local wc = word..c 71 | if not (basedictcompress[wc] or dict[wc]) then 72 | local write = basedictcompress[word] or dict[word] 73 | if not write then 74 | return nil, "algorithm error, could not fetch word" 75 | end 76 | result[n] = write 77 | resultlen = resultlen + #write 78 | n = n+1 79 | if len <= resultlen then 80 | return "u"..input 81 | end 82 | dict, a, b = dictAddA(wc, dict, a, b) 83 | word = c 84 | else 85 | word = wc 86 | end 87 | end 88 | result[n] = basedictcompress[word] or dict[word] 89 | resultlen = resultlen+#result[n] 90 | n = n+1 91 | if len <= resultlen then 92 | return "u"..input 93 | end 94 | return tconcat(result) 95 | end 96 | 97 | local function dictAddB(str, dict, a, b) 98 | if a >= 256 then 99 | a, b = 1, b+1 100 | if b >= 256 then 101 | dict = {} 102 | b = 2 103 | end 104 | end 105 | dict[char(a,b)] = str 106 | a = a+1 107 | return dict, a, b 108 | end 109 | 110 | local function decompress(input) 111 | if type(input) ~= "string" then 112 | return nil, "string expected, got "..type(input) 113 | end 114 | 115 | if #input < 1 then 116 | return nil, "invalid input - not a compressed string" 117 | end 118 | 119 | local control = sub(input, 1, 1) 120 | if control == "u" then 121 | return sub(input, 2) 122 | elseif control ~= "c" then 123 | return nil, "invalid input - not a compressed string" 124 | end 125 | input = sub(input, 2) 126 | local len = #input 127 | 128 | if len < 2 then 129 | return nil, "invalid input - not a compressed string" 130 | end 131 | 132 | local dict = {} 133 | local a, b = 1, 2 134 | 135 | local result = {} 136 | local n = 1 137 | local last = sub(input, 1, 2) 138 | result[n] = basedictdecompress[last] or dict[last] 139 | n = n+1 140 | for i = 3, len, 2 do 141 | local code = sub(input, i, i+1) 142 | local lastStr = basedictdecompress[last] or dict[last] 143 | if not lastStr then 144 | return nil, "could not find last from dict. Invalid input?" 145 | end 146 | local toAdd = basedictdecompress[code] or dict[code] 147 | if toAdd then 148 | result[n] = toAdd 149 | n = n+1 150 | dict, a, b = dictAddB(lastStr..sub(toAdd, 1, 1), dict, a, b) 151 | else 152 | local tmp = lastStr..sub(lastStr, 1, 1) 153 | result[n] = tmp 154 | n = n+1 155 | dict, a, b = dictAddB(tmp, dict, a, b) 156 | end 157 | last = code 158 | end 159 | return tconcat(result) 160 | end 161 | 162 | lualzw = { 163 | compress = compress, 164 | decompress = decompress, 165 | } 166 | return lualzw 167 | -------------------------------------------------------------------------------- /AIO_Server/queue.lua: -------------------------------------------------------------------------------- 1 | local Queue = {} 2 | function Queue.__index(que, key) 3 | return Queue[key] 4 | end 5 | 6 | function NewQueue() 7 | local t = {first = 0, last = -1} 8 | setmetatable(t, Queue) 9 | return t 10 | end 11 | 12 | function Queue.pushleft(que, value) 13 | local first = que.first - 1 14 | que.first = first 15 | que[first] = value 16 | return first 17 | end 18 | 19 | function Queue.pushright(que, value) 20 | local last = que.last + 1 21 | que.last = last 22 | que[last] = value 23 | return last 24 | end 25 | 26 | function Queue.popleft(que) 27 | local first = que.first 28 | if first > que.last then error("que is empty") end 29 | local value = que[first] 30 | que[first] = nil -- to allow garbage collection 31 | que.first = first + 1 32 | return value 33 | end 34 | 35 | function Queue.popright(que) 36 | local last = que.last 37 | if que.first > last then error("que is empty") end 38 | local value = que[last] 39 | que[last] = nil -- to allow garbage collection 40 | que.last = last - 1 41 | return value 42 | end 43 | 44 | function Queue.peekleft(que) 45 | return que[que.first] 46 | end 47 | 48 | function Queue.peekright(que) 49 | return que[que.last] 50 | end 51 | 52 | function Queue.empty(que) 53 | return que.last < que.first 54 | end 55 | 56 | function Queue.size(que) 57 | return que.last - que.first + 1 58 | end 59 | 60 | function Queue.clear(que) 61 | local l, r = self:getrange() 62 | for i = l, r do 63 | que[idx] = nil 64 | end 65 | que.first, que.last = 0, -1 66 | end 67 | 68 | function Queue.get(que, idx) 69 | if idx < que.first or idx > que.last then 70 | return 71 | end 72 | return que[idx] 73 | end 74 | 75 | function Queue.getrange(que) 76 | return que.first, que.last 77 | end 78 | 79 | function Queue.gettable(que) 80 | return que 81 | end 82 | 83 | return NewQueue 84 | -------------------------------------------------------------------------------- /Examples/HelloWorld.lua: -------------------------------------------------------------------------------- 1 | local AIO = AIO or require("AIO") 2 | 3 | if AIO.AddAddon() then 4 | -- we are on server 5 | print("Hello Server") 6 | else 7 | -- we are on client 8 | print("Hello Client") 9 | end 10 | -------------------------------------------------------------------------------- /Examples/KaevStatTest/Client.lua: -------------------------------------------------------------------------------- 1 | local AIO = AIO or require("AIO") 2 | if AIO.AddAddon() then 3 | return 4 | end 5 | 6 | local MyHandlers = AIO.AddHandlers("Kaev", {}) 7 | 8 | -- Attribute window 9 | local frameAttributes = CreateFrame("Frame", "frameAttributes", UIParent) 10 | frameAttributes:SetSize(200, 300) 11 | frameAttributes:SetMovable(true) 12 | frameAttributes:EnableMouse(true) 13 | frameAttributes:RegisterForDrag("LeftButton") 14 | frameAttributes:SetPoint("CENTER") 15 | frameAttributes:SetBackdrop( 16 | { 17 | bgFile = "Interface/AchievementFrame/UI-Achievement-Parchment-Horizontal", 18 | edgeFile = "Interface/DialogFrame/UI-DialogBox-Border", 19 | edgeSize = 20, 20 | insets = { left = 5, right = 5, top = 5, bottom = 5 } 21 | }) 22 | -- Drag & Drop 23 | frameAttributes:SetScript("OnDragStart", frameAttributes.StartMoving) 24 | frameAttributes:SetScript("OnHide", frameAttributes.StopMovingOrSizing) 25 | frameAttributes:SetScript("OnDragStop", frameAttributes.StopMovingOrSizing) 26 | frameAttributes:Hide() 27 | 28 | -- Close button 29 | local buttonAttributesClose = CreateFrame("Button", "buttonAttributesClose", frameAttributes, "UIPanelCloseButton") 30 | buttonAttributesClose:SetPoint("TOPRIGHT", -5, -5) 31 | buttonAttributesClose:EnableMouse(true) 32 | buttonAttributesClose:SetSize(27, 27) 33 | 34 | -- Title bar 35 | local frameAttributesTitleBar = CreateFrame("Frame", "frameAttributesTitleBar", frameAttributes, nil) 36 | frameAttributesTitleBar:SetSize(135, 25) 37 | frameAttributesTitleBar:SetBackdrop( 38 | { 39 | bgFile = "Interface/CHARACTERFRAME/UI-Party-Background", 40 | edgeFile = "Interface/DialogFrame/UI-DialogBox-Border", 41 | tile = true, 42 | edgeSize = 16, 43 | tileSize = 16, 44 | insets = { left = 5, right = 5, top = 5, bottom = 5 } 45 | }) 46 | frameAttributesTitleBar:SetPoint("TOP", 0, 9) 47 | 48 | local fontAttributesTitleText = frameAttributesTitleBar:CreateFontString("fontAttributesTitleText") 49 | fontAttributesTitleText:SetFont("Fonts\\FRIZQT__.TTF", 13) 50 | fontAttributesTitleText:SetSize(190, 5) 51 | fontAttributesTitleText:SetPoint("CENTER", 0, 0) 52 | fontAttributesTitleText:SetText("|cffFFC125Attribute Points|r") 53 | 54 | -- Attribute points left 55 | local fontAttributesPointsLeft = frameAttributes:CreateFontString("fontAttributesPointsLeft") 56 | fontAttributesPointsLeft:SetFont("Fonts\\FRIZQT__.TTF", 15) 57 | fontAttributesPointsLeft:SetSize(50, 5) 58 | fontAttributesPointsLeft:SetPoint("TOPLEFT", 107, -25) 59 | 60 | -- Strength 61 | local fontAttributesStrength = frameAttributes:CreateFontString("fontAttributesStrength") 62 | fontAttributesStrength:SetFont("Fonts\\FRIZQT__.TTF", 15) 63 | fontAttributesStrength:SetSize(137, 5) 64 | fontAttributesStrength:SetPoint("TOPLEFT", -20, -45) 65 | fontAttributesStrength:SetText("|cFF000000Strength|r") 66 | 67 | local fontAttributesStrengthValue = frameAttributes:CreateFontString("fontAttributesStrengthValue") 68 | fontAttributesStrengthValue:SetFont("Fonts\\FRIZQT__.TTF", 15) 69 | fontAttributesStrengthValue:SetSize(50, 5) 70 | fontAttributesStrengthValue:SetPoint("TOPLEFT", 107, -45) 71 | 72 | local buttonAttributesIncreaseStrength = CreateFrame("Button", "buttonAttributesIncreaseStrength", frameAttributes, nil) 73 | buttonAttributesIncreaseStrength:SetSize(20, 20) 74 | buttonAttributesIncreaseStrength:SetPoint("TOPLEFT", 144, -39) 75 | buttonAttributesIncreaseStrength:EnableMouse(true) 76 | buttonAttributesIncreaseStrength:SetNormalTexture("Interface/BUTTONS/UI-SpellbookIcon-NextPage-Up") 77 | buttonAttributesIncreaseStrength:SetHighlightTexture("Interface/BUTTONS/UI-Panel-MinimizeButton-Highlight") 78 | buttonAttributesIncreaseStrength:SetPushedTexture("Interface/BUTTONS/UI-SpellbookIcon-NextPage-Down") 79 | buttonAttributesIncreaseStrength:SetScript("OnMouseUp", function() AIO.Handle("Kaev", "AttributesIncrease", 1) end) 80 | 81 | local buttonAttributesDecreaseStrength = CreateFrame("Button", "buttonAttributesDecreaseStrength", frameAttributes, nil) 82 | buttonAttributesDecreaseStrength:SetSize(20, 20) 83 | buttonAttributesDecreaseStrength:SetPoint("TOPLEFT", 104, -39) 84 | buttonAttributesDecreaseStrength:EnableMouse(true) 85 | buttonAttributesDecreaseStrength:SetNormalTexture("Interface/BUTTONS/UI-SpellbookIcon-PrevPage-Up") 86 | buttonAttributesDecreaseStrength:SetHighlightTexture("Interface/BUTTONS/UI-Panel-MinimizeButton-Highlight") 87 | buttonAttributesDecreaseStrength:SetPushedTexture("Interface/BUTTONS/UI-SpellbookIcon-PrevPage-Down") 88 | buttonAttributesDecreaseStrength:SetScript("OnMouseUp", function() AIO.Handle("Kaev", "AttributesDecrease", 1) end) 89 | 90 | -- Agility 91 | local fontAttributesAgility = frameAttributes:CreateFontString("fontAttributesAgility") 92 | fontAttributesAgility:SetFont("Fonts\\FRIZQT__.TTF", 15) 93 | fontAttributesAgility:SetSize(137, 5) 94 | fontAttributesAgility:SetPoint("TOPLEFT", -20, -65) 95 | fontAttributesAgility:SetText("|cFF000000Agility|r") 96 | 97 | local fontAttributesAgilityValue = frameAttributes:CreateFontString("fontAttributesAgilityValue") 98 | fontAttributesAgilityValue:SetFont("Fonts\\FRIZQT__.TTF", 15) 99 | fontAttributesAgilityValue:SetSize(50, 5) 100 | fontAttributesAgilityValue:SetPoint("TOPLEFT", 107, -65) 101 | 102 | local buttonAttributesIncreaseAgility = CreateFrame("Button", "buttonAttributesIncreaseAgility", frameAttributes, nil) 103 | buttonAttributesIncreaseAgility:SetSize(20, 20) 104 | buttonAttributesIncreaseAgility:SetPoint("TOPLEFT", 144, -59) 105 | buttonAttributesIncreaseAgility:EnableMouse(true) 106 | buttonAttributesIncreaseAgility:SetNormalTexture("Interface/BUTTONS/UI-SpellbookIcon-NextPage-Up") 107 | buttonAttributesIncreaseAgility:SetHighlightTexture("Interface/BUTTONS/UI-Panel-MinimizeButton-Highlight") 108 | buttonAttributesIncreaseAgility:SetPushedTexture("Interface/BUTTONS/UI-SpellbookIcon-NextPage-Down") 109 | buttonAttributesIncreaseAgility:SetScript("OnMouseUp", function() AIO.Handle("Kaev", "AttributesIncrease", 2) end) 110 | 111 | local buttonAttributesDecreaseAgility = CreateFrame("Button", "buttonAttributesDecreaseAgility", frameAttributes, nil) 112 | buttonAttributesDecreaseAgility:SetSize(20, 20) 113 | buttonAttributesDecreaseAgility:SetPoint("TOPLEFT", 104, -59) 114 | buttonAttributesDecreaseAgility:EnableMouse(true) 115 | buttonAttributesDecreaseAgility:SetNormalTexture("Interface/BUTTONS/UI-SpellbookIcon-PrevPage-Up") 116 | buttonAttributesDecreaseAgility:SetHighlightTexture("Interface/BUTTONS/UI-Panel-MinimizeButton-Highlight") 117 | buttonAttributesDecreaseAgility:SetPushedTexture("Interface/BUTTONS/UI-SpellbookIcon-PrevPage-Down") 118 | buttonAttributesDecreaseAgility:SetScript("OnMouseUp", function() AIO.Handle("Kaev", "AttributesDecrease", 2) end) 119 | 120 | -- Stamina 121 | local fontAttributesStamina = frameAttributes:CreateFontString("fontAttributesStamina") 122 | fontAttributesStamina:SetFont("Fonts\\FRIZQT__.TTF", 15) 123 | fontAttributesStamina:SetSize(137, 5) 124 | fontAttributesStamina:SetPoint("TOPLEFT", -20, -85) 125 | fontAttributesStamina:SetText("|cFF000000Stamina|r") 126 | 127 | local fontAttributesStaminaValue = frameAttributes:CreateFontString("fontAttributesStaminaValue") 128 | fontAttributesStaminaValue:SetFont("Fonts\\FRIZQT__.TTF", 15) 129 | fontAttributesStaminaValue:SetSize(50, 5) 130 | fontAttributesStaminaValue:SetPoint("TOPLEFT", 107, -85) 131 | 132 | local buttonAttributesIncreaseStamina = CreateFrame("Button", "buttonAttributesIncreaseStamina", frameAttributes, nil) 133 | buttonAttributesIncreaseStamina:SetSize(20, 20) 134 | buttonAttributesIncreaseStamina:SetPoint("TOPLEFT", 144, -79) 135 | buttonAttributesIncreaseStamina:EnableMouse(true) 136 | buttonAttributesIncreaseStamina:SetNormalTexture("Interface/BUTTONS/UI-SpellbookIcon-NextPage-Up") 137 | buttonAttributesIncreaseStamina:SetHighlightTexture("Interface/BUTTONS/UI-Panel-MinimizeButton-Highlight") 138 | buttonAttributesIncreaseStamina:SetPushedTexture("Interface/BUTTONS/UI-SpellbookIcon-NextPage-Down") 139 | buttonAttributesIncreaseStamina:SetScript("OnMouseUp", function() AIO.Handle("Kaev", "AttributesIncrease", 3) end) 140 | 141 | local buttonAttributesDecreaseStamina = CreateFrame("Button", "buttonAttributesDecreaseStamina", frameAttributes, nil) 142 | buttonAttributesDecreaseStamina:SetSize(20, 20) 143 | buttonAttributesDecreaseStamina:SetPoint("TOPLEFT", 104, -79) 144 | buttonAttributesDecreaseStamina:EnableMouse(true) 145 | buttonAttributesDecreaseStamina:SetNormalTexture("Interface/BUTTONS/UI-SpellbookIcon-PrevPage-Up") 146 | buttonAttributesDecreaseStamina:SetHighlightTexture("Interface/BUTTONS/UI-Panel-MinimizeButton-Highlight") 147 | buttonAttributesDecreaseStamina:SetPushedTexture("Interface/BUTTONS/UI-SpellbookIcon-PrevPage-Down") 148 | buttonAttributesDecreaseStamina:SetScript("OnMouseUp", function() AIO.Handle("Kaev", "AttributesDecrease", 3) end) 149 | 150 | -- Intellect 151 | local fontAttributesIntellect = frameAttributes:CreateFontString("fontAttributesIntellect") 152 | fontAttributesIntellect:SetFont("Fonts\\FRIZQT__.TTF", 15) 153 | fontAttributesIntellect:SetSize(137, 5) 154 | fontAttributesIntellect:SetPoint("TOPLEFT", -20, -105) 155 | fontAttributesIntellect:SetText("|cFF000000Intellect|r") 156 | 157 | local fontAttributesIntellectValue = frameAttributes:CreateFontString("fontAttributesIntellectValue") 158 | fontAttributesIntellectValue:SetFont("Fonts\\FRIZQT__.TTF", 15) 159 | fontAttributesIntellectValue:SetSize(50, 5) 160 | fontAttributesIntellectValue:SetPoint("TOPLEFT", 107, -105) 161 | 162 | local buttonAttributesIncreaseIntellect = CreateFrame("Button", "buttonAttributesIncreaseIntellect", frameAttributes, nil) 163 | buttonAttributesIncreaseIntellect:SetSize(20, 20) 164 | buttonAttributesIncreaseIntellect:SetPoint("TOPLEFT", 144, -99) 165 | buttonAttributesIncreaseIntellect:EnableMouse(true) 166 | buttonAttributesIncreaseIntellect:SetNormalTexture("Interface/BUTTONS/UI-SpellbookIcon-NextPage-Up") 167 | buttonAttributesIncreaseIntellect:SetHighlightTexture("Interface/BUTTONS/UI-Panel-MinimizeButton-Highlight") 168 | buttonAttributesIncreaseIntellect:SetPushedTexture("Interface/BUTTONS/UI-SpellbookIcon-NextPage-Down") 169 | buttonAttributesIncreaseIntellect:SetScript("OnMouseUp", function() AIO.Handle("Kaev", "AttributesIncrease", 4) end) 170 | 171 | local buttonAttributesDecreaseIntellect = CreateFrame("Button", "buttonAttributesDecreaseIntellect", frameAttributes, nil) 172 | buttonAttributesDecreaseIntellect:SetSize(20, 20) 173 | buttonAttributesDecreaseIntellect:SetPoint("TOPLEFT", 104, -99) 174 | buttonAttributesDecreaseIntellect:EnableMouse(true) 175 | buttonAttributesDecreaseIntellect:SetNormalTexture("Interface/BUTTONS/UI-SpellbookIcon-PrevPage-Up") 176 | buttonAttributesDecreaseIntellect:SetHighlightTexture("Interface/BUTTONS/UI-Panel-MinimizeButton-Highlight") 177 | buttonAttributesDecreaseIntellect:SetPushedTexture("Interface/BUTTONS/UI-SpellbookIcon-PrevPage-Down") 178 | buttonAttributesDecreaseIntellect:SetScript("OnMouseUp", function() AIO.Handle("Kaev", "AttributesDecrease", 4) end) 179 | 180 | -- Spirit 181 | local fontAttributesSpirit = frameAttributes:CreateFontString("fontAttributesSpirit") 182 | fontAttributesSpirit:SetFont("Fonts\\FRIZQT__.TTF", 15) 183 | fontAttributesSpirit:SetSize(137, 5) 184 | fontAttributesSpirit:SetPoint("TOPLEFT", -20, -125) 185 | fontAttributesSpirit:SetText("|cFF000000Spirit|r") 186 | 187 | local fontAttributesSpiritValue = frameAttributes:CreateFontString("fontAttributesSpiritValue") 188 | fontAttributesSpiritValue:SetFont("Fonts\\FRIZQT__.TTF", 15) 189 | fontAttributesSpiritValue:SetSize(50, 5) 190 | fontAttributesSpiritValue:SetPoint("TOPLEFT", 107, -125) 191 | 192 | local buttonAttributesIncreaseSpirit = CreateFrame("Button", "buttonAttributesIncreaseSpirit", frameAttributes, nil) 193 | buttonAttributesIncreaseSpirit:SetSize(20, 20) 194 | buttonAttributesIncreaseSpirit:SetPoint("TOPLEFT", 144, -119) 195 | buttonAttributesIncreaseSpirit:EnableMouse(true) 196 | buttonAttributesIncreaseSpirit:SetNormalTexture("Interface/BUTTONS/UI-SpellbookIcon-NextPage-Up") 197 | buttonAttributesIncreaseSpirit:SetHighlightTexture("Interface/BUTTONS/UI-Panel-MinimizeButton-Highlight") 198 | buttonAttributesIncreaseSpirit:SetPushedTexture("Interface/BUTTONS/UI-SpellbookIcon-NextPage-Down") 199 | buttonAttributesIncreaseSpirit:SetScript("OnMouseUp", function() AIO.Handle("Kaev", "AttributesIncrease", 5) end) 200 | 201 | buttonAttributesDecreaseSpirit = CreateFrame("Button", "buttonAttributesDecreaseSpirit", frameAttributes, nil) 202 | buttonAttributesDecreaseSpirit:SetSize(20, 20) 203 | buttonAttributesDecreaseSpirit:SetPoint("TOPLEFT", 104, -119) 204 | buttonAttributesDecreaseSpirit:EnableMouse(true) 205 | buttonAttributesDecreaseSpirit:SetNormalTexture("Interface/BUTTONS/UI-SpellbookIcon-PrevPage-Up") 206 | buttonAttributesDecreaseSpirit:SetHighlightTexture("Interface/BUTTONS/UI-Panel-MinimizeButton-Highlight") 207 | buttonAttributesDecreaseSpirit:SetPushedTexture("Interface/BUTTONS/UI-SpellbookIcon-PrevPage-Down") 208 | buttonAttributesDecreaseSpirit:SetScript("OnMouseUp", function() AIO.Handle("Kaev", "AttributesDecrease", 5) end) 209 | 210 | function MyHandlers.ShowAttributes(player) 211 | frameAttributes:Show() 212 | end 213 | 214 | function MyHandlers.SetStats(player, left, p1, p2, p3, p4, p5) 215 | fontAttributesStrengthValue:SetText("|cFF000000"..p1.."|r") 216 | fontAttributesAgilityValue:SetText("|cFF000000"..p2.."|r") 217 | fontAttributesStaminaValue:SetText("|cFF000000"..p3.."|r") 218 | fontAttributesIntellectValue:SetText("|cFF000000"..p4.."|r") 219 | fontAttributesSpiritValue:SetText("|cFF000000"..p5.."|r") 220 | fontAttributesPointsLeft:SetText("|cFF000000"..left.."|r") 221 | end 222 | -------------------------------------------------------------------------------- /Examples/KaevStatTest/Server.lua: -------------------------------------------------------------------------------- 1 | local AIO = AIO or require("AIO") 2 | 3 | local MyHandlers = AIO.AddHandlers("Kaev", {}) 4 | local AttributesPointsLeft = {} 5 | local AttributesPointsSpend = {} 6 | local AttributesAuraIds = { 7464, 7471, 7477, 7468, 7474 } -- Strength, Agility, Stamina, Intellect, Spirit 7 | 8 | local function AddPlayerStats(msg, player) 9 | local guid = player:GetGUIDLow() 10 | local spend, left = AttributesPointsSpend[guid], AttributesPointsLeft[guid] 11 | return msg:Add("Kaev", "SetStats", left, AIO.unpack(spend)) 12 | end 13 | AIO.AddOnInit(AddPlayerStats) 14 | 15 | local function UpdatePlayerStats(player) 16 | AddPlayerStats(AIO.Msg(), player):Send(player) 17 | end 18 | 19 | local function AttributesInitPoints(guid) 20 | AttributesPointsLeft[guid] = 5 21 | AttributesPointsSpend[guid] = { 0, 0, 0, 0, 0 } 22 | end 23 | local function AttributesDeinitPoints(guid) 24 | AttributesPointsLeft[guid] = nil 25 | AttributesPointsSpend[guid] = nil 26 | end 27 | 28 | local function OnLogin(event, player) 29 | AttributesInitPoints(player:GetGUIDLow()) 30 | end 31 | local function OnLogout(event, player) 32 | AttributesDeinitPoints(player:GetGUIDLow()) 33 | end 34 | 35 | RegisterPlayerEvent(3, OnLogin) 36 | RegisterPlayerEvent(4, OnLogout) 37 | for k,v in ipairs(GetPlayersInWorld()) do 38 | OnLogin(3, v) 39 | end 40 | 41 | function MyHandlers.AttributesIncrease(player, statId) 42 | if (player:IsInCombat()) then 43 | player:SendBroadcastMessage("Du kannst während einem Kampfes keine Attributspunkte verteilen.") 44 | else 45 | local guid = player:GetGUIDLow() 46 | local spend, left = AttributesPointsSpend[guid], AttributesPointsLeft[guid] 47 | if not spend or not left then 48 | return 49 | end 50 | if not statId or not spend[statId] then 51 | return 52 | end 53 | if (left <= 0) then 54 | player:SendBroadcastMessage("Du hast nicht genuegend Attributspunkte.") 55 | else 56 | AttributesPointsLeft[guid] = left - 1 57 | spend[statId] = spend[statId] + 1 58 | local aura = player:GetAura(AttributesAuraIds[statId]) 59 | if (aura) then 60 | aura:SetStackAmount(spend[statId]) 61 | else 62 | player:AddAura(AttributesAuraIds[statId], player) 63 | end 64 | UpdatePlayerStats(player) 65 | end 66 | end 67 | end 68 | 69 | function MyHandlers.AttributesDecrease(player, statId) 70 | if (player:IsInCombat()) then 71 | player:SendBroadcastMessage("Du kannst während einem Kampfes keine Attributspunkte verteilen.") 72 | else 73 | local guid = player:GetGUIDLow() 74 | local spend, left = AttributesPointsSpend[guid], AttributesPointsLeft[guid] 75 | if not spend or not left then 76 | return 77 | end 78 | if not statId or not spend[statId] then 79 | return 80 | end 81 | if (spend[statId] <= 0) then 82 | player:SendBroadcastMessage("Es sind keine Punkte auf diesem Attribut verteilt.") 83 | else 84 | AttributesPointsLeft[guid] = left + 1 85 | spend[statId] = spend[statId] - 1 86 | local aura = player:GetAura(AttributesAuraIds[statId]) 87 | if (aura) then 88 | aura:SetStackAmount(spend[statId]) 89 | else 90 | player:AddAura(AttributesAuraIds[statId], player) 91 | end 92 | UpdatePlayerStats(player) 93 | end 94 | end 95 | end 96 | 97 | local function AttributesOnCommand(event, player, command) 98 | if(command == "para") then 99 | AIO.Handle(player, "Kaev", "ShowAttributes") 100 | return false 101 | end 102 | end 103 | RegisterPlayerEvent(42, AttributesOnCommand) 104 | -------------------------------------------------------------------------------- /Examples/PersistentVariables_Client.lua: -------------------------------------------------------------------------------- 1 | local AIO = AIO or require("AIO") 2 | if AIO.AddAddon() then 3 | return 4 | end 5 | 6 | -- This script shows how to 7 | 8 | -- Make a global variable 9 | -- Notice how the variable is only initialized if it doesnt exist yet because 10 | -- the persisting variable can be loaded already 11 | PLAYER_STUFF = PLAYER_STUFF or { var = 0 } 12 | 13 | -- Then you add it as a saved variable for account or character 14 | AIO.AddSavedVar("PLAYER_STUFF") 15 | 16 | -- Then you store data to it or read data from it 17 | PLAYER_STUFF.var = PLAYER_STUFF.var+1 18 | print("This value should increment on reloads of UI:", PLAYER_STUFF.var) 19 | -------------------------------------------------------------------------------- /Examples/PingPong.lua: -------------------------------------------------------------------------------- 1 | local AIO = AIO or require("AIO") 2 | 3 | local HandlePingPong 4 | if AIO.AddAddon() then 5 | -- we are on server 6 | 7 | -- When we receive PingPong message on server, print ping to the sender player 8 | -- and send pong message to him 9 | function HandlePingPong(player, msg) 10 | player:SendBroadcastMessage(tostring(msg)) 11 | AIO.Msg():Add("PingPong", "pong"):Send(player) 12 | end 13 | else 14 | -- we are on client 15 | 16 | -- store the time we send the ping here 17 | local senttime 18 | 19 | -- When we receive the PingPong message on client, print pong and the time it took to 20 | -- go from client to server to client. 21 | function HandlePingPong(player, msg) 22 | print(tostring(msg), time()-senttime) 23 | end 24 | 25 | -- just incase we are overwriting someone's function .. 26 | assert(not Ping, "PingPong: Ping is already defined") 27 | 28 | -- Send ping, ingame use /run Ping() to test this script 29 | function Ping() 30 | senttime = time() 31 | AIO.Msg():Add("PingPong", "ping"):Send() 32 | end 33 | Ping() -- automatically call on UI load 34 | end 35 | 36 | AIO.RegisterEvent("PingPong", HandlePingPong) 37 | -------------------------------------------------------------------------------- /Examples/README.md: -------------------------------------------------------------------------------- 1 | This folder contains example files for how to use AIO. Each folder or file in this folder is an example of it's own. 2 | 3 | To run the examples place all of their files to `/lua_scripts/` folder on your server. No files are placed on the client side folders. 4 | The files that have `client` in their name are usually sent in their entirety to the client from the server. 5 | Many examples have a lot of comments and it is recommended to try read through the comments to understand how the examples work. 6 | -------------------------------------------------------------------------------- /Examples/RunHelloFirst.lua: -------------------------------------------------------------------------------- 1 | local AIO = AIO or require("AIO") 2 | 3 | -- All addons are run on client side in the order they are added with 4 | -- AIO.AddAddon or AIO.AddAddonCode. If you want to control the order, you can 5 | -- simply require the file(s) to load first on the server side 6 | if AIO.IsServer() then 7 | require("HelloWorld") 8 | end 9 | 10 | -- or like this 11 | if AIO.AddAddon() then 12 | require("HelloWorld") 13 | return 14 | end 15 | 16 | print("'Hello Client' should be above this message, not below") 17 | 18 | -- You can also control the order by adding the addons "manually" by using 19 | -- AIO.AddAddon with the custom path or AIO.AddAddonCode 20 | -------------------------------------------------------------------------------- /Examples/TestWindow/ExampleClient.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (C) 2014- Rochet2 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | ]] 18 | 19 | --[[ 20 | This file is a client file and it handles all client side code. It is added on server 21 | side to a list of files to send to the client when the client reloads UI or logs in. 22 | This means that the file is run on server side and then on client side. 23 | This file should be placed somewhere in the lua_scripts folder so Eluna can load it. 24 | You can of course design your own addons and codes in some other way. 25 | 26 | Few tips: 27 | Size matters. The final compressed and obfuscated code will be sent to the client and 28 | if it is very large, it will take more messages and more work to send. 29 | Obfuscation will be done on startup so it will not slow down the sending process. 30 | AIO has a cache system that avoids unnecessary resending of unchanged addons 31 | between relogging. You can reset all client side saved information with /aio reset 32 | Type /aio help to see all other commands. 33 | 34 | Message compression and obfuscation should be turned on in AIO.lua files on server 35 | and client. If you want to debug your code and need to see the correct line numbers 36 | on error messages, disable obfuscation. 37 | Use locals! local variables will be shortened by obfuscation, so you should prefer 38 | local variables over global and you should try make functions, methods and variables local. 39 | Make functions out of repetitive code to make the code smaller. 40 | Obfuscation removes comments so you can have as much comments as you want in your code 41 | to keep it clear. 42 | 43 | After getting some base understanding of how things work, it is suggested to read all the AIO files. 44 | They contain a lot of new functions and information and everything has comments about what it does. 45 | ]] 46 | 47 | 48 | -- Note that getting AIO is done like this since AIO is defined on client 49 | -- side by default when running addons and on server side it may need to be 50 | -- required depending on the load order. 51 | local AIO = AIO or require("AIO") 52 | 53 | -- This will add this file to the server side list of addons to send to players. 54 | -- The function is coded to get the path and file name automatically, 55 | -- but you can also provide them yourself. AIO.AddAddon will return true if the 56 | -- addon was added to the list of loaded addons, this means that if the 57 | -- function returns true the file is being executed on server side and we 58 | -- return since this is a client file. On client side the file will be executed 59 | -- entirely. 60 | if AIO.AddAddon() then 61 | return 62 | end 63 | 64 | -- AIO.AddHandlers adds a new table of functions as handlers for a name and returns the table. 65 | -- This is used to add functions for a specific "channel name" that trigger on specific messages. 66 | -- At this point the table is empty, but MyHandlers table will be filled soon. 67 | local MyHandlers = AIO.AddHandlers("AIOExample", {}) 68 | -- You can also call this after filling the table. like so: 69 | -- local MyHandlers = {}; ..fill MyHandlers table.. AIO.AddHandlers("AIOExample", MyHandlers) 70 | 71 | -- Lets create some UI frames for the client. 72 | -- Note that this code is executed on addon side - you can use any addon API function etc. 73 | 74 | -- Create the base frame. 75 | FrameTest = CreateFrame("Frame", "FrameTest", UIParent, "UIPanelDialogTemplate") 76 | local frame = FrameTest 77 | 78 | -- Some basic method usage.. 79 | -- Read the wow addon widget API for what each function does: 80 | -- http://wowwiki.wikia.com/Widget_API 81 | frame:SetSize(200, 200) 82 | frame:RegisterForDrag("LeftButton") 83 | frame:SetPoint("CENTER") 84 | frame:SetToplevel(true) 85 | frame:SetClampedToScreen(true) 86 | -- Enable dragging of frame 87 | frame:SetMovable(true) 88 | frame:EnableMouse(true) 89 | frame:SetScript("OnDragStart", frame.StartMoving) 90 | frame:SetScript("OnHide", frame.StopMovingOrSizing) 91 | frame:SetScript("OnDragStop", frame.StopMovingOrSizing) 92 | 93 | -- This enables saving of the position of the frame over reload of the UI or restarting game 94 | AIO.SavePosition(frame) 95 | 96 | -- A handler triggered by using AIO.Handle(player, "AIOExample", "ShowFrame") 97 | -- on server side. 98 | function MyHandlers.ShowFrame(player) 99 | frame:Show() 100 | end 101 | 102 | -- Creating an input: 103 | local input = CreateFrame("EditBox", "InputTest", frame, "InputBoxTemplate") 104 | input:SetSize(100, 30) 105 | input:SetAutoFocus(false) 106 | input:SetPoint("CENTER", frame, "CENTER", 0, 50) 107 | input:SetScript("OnEnterPressed", input.ClearFocus) 108 | input:SetScript("OnEscapePressed", input.ClearFocus) 109 | 110 | -- Creating a slider: 111 | local slider = CreateFrame("Slider", "SlideTest", frame, "OptionsSliderTemplate") 112 | slider:SetSize(100, 17) 113 | slider:SetPoint("CENTER", frame, "CENTER", 0, -50) 114 | slider:SetValueStep(0.5) 115 | slider:SetMinMaxValues(0, 100) 116 | slider:SetValue(50) 117 | slider.tooltipText = 'This is the Tooltip hint' 118 | _G[slider:GetName() .."Text"]:SetText(50) 119 | slider:SetScript("OnValueChanged", function(self) _G[slider:GetName() .."Text"]:SetText(self:GetValue()) end) 120 | _G[slider:GetName().."High"]:Hide() 121 | _G[slider:GetName().."Low"]:Hide() 122 | slider:Show() 123 | 124 | -- Creating a child, a button: 125 | local button = CreateFrame("Button", "ButtonTest", frame) 126 | button:SetSize(100, 30) 127 | button:SetPoint("CENTER", frame, "CENTER") 128 | button:EnableMouse(true) 129 | -- Small script to clear the focus from input on click 130 | button:SetScript("OnMouseUp", function() input:ClearFocus() end) 131 | -- Usually I use UIPanelButtonTemplate for buttons, but I wanted to show and test some custom color texture here: 132 | local texture = button:CreateTexture("TextureTest") 133 | texture:SetAllPoints(button) 134 | texture:SetTexture(0.5, 1, 1, 0.5) 135 | button:SetNormalTexture(texture) 136 | -- Set the font, could use GameFontNormal template, but I wanted to create my own 137 | local fontstring = button:CreateFontString("FontTest") 138 | fontstring:SetFont("Fonts\\FRIZQT__.TTF", 11, "OUTLINE, MONOCHROME") 139 | fontstring:SetShadowOffset(1, -1) 140 | button:SetFontString(fontstring) 141 | button:SetText("Test") 142 | 143 | -- You can do a lot of things on client side events. 144 | -- You can find all events for different frame types here: http://wowwiki.wikia.com/Widget_handlers 145 | -- Here I send a message to the server that executes the print handler 146 | -- See the ExampleServer.lua file for the server side print handler. 147 | local function OnClickButton(btn) 148 | AIO.Handle("AIOExample", "Print", btn:GetName(), input:GetText(), slider:GetValue()) 149 | end 150 | button:SetScript("OnClick", OnClickButton) 151 | -------------------------------------------------------------------------------- /Examples/TestWindow/ExampleServer.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (C) 2014- Rochet2 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | ]] 18 | 19 | --[[ 20 | This file is a server file. It is loaded on server side and handles all server side code. 21 | This file should be placed somewhere in the lua_scripts folder so Eluna can load it. 22 | You can of course design your own addons and codes in some other way. 23 | 24 | Few tips: 25 | On server side the code size does not matter, however safety does! 26 | On client side safety is not needed, but server safety will avoid nasty behavior and errors. 27 | The client may send ANY data. Be cautious and make sure the data you receive is indeed the type you 28 | expect it to be. 29 | 30 | Message compression and obfuscation should be turned on in AIO.lua files on server 31 | and client. If you want to debug your code and need to see the correct line numbers 32 | on error messages, disable obfuscation. 33 | 34 | After getting some base understanding of how things work, it is suggested to read all the AIO files. 35 | They contain a lot of new functions and information and everything has comments about what it does. 36 | ]] 37 | 38 | 39 | -- Note that getting AIO is done like this since AIO is defined on client 40 | -- side by default when running addons and on server side it may need to be 41 | -- required depending on the load order. On server only files the require 42 | -- would be enough, but lets just keep it like this for the sake of consistency 43 | local AIO = AIO or require("AIO") 44 | 45 | -- AIO.AddHandlers adds a new table of functions as handlers for a name and returns the table. 46 | -- This is used to add functions for a specific "channel name" that trigger on specific messages. 47 | -- At this point the table is empty, but MyHandlers table will be filled soon. 48 | local MyHandlers = AIO.AddHandlers("AIOExample", {}) 49 | -- You can also call this after filling the table. like so: 50 | -- local MyHandlers = {}; ..fill MyHandlers table.. AIO.AddHandlers("AIOExample", MyHandlers) 51 | 52 | -- An example handler. 53 | -- This prints all the values the client sends with the command 54 | -- AIO.Handle("AIOExample", "print") 55 | function MyHandlers.Print(player, ...) 56 | print(...) 57 | end 58 | 59 | -- When a player uses command .test, show the UI to player 60 | -- The showing is done by sending a message to the client that then does whatever 61 | -- we have coded to be done when receiving the message 62 | local function OnCommand(event, player, command) 63 | if(command == "test") then 64 | -- Note that AIO.Handle has two different definitions: 65 | -- On client side you don't pass the player argument 66 | AIO.Handle(player, "AIOExample", "ShowFrame") 67 | return false 68 | end 69 | end 70 | 71 | RegisterPlayerEvent(42, OnCommand) 72 | 73 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AIO 2 | AIO is a pure lua server-client communication system for Eluna and WoW. 3 | AIO is designed for sending lua addons and data to player from server and data from player to server. 4 | Made for [Eluna Lua Engine](https://github.com/ElunaLuaEngine/Eluna). Tested on 3.3.5a and should work on other patches. Tested with Lua 5.1 and 5.2. 5 | [Third party C++ support is made by SaiFi0102](https://github.com/SaiFi0102/TrinityCore/blob/CAIO-3.3.5/CAIO_README.md). It allows you to use AIO without requiring Eluna. 6 | 7 | Backlink: https://github.com/Rochet2/AIO 8 | 9 | # Installation 10 | - Make sure you have [Eluna Lua Engine](https://github.com/ElunaLuaEngine/Eluna) 11 | - Copy the `AIO_Client` to your `WoW_installation_folder/Interface/AddOns/` 12 | - Copy the `AIO_Server` to your `server_root/lua_scripts/` 13 | - See configuration settings on AIO.lua file. You can tweak both the server and client file respectively 14 | - When developing an addon it is recommended to have AIO_ENABLE_PCALL off and sometimes you may need AIO_ENABLE_DEBUG_MSGS on to see some information about what is going on. 15 | 16 | # About 17 | AIO works so that the server and client have their own lua scripts that handle sending and receiving messages from and to eachother. 18 | When an addon added to AIO as an addon to send to the client, it will be processed (depending on settings, obfuscated and compressed) and stored in memory to wait for sending to players. 19 | All addons that are added are executed on client side in the order they were added to AIO. 20 | AIO is using a cache system to cache the addon codes to client side so they dont need to be sent on every login. 21 | Only if an addon is changed or added the new addon is sent again. The user can also clear his local AIO cache in which case the addons will be sent again. 22 | The full addon code sent to client is executed on client as is. The code has full access to the client side addon API. 23 | The client-server messaging is handled with an AIO message helper class. It holds and manages the data to send over. 24 | 25 | # Commands 26 | There are some commands that may be useful. 27 | On client side use `/aio help` to see a list of them. On server side use `.aio help` to see a list of them. 28 | 29 | # Safety 30 | The messaging between server and client is coded to be safe 31 | 32 | - you can limit the cache sizes, delays and other in AIO.lua 33 | - data received from client is only deserialized - no compressions etc. 34 | - serialization library is not using loadstring to make deserialization safe 35 | - when receiving messages the code is run in pcall to prevent all user sent data creating errors. Set debug messages on in AIO.lua to see all errors on server side as well 36 | - the code is only as safe as you make it. In your own codes make sure all data the client sends to server and you use is the type you expect it to be and is in the range you expect it to be in. (example: math.huge is a number type, but not a real number) 37 | - make sure your code has asserts in place and is fast. There is a tweakable timeout in AIO.lua just to be sure that the server will not hang if you happen to write bad or abusable code or if a bad user finds a way to hang the system 38 | - Do check the AIO.lua settings and tweak them to your needs for both client and server respectively. This is important to fend off bad users and make things work better with your setup. 39 | 40 | # Handlers 41 | AIO has a few handlers by default that are used for the internal codes and you can 42 | use them if you wish. 43 | You can also code your own handlers and add them to AIO with the functions described in API section. See AIO.RegisterEvent(name, func) and AIO.AddHandlers(name, handlertable) 44 | 45 | ```lua 46 | -- Force reload of player UI 47 | -- Displays a message that UI is being force reloaded and reloads UI when player 48 | -- clicks anywhere in his screen. 49 | AIO.Handle(player, "AIO", "ForceReload") 50 | 51 | -- Force reset of player UI 52 | -- Resets AIO addon saved variables and displays a message that UI is being force 53 | -- reloaded and reloads UI when player clicks anywhere in his screen. 54 | AIO.Handle(player, "AIO", "ForceReset") 55 | ``` 56 | 57 | # API 58 | For example scripts see the Examples folder. The example files are named according to their final execution location. To run the examples place all of their files to `server_root/lua_scripts/`. 59 | 60 | There are some client side commands. Use the slash command `/aio` ingame to see list of commands 61 | 62 | ```lua 63 | -- AIO is required this way due to server and client differences with require function 64 | local AIO = AIO or require("AIO") 65 | 66 | -- Returns true if we are on server side, false if we are on client side 67 | isServer = AIO.IsServer() 68 | 69 | -- Returns AIO version - note the type is not guaranteed to be a number 70 | version = AIO.GetVersion() 71 | 72 | -- Adds the file at given path to files to send to players if called on server side. 73 | -- The addon code is trimmed according to settings in AIO.lua. 74 | -- The addon is cached on client side and will be updated only when needed. 75 | -- Returns false on client side and true on server side. By default the 76 | -- path is the current file's path and name is the file's name 77 | -- 'path' is relative to worldserver.exe but an absolute path can also be given. 78 | -- You should call this function only on startup to ensure everyone gets the same 79 | -- addons and no addon is duplicate. 80 | added = AIO.AddAddon([path, name]) 81 | -- The way this is designed to be used is at the top of an addon file so that the 82 | -- file is added and not run if we are on server, and just run if we are on client: 83 | if AIO.AddAddon() then 84 | return 85 | end 86 | 87 | -- Similar to AddAddon - Adds 'code' to the addons sent to players. The code is trimmed 88 | -- according to settings in AIO.lua. The addon is cached on client side and will 89 | -- be updated only when needed. 'name' is an unique name for the addon, usually 90 | -- you can use the file name or addon name there. Do note that short names are 91 | -- better since they are sent back and forth to indentify files. 92 | -- The function only exists on server side. 93 | -- You should call this function only on startup to ensure everyone gets the same 94 | -- addons and no addon is duplicate. 95 | AIO.AddAddonCode(name, code) 96 | 97 | -- Triggers the handler function that has the name 'handlername' from the handlertable 98 | -- added with AIO.AddHandlers(name, handlertable) for the 'name'. 99 | -- Can also trigger a function registered with AIO.RegisterEvent(name, func) 100 | -- All triggered handlers have parameters handler(player, ...) where varargs are 101 | -- the varargs in AIO.Handle or msg.Add 102 | -- This function is a shorthand for AIO.Msg():Add(name, handlername, ...):Send() 103 | -- For efficiency favour creating messages once and sending them rather than creating 104 | -- them over and over with AIO.Handle(). 105 | -- The server side version. 106 | AIO.Handle(player, name, handlername[, ...]) 107 | -- The client side version. 108 | AIO.Handle(name, handlername[, ...]) 109 | 110 | -- Adds a table of handler functions for the specified 'name'. When a message like: 111 | -- AIO.Handle(name, "HandlerName", ...) is received, the handlertable["HandlerName"] 112 | -- will be called with player and varargs as parameters. 113 | -- Returns the passed 'handlertable'. 114 | -- AIO.AddHandlers uses AIO.RegisterEvent internally, so same name can not be used on both. 115 | handlertable = AIO.AddHandlers(name, handlertable) 116 | 117 | -- Adds a new callback function that is called if a message with the given 118 | -- name is recieved. All parameters the sender sends in the message will 119 | -- be passed to func when called. 120 | -- Example message: AIO.Msg():Add(name, ...):Send() 121 | -- AIO.AddHandlers uses AIO.RegisterEvent internally, so same name can not be used on both. 122 | AIO.RegisterEvent(name, func) 123 | 124 | -- Adds a new function that is called when the initial message is sent to the player. 125 | -- The function is called before sending and the initial message is passed to it 126 | -- along with the player if available: func(msg[, player]) 127 | -- In the function you can modify the passed msg and/or return a new one to be 128 | -- used as initial message. Only on server side. 129 | -- This can be used to send for example initial values (like player stats) for the addons. 130 | -- If dynamic loading is preferred, you can use the messaging API to request the values 131 | -- on demand also. 132 | AIO.AddOnInit(func) 133 | 134 | -- Key is a key for a variable in the global table _G. 135 | -- The variable is stored when the player logs out and will be restored 136 | -- when he logs back in before the addon codes are run. 137 | -- These variables are account bound. 138 | -- Only exists on client side and you should call it only once per key. 139 | -- All saved data is saved to client side. 140 | AIO.AddSavedVar(key) 141 | 142 | -- Key is a key for a variable in the global table _G. 143 | -- The variable is stored when the player logs out and will be restored 144 | -- when he logs back in before the addon codes are run. 145 | -- These variables are character bound. 146 | -- Only exists on client side and you should call it only once per key. 147 | -- All saved data is saved to client side. 148 | AIO.AddSavedVarChar(key) 149 | 150 | -- Makes the addon frame save it's position and restore it on login. 151 | -- If char is true, the position saving is character bound, otherwise account bound. 152 | -- Only exists on client side and you should call it only once per frame. 153 | -- All saved data is saved to client side. 154 | AIO.SavePosition(frame[, char]) 155 | 156 | -- AIO message class: 157 | -- Creates and returns a new AIO message that you can append stuff to and send to 158 | -- client or server. Example: AIO.Msg():Add("MyHandlerName", param1, param2):Send(player) 159 | -- These messages handle all client-server communication. 160 | msg = AIO.Msg() 161 | 162 | -- The name is used to identify the handler function on receiving end. 163 | -- A handler function registered with AIO.RegisterEvent(name, func) 164 | -- will be called on receiving end with the varargs. 165 | function msgmt:Add(name, ...) 166 | 167 | -- Appends messages to eachother, returns self 168 | msg = msg:Append(msg2) 169 | 170 | -- Sends the message, returns self 171 | -- Server side version - sends to all players passed 172 | msg = msg:Send(player, ...) 173 | -- Client side version - sends to server 174 | msg = msg:Send() 175 | 176 | -- Returns true if the message has something in it 177 | hasmsg = msg:HasMsg() 178 | 179 | -- Returns the message as a string 180 | msgstr = msg:ToString() 181 | 182 | -- Erases the so far built message and returns self 183 | msg = msg:Clear() 184 | 185 | -- Assembles the message string from added and appended data. Mainly for internal use. 186 | -- Returns self 187 | msg = msg:Assemble() 188 | ``` 189 | 190 | # Included dependencies 191 | You do not need to get these, they are already included 192 | - Lua serializer: https://github.com/gvx/Smallfolk 193 | - Lua crc32: https://github.com/davidm/lua-digest-crc32lua 194 | - Lua queue with modifications: http://www.lua.org/pil/11.4.html 195 | - Compression for string data: https://github.com/Rochet2/lualzw/tree/zeros 196 | - Obfuscation for addon code: http://luasrcdiet.luaforge.net/ 197 | - Sent addons' frame position saving: http://www.wowace.com/addons/libwindow-1-1/ 198 | 199 | # Special thanks 200 | - Kenuvis < [Gate](http://www.ac-web.org/forums/showthread.php?148415-LUA-Gate-Project), [ElunaGate](https://github.com/ElunaLuaEngine/ElunaGate) > 201 | - Laurea/alexeng/Kyromyr < https://github.com/Alexeng, https://github.com/Kyromyr> 202 | - Foereaper < https://github.com/Foereaper > 203 | - SaiF < https://github.com/SaiFi0102 > 204 | - Eluna team < https://github.com/ElunaLuaEngine/Eluna#team > 205 | - Lua contributors < http://www.lua.org/ > 206 | --------------------------------------------------------------------------------