mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 21:53:46 +03:00
Upload
This commit is contained in:
362
gamemodes/helix/gamemode/core/libs/thirdparty/cl_ikon.lua
vendored
Normal file
362
gamemodes/helix/gamemode/core/libs/thirdparty/cl_ikon.lua
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
--[[
|
||||
BLACK TEA ICON LIBRARY FOR NUTSCRIPT 1.1
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017, Kyu Yeon Lee(Black Tea Za rebel1324)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so, subject
|
||||
to the following conditions:
|
||||
|
||||
The above copyright notice and thispermission notice shall be included in all copies
|
||||
or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
TL;DR: https://tldrlegal.com/license/mit-license
|
||||
OK -
|
||||
Commercial Use
|
||||
Modify
|
||||
Distribute
|
||||
Sublicense
|
||||
Private Use
|
||||
|
||||
NOT OK -
|
||||
Hold Liable
|
||||
|
||||
MUST -
|
||||
Include Copyright
|
||||
Include License
|
||||
]]--
|
||||
|
||||
--[[
|
||||
Default Tables.
|
||||
]]--
|
||||
|
||||
ikon = ikon or {}
|
||||
ikon.cache = ikon.cache or {}
|
||||
ikon.requestList = ikon.requestList or {}
|
||||
ikon.dev = false
|
||||
ikon.maxSize = 8 -- 8x8 (512^2) is max icon size.
|
||||
|
||||
IKON_BUSY = 1
|
||||
IKON_PROCESSING = 0
|
||||
IKON_SOMETHINGWRONG = -1
|
||||
|
||||
local schemaName = schemaName or (Schema and Schema.folder)
|
||||
|
||||
--[[
|
||||
Initialize hooks and RT Screens.
|
||||
returns nothing
|
||||
]]--
|
||||
function ikon:init()
|
||||
if (self.dev) then
|
||||
hook.Add("HUDPaint", "ikon_dev2", ikon.showResult)
|
||||
else
|
||||
hook.Remove("HUDPaint", "ikon_dev2")
|
||||
end
|
||||
|
||||
--[[
|
||||
Being good at gmod is knowing all of stinky hacks
|
||||
- Black Tea (2017)
|
||||
]]--
|
||||
ikon.haloAdd = ikon.haloAdd or halo.Add
|
||||
function halo.Add(...)
|
||||
if (ikon.rendering != true) then
|
||||
ikon.haloAdd(...)
|
||||
end
|
||||
end
|
||||
|
||||
ikon.haloRender = ikon.haloRender or halo.Render
|
||||
function halo.Render(...)
|
||||
if (ikon.rendering != true) then
|
||||
ikon.haloRender(...)
|
||||
end
|
||||
end
|
||||
|
||||
file.CreateDir("helix/icons")
|
||||
file.CreateDir("helix/icons/" .. schemaName)
|
||||
end
|
||||
|
||||
--[[
|
||||
IKON Library Essential Material/Texture Declare
|
||||
]]--
|
||||
|
||||
local TEXTURE_FLAGS_CLAMP_S = 0x0004
|
||||
local TEXTURE_FLAGS_CLAMP_T = 0x0008
|
||||
|
||||
ikon.max = ikon.maxSize * 64
|
||||
ikon.RT = GetRenderTargetEx("ixIconRendered",
|
||||
ikon.max,
|
||||
ikon.max,
|
||||
RT_SIZE_NO_CHANGE,
|
||||
MATERIAL_RT_DEPTH_SHARED,
|
||||
bit.bor(TEXTURE_FLAGS_CLAMP_S, TEXTURE_FLAGS_CLAMP_T),
|
||||
CREATERENDERTARGETFLAGS_UNFILTERABLE_OK,
|
||||
IMAGE_FORMAT_RGBA8888
|
||||
)
|
||||
|
||||
local tex_effect = GetRenderTarget("ixIconRenderedOutline", ikon.max, ikon.max)
|
||||
local mat_outline = CreateMaterial("ixIconRenderedTemp", "UnlitGeneric", {
|
||||
["$basetexture"] = tex_effect:GetName(),
|
||||
["$translucent"] = 1
|
||||
})
|
||||
|
||||
local lightPositions = {
|
||||
BOX_TOP = Color(255, 255, 255),
|
||||
BOX_FRONT = Color(255, 255, 255),
|
||||
}
|
||||
function ikon:renderHook()
|
||||
local entity = ikon.renderEntity
|
||||
|
||||
if (halo.RenderedEntity() == entity) then
|
||||
return
|
||||
end
|
||||
|
||||
local w, h = ikon.curWidth * 64, ikon.curHeight * 64
|
||||
local x, y = 0, 0
|
||||
local tab
|
||||
|
||||
if (ikon.info) then
|
||||
tab = {
|
||||
origin = ikon.info.pos,
|
||||
angles = ikon.info.ang,
|
||||
fov = ikon.info.fov,
|
||||
outline = ikon.info.outline,
|
||||
outCol = ikon.info.outlineColor
|
||||
}
|
||||
|
||||
if (!tab.origin and !tab.angles and !tab.fov) then
|
||||
table.Merge(tab, PositionSpawnIcon(entity, entity:GetPos(), true))
|
||||
end
|
||||
else
|
||||
tab = PositionSpawnIcon(entity, entity:GetPos(), true)
|
||||
end
|
||||
|
||||
-- Taking MDave's Tip
|
||||
xpcall(function()
|
||||
render.OverrideAlphaWriteEnable(true, true) -- some playermodel eyeballs will not render without this
|
||||
render.SetWriteDepthToDestAlpha(false)
|
||||
render.OverrideBlend(true, BLEND_ONE, BLEND_ONE, BLENDFUNC_ADD, BLEND_ONE, BLEND_ONE, BLENDFUNC_ADD)
|
||||
render.SuppressEngineLighting(true)
|
||||
render.Clear(0, 0, 0, 0, true, true)
|
||||
|
||||
render.SetLightingOrigin(vector_origin)
|
||||
render.ResetModelLighting(200 / 255, 200 / 255, 200 / 255)
|
||||
render.SetColorModulation(1, 1, 1)
|
||||
|
||||
for i = 0, 6 do
|
||||
local col = lightPositions[i]
|
||||
|
||||
if (col) then
|
||||
render.SetModelLighting(i, col.r / 255, col.g / 255, col.b / 255)
|
||||
end
|
||||
end
|
||||
|
||||
if (tab.outline) then
|
||||
ix.util.ResetStencilValues()
|
||||
render.SetStencilEnable(true)
|
||||
render.SetStencilWriteMask(137) -- yeah random number to avoid confliction
|
||||
render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_ALWAYS)
|
||||
render.SetStencilPassOperation(STENCILOPERATION_REPLACE)
|
||||
render.SetStencilFailOperation(STENCILOPERATION_REPLACE)
|
||||
end
|
||||
|
||||
--[[
|
||||
Add more effects on the Models!
|
||||
]]--
|
||||
if (ikon.info and ikon.info.drawHook) then
|
||||
ikon.info.drawHook(entity)
|
||||
end
|
||||
|
||||
cam.Start3D(tab.origin, tab.angles, tab.fov, 0, 0, w, h)
|
||||
render.SetBlend(1)
|
||||
entity:DrawModel()
|
||||
cam.End3D()
|
||||
|
||||
if (tab.outline) then
|
||||
render.PushRenderTarget(tex_effect)
|
||||
render.Clear(0, 0, 0, 0)
|
||||
render.ClearDepth()
|
||||
cam.Start2D()
|
||||
cam.Start3D(tab.origin, tab.angles, tab.fov, 0, 0, w, h)
|
||||
render.SetBlend(0)
|
||||
entity:DrawModel()
|
||||
|
||||
render.SetStencilWriteMask(138) -- could you please?
|
||||
render.SetStencilTestMask(1)
|
||||
render.SetStencilReferenceValue(1)
|
||||
render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_EQUAL)
|
||||
render.SetStencilPassOperation(STENCILOPERATION_KEEP)
|
||||
render.SetStencilFailOperation(STENCILOPERATION_KEEP)
|
||||
cam.Start2D()
|
||||
surface.SetDrawColor(tab.outCol or color_white)
|
||||
surface.DrawRect(0, 0, ScrW(), ScrH())
|
||||
cam.End2D()
|
||||
cam.End3D()
|
||||
cam.End2D()
|
||||
render.PopRenderTarget()
|
||||
|
||||
render.SetBlend(1)
|
||||
render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_NOTEQUAL)
|
||||
|
||||
--[[
|
||||
Thanks for Noiwex
|
||||
NxServ.eu
|
||||
]]--
|
||||
cam.Start2D()
|
||||
surface.SetMaterial(mat_outline)
|
||||
surface.DrawTexturedRectUV(-2, 0, w, h, 0, 0, w / ikon.max, h / ikon.max)
|
||||
surface.DrawTexturedRectUV(2, 0, w, h, 0, 0, w / ikon.max, h / ikon.max)
|
||||
surface.DrawTexturedRectUV(0, 2, w, h, 0, 0, w / ikon.max, h / ikon.max)
|
||||
surface.DrawTexturedRectUV(0, -2, w, h, 0, 0, w / ikon.max, h / ikon.max)
|
||||
cam.End2D()
|
||||
|
||||
render.SetStencilEnable(false)
|
||||
end
|
||||
|
||||
render.SuppressEngineLighting(false)
|
||||
render.SetWriteDepthToDestAlpha(true)
|
||||
render.OverrideAlphaWriteEnable(false)
|
||||
end, function(message)
|
||||
print(message)
|
||||
end)
|
||||
end
|
||||
|
||||
function ikon:showResult()
|
||||
local x, y = ScrW() / 2, ScrH() / 2
|
||||
local w, h = ikon.curWidth * 64, ikon.curHeight * 64
|
||||
|
||||
surface.SetDrawColor(255, 255, 255, 255)
|
||||
surface.DrawOutlinedRect(x, 0, w, h)
|
||||
|
||||
surface.SetMaterial(mat_outline)
|
||||
surface.DrawTexturedRect(x, 0, w, h)
|
||||
end
|
||||
|
||||
--[[
|
||||
Renders the Icon with given arguments.
|
||||
returns nothing
|
||||
]]--
|
||||
function ikon:renderIcon(name, w, h, mdl, camInfo, updateCache)
|
||||
if (#ikon.requestList > 0) then return IKON_BUSY end
|
||||
if (ikon.requestList[name]) then return IKON_PROCESSING end
|
||||
if (!w or !h or !mdl) then return IKON_SOMETHINGWRONG end
|
||||
|
||||
local capturedIcon
|
||||
ikon.curWidth = w or 1
|
||||
ikon.curHeight = h or 1
|
||||
ikon.renderModel = mdl
|
||||
|
||||
if (camInfo) then
|
||||
ikon.info = camInfo
|
||||
end
|
||||
|
||||
local w, h = ikon.curWidth * 64, ikon.curHeight * 64
|
||||
local sw, sh = ScrW(), ScrH()
|
||||
|
||||
if (ikon.renderModel) then
|
||||
if (!IsValid(ikon.renderEntity)) then
|
||||
ikon.renderEntity = ClientsideModel(ikon.renderModel, RENDERGROUP_BOTH)
|
||||
ikon.renderEntity:SetNoDraw(true)
|
||||
end
|
||||
end
|
||||
|
||||
ikon.renderEntity:SetModel(ikon.renderModel)
|
||||
|
||||
local bone = ikon.renderEntity:LookupBone("ValveBiped.Bip01_Head1")
|
||||
|
||||
if (bone) then
|
||||
ikon.renderEntity:SetEyeTarget(ikon.renderEntity:GetBonePosition(bone) + ikon.renderEntity:GetForward() * 32)
|
||||
end
|
||||
|
||||
local oldRT = render.GetRenderTarget()
|
||||
render.PushRenderTarget(ikon.RT)
|
||||
|
||||
ikon.rendering = true
|
||||
ikon:renderHook()
|
||||
ikon.rendering = nil
|
||||
|
||||
capturedIcon = render.Capture({
|
||||
format = "png",
|
||||
alpha = true,
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = w,
|
||||
h = h
|
||||
})
|
||||
|
||||
file.Write("helix/icons/" .. schemaName .. "/" .. name .. ".png", capturedIcon)
|
||||
ikon.info = nil
|
||||
render.PopRenderTarget()
|
||||
|
||||
if (updateCache) then
|
||||
local materialID = tostring(os.time())
|
||||
file.Write(materialID .. ".png", capturedIcon)
|
||||
|
||||
timer.Simple(0, function()
|
||||
local material = Material("../data/".. materialID ..".png")
|
||||
|
||||
ikon.cache[name] = material
|
||||
file.Delete(materialID .. ".png")
|
||||
end)
|
||||
end
|
||||
|
||||
ikon.requestList[name] = nil
|
||||
return true
|
||||
end
|
||||
|
||||
--[[
|
||||
Gets rendered icon with given unique name.
|
||||
returns IMaterial
|
||||
]]--
|
||||
function ikon:GetIcon(name)
|
||||
if (ikon.cache[name]) then
|
||||
return ikon.cache[name] -- yeah return cache
|
||||
end
|
||||
|
||||
if (file.Exists("helix/icons/" .. schemaName .. "/" .. name .. ".png", "DATA")) then
|
||||
ikon.cache[name] = Material("../data/helix/icons/" .. schemaName .. "/".. name ..".png")
|
||||
return ikon.cache[name] -- yeah return cache
|
||||
else
|
||||
return false -- retryd
|
||||
end
|
||||
end
|
||||
|
||||
concommand.Add("ix_flushicon", function()
|
||||
local root = "helix/icons/" .. schemaName
|
||||
|
||||
for _, v in pairs(file.Find(root .. "/*.png", "DATA")) do
|
||||
file.Delete(root .. "/" .. v)
|
||||
end
|
||||
|
||||
ikon.cache = {}
|
||||
end)
|
||||
|
||||
hook.Add("InitializedSchema", "updatePath", function()
|
||||
schemaName = Schema.folder
|
||||
ikon:init()
|
||||
end)
|
||||
|
||||
if (schemaName) then
|
||||
ikon:init()
|
||||
end
|
||||
1870
gamemodes/helix/gamemode/core/libs/thirdparty/data/sh_utf8_casemap.lua
vendored
Normal file
1870
gamemodes/helix/gamemode/core/libs/thirdparty/data/sh_utf8_casemap.lua
vendored
Normal file
File diff suppressed because it is too large
Load Diff
560
gamemodes/helix/gamemode/core/libs/thirdparty/sh_cami.lua
vendored
Normal file
560
gamemodes/helix/gamemode/core/libs/thirdparty/sh_cami.lua
vendored
Normal file
@@ -0,0 +1,560 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
--[[
|
||||
CAMI - Common Admin Mod Interface.
|
||||
Makes admin mods intercompatible and provides an abstract privilege interface
|
||||
for third party addons.
|
||||
|
||||
Follows the specification on this page:
|
||||
https://docs.google.com/document/d/1QIRVcAgZfAYf1aBl_dNV_ewR6P25wze2KmUVzlbFgMI
|
||||
|
||||
Structures:
|
||||
CAMI_USERGROUP, defines the charactaristics of a usergroup:
|
||||
{
|
||||
Name
|
||||
string
|
||||
The name of the usergroup
|
||||
Inherits
|
||||
string
|
||||
The name of the usergroup this usergroup inherits from
|
||||
}
|
||||
|
||||
CAMI_PRIVILEGE, defines the charactaristics of a privilege:
|
||||
{
|
||||
Name
|
||||
string
|
||||
The name of the privilege
|
||||
MinAccess
|
||||
string
|
||||
One of the following three: user/admin/superadmin
|
||||
Description
|
||||
string
|
||||
optional
|
||||
A text describing the purpose of the privilege
|
||||
HasAccess
|
||||
function(
|
||||
privilege :: CAMI_PRIVILEGE,
|
||||
actor :: Player,
|
||||
target :: Player
|
||||
) :: bool
|
||||
optional
|
||||
Function that decides whether a player can execute this privilege,
|
||||
optionally on another player (target).
|
||||
}
|
||||
]]
|
||||
|
||||
-- Version number in YearMonthDay format.
|
||||
local version = 20190102
|
||||
|
||||
if CAMI and CAMI.Version >= version then return end
|
||||
|
||||
CAMI = CAMI or {}
|
||||
CAMI.Version = version
|
||||
|
||||
--[[
|
||||
usergroups
|
||||
Contains the registered CAMI_USERGROUP usergroup structures.
|
||||
Indexed by usergroup name.
|
||||
]]
|
||||
local usergroups = CAMI.GetUsergroups and CAMI.GetUsergroups() or {
|
||||
user = {
|
||||
Name = "user",
|
||||
Inherits = "user"
|
||||
},
|
||||
admin = {
|
||||
Name = "admin",
|
||||
Inherits = "user"
|
||||
},
|
||||
superadmin = {
|
||||
Name = "superadmin",
|
||||
Inherits = "admin"
|
||||
}
|
||||
}
|
||||
|
||||
--[[
|
||||
privileges
|
||||
Contains the registered CAMI_PRIVILEGE privilege structures.
|
||||
Indexed by privilege name.
|
||||
]]
|
||||
local privileges = CAMI.GetPrivileges and CAMI.GetPrivileges() or {}
|
||||
|
||||
--[[
|
||||
CAMI.RegisterUsergroup
|
||||
Registers a usergroup with CAMI.
|
||||
|
||||
Parameters:
|
||||
usergroup
|
||||
CAMI_USERGROUP
|
||||
(see CAMI_USERGROUP structure)
|
||||
source
|
||||
any
|
||||
Identifier for your own admin mod. Can be anything.
|
||||
Use this to make sure CAMI.RegisterUsergroup function and the
|
||||
CAMI.OnUsergroupRegistered hook don't cause an infinite loop
|
||||
|
||||
|
||||
|
||||
Return value:
|
||||
CAMI_USERGROUP
|
||||
The usergroup given as argument.
|
||||
]]
|
||||
function CAMI.RegisterUsergroup(usergroup, source)
|
||||
usergroups[usergroup.Name] = usergroup
|
||||
|
||||
hook.Call("CAMI.OnUsergroupRegistered", nil, usergroup, source)
|
||||
return usergroup
|
||||
end
|
||||
|
||||
--[[
|
||||
CAMI.UnregisterUsergroup
|
||||
Unregisters a usergroup from CAMI. This will call a hook that will notify
|
||||
all other admin mods of the removal.
|
||||
|
||||
Call only when the usergroup is to be permanently removed.
|
||||
|
||||
Parameters:
|
||||
usergroupName
|
||||
string
|
||||
The name of the usergroup.
|
||||
source
|
||||
any
|
||||
Identifier for your own admin mod. Can be anything.
|
||||
Use this to make sure CAMI.UnregisterUsergroup function and the
|
||||
CAMI.OnUsergroupUnregistered hook don't cause an infinite loop
|
||||
|
||||
Return value:
|
||||
bool
|
||||
Whether the unregistering succeeded.
|
||||
]]
|
||||
function CAMI.UnregisterUsergroup(usergroupName, source)
|
||||
if not usergroups[usergroupName] then return false end
|
||||
|
||||
local usergroup = usergroups[usergroupName]
|
||||
usergroups[usergroupName] = nil
|
||||
|
||||
hook.Call("CAMI.OnUsergroupUnregistered", nil, usergroup, source)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--[[
|
||||
CAMI.GetUsergroups
|
||||
Retrieves all registered usergroups.
|
||||
|
||||
Return value:
|
||||
Table of CAMI_USERGROUP, indexed by their names.
|
||||
]]
|
||||
function CAMI.GetUsergroups()
|
||||
return usergroups
|
||||
end
|
||||
|
||||
--[[
|
||||
CAMI.GetUsergroup
|
||||
Receives information about a usergroup.
|
||||
|
||||
Return value:
|
||||
CAMI_USERGROUP
|
||||
Returns nil when the usergroup does not exist.
|
||||
]]
|
||||
function CAMI.GetUsergroup(usergroupName)
|
||||
return usergroups[usergroupName]
|
||||
end
|
||||
|
||||
--[[
|
||||
CAMI.UsergroupInherits
|
||||
Returns true when usergroupName1 inherits usergroupName2.
|
||||
Note that usergroupName1 does not need to be a direct child.
|
||||
Every usergroup trivially inherits itself.
|
||||
|
||||
Parameters:
|
||||
usergroupName1
|
||||
string
|
||||
The name of the usergroup that is queried.
|
||||
usergroupName2
|
||||
string
|
||||
The name of the usergroup of which is queried whether usergroupName
|
||||
inherits from.
|
||||
|
||||
Return value:
|
||||
bool
|
||||
Whether usergroupName1 inherits usergroupName2.
|
||||
]]
|
||||
function CAMI.UsergroupInherits(usergroupName1, usergroupName2)
|
||||
repeat
|
||||
if usergroupName1 == usergroupName2 then return true end
|
||||
|
||||
usergroupName1 = usergroups[usergroupName1] and
|
||||
usergroups[usergroupName1].Inherits or
|
||||
usergroupName1
|
||||
until not usergroups[usergroupName1] or
|
||||
usergroups[usergroupName1].Inherits == usergroupName1
|
||||
|
||||
-- One can only be sure the usergroup inherits from user if the
|
||||
-- usergroup isn't registered.
|
||||
return usergroupName1 == usergroupName2 or usergroupName2 == "user"
|
||||
end
|
||||
|
||||
--[[
|
||||
CAMI.InheritanceRoot
|
||||
All usergroups must eventually inherit either user, admin or superadmin.
|
||||
Regardless of what inheritance mechism an admin may or may not have, this
|
||||
always applies.
|
||||
|
||||
This method always returns either user, admin or superadmin, based on what
|
||||
usergroups eventually inherit.
|
||||
|
||||
Parameters:
|
||||
usergroupName
|
||||
string
|
||||
The name of the usergroup of which the root of inheritance is
|
||||
requested
|
||||
|
||||
Return value:
|
||||
string
|
||||
The name of the root usergroup (either user, admin or superadmin)
|
||||
]]
|
||||
function CAMI.InheritanceRoot(usergroupName)
|
||||
if not usergroups[usergroupName] then return end
|
||||
|
||||
local inherits = usergroups[usergroupName].Inherits
|
||||
while inherits ~= usergroups[usergroupName].Inherits do
|
||||
usergroupName = usergroups[usergroupName].Inherits
|
||||
end
|
||||
|
||||
return usergroupName
|
||||
end
|
||||
|
||||
--[[
|
||||
CAMI.RegisterPrivilege
|
||||
Registers a privilege with CAMI.
|
||||
Note: do NOT register all your admin mod's privileges with this function!
|
||||
This function is for third party addons to register privileges
|
||||
with admin mods, not for admin mods sharing the privileges amongst one
|
||||
another.
|
||||
|
||||
Parameters:
|
||||
privilege
|
||||
CAMI_PRIVILEGE
|
||||
See CAMI_PRIVILEGE structure.
|
||||
|
||||
Return value:
|
||||
CAMI_PRIVILEGE
|
||||
The privilege given as argument.
|
||||
]]
|
||||
function CAMI.RegisterPrivilege(privilege)
|
||||
privileges[privilege.Name] = privilege
|
||||
|
||||
hook.Call("CAMI.OnPrivilegeRegistered", nil, privilege)
|
||||
|
||||
return privilege
|
||||
end
|
||||
|
||||
--[[
|
||||
CAMI.UnregisterPrivilege
|
||||
Unregisters a privilege from CAMI. This will call a hook that will notify
|
||||
all other admin mods of the removal.
|
||||
|
||||
Call only when the privilege is to be permanently removed.
|
||||
|
||||
Parameters:
|
||||
privilegeName
|
||||
string
|
||||
The name of the privilege.
|
||||
|
||||
Return value:
|
||||
bool
|
||||
Whether the unregistering succeeded.
|
||||
]]
|
||||
function CAMI.UnregisterPrivilege(privilegeName)
|
||||
if not privileges[privilegeName] then return false end
|
||||
|
||||
local privilege = privileges[privilegeName]
|
||||
privileges[privilegeName] = nil
|
||||
|
||||
hook.Call("CAMI.OnPrivilegeUnregistered", nil, privilege)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--[[
|
||||
CAMI.GetPrivileges
|
||||
Retrieves all registered privileges.
|
||||
|
||||
Return value:
|
||||
Table of CAMI_PRIVILEGE, indexed by their names.
|
||||
]]
|
||||
function CAMI.GetPrivileges()
|
||||
return privileges
|
||||
end
|
||||
|
||||
--[[
|
||||
CAMI.GetPrivilege
|
||||
Receives information about a privilege.
|
||||
|
||||
Return value:
|
||||
CAMI_PRIVILEGE when the privilege exists.
|
||||
nil when the privilege does not exist.
|
||||
]]
|
||||
function CAMI.GetPrivilege(privilegeName)
|
||||
return privileges[privilegeName]
|
||||
end
|
||||
|
||||
--[[
|
||||
CAMI.PlayerHasAccess
|
||||
Queries whether a certain player has the right to perform a certain action.
|
||||
|
||||
Parameters:
|
||||
actorPly
|
||||
Player
|
||||
The player of which is requested whether they have the privilege.
|
||||
privilegeName
|
||||
string
|
||||
The name of the privilege.
|
||||
callback
|
||||
function(bool, string) or nil
|
||||
This function will be called with the answer. The bool signifies the
|
||||
yes or no answer as to whether the player is allowed. The string
|
||||
will optionally give a reason.
|
||||
|
||||
Give an explicit nil here to get an answer immediately
|
||||
Important note: May throw an error when the admin mod doesn't
|
||||
give an answer immediately!
|
||||
targetPly
|
||||
Optional.
|
||||
The player on which the privilege is executed.
|
||||
extraInfoTbl
|
||||
Optional.
|
||||
Table containing extra information.
|
||||
Officially supported members:
|
||||
Fallback
|
||||
string
|
||||
Either of user/admin/superadmin. When no admin mod replies,
|
||||
the decision is based on the admin status of the user.
|
||||
Defaults to admin if not given.
|
||||
IgnoreImmunity
|
||||
bool
|
||||
Ignore any immunity mechanisms an admin mod might have.
|
||||
CommandArguments
|
||||
table
|
||||
Extra arguments that were given to the privilege command.
|
||||
|
||||
Return value:
|
||||
If callback is specified:
|
||||
None
|
||||
Otherwise:
|
||||
hasAccess
|
||||
bool
|
||||
Whether the player has access
|
||||
reason
|
||||
Optional.
|
||||
The reason why a player does or does not have access.
|
||||
]]
|
||||
-- Default access handler
|
||||
local defaultAccessHandler = {["CAMI.PlayerHasAccess"] =
|
||||
function(_, actorPly, privilegeName, callback, _, extraInfoTbl)
|
||||
-- The server always has access in the fallback
|
||||
if not IsValid(actorPly) then return callback(true, "Fallback.") end
|
||||
|
||||
local priv = privileges[privilegeName]
|
||||
|
||||
local fallback = extraInfoTbl and (
|
||||
not extraInfoTbl.Fallback and actorPly:IsAdmin() or
|
||||
extraInfoTbl.Fallback == "user" and true or
|
||||
extraInfoTbl.Fallback == "admin" and actorPly:IsAdmin() or
|
||||
extraInfoTbl.Fallback == "superadmin" and actorPly:IsSuperAdmin())
|
||||
|
||||
|
||||
if not priv then return callback(fallback, "Fallback.") end
|
||||
|
||||
callback(
|
||||
priv.MinAccess == "user" or
|
||||
priv.MinAccess == "admin" and actorPly:IsAdmin() or
|
||||
priv.MinAccess == "superadmin" and actorPly:IsSuperAdmin()
|
||||
, "Fallback.")
|
||||
end,
|
||||
["CAMI.SteamIDHasAccess"] =
|
||||
function(_, _, _, callback)
|
||||
callback(false, "No information available.")
|
||||
end
|
||||
}
|
||||
function CAMI.PlayerHasAccess(actorPly, privilegeName, callback, targetPly,
|
||||
extraInfoTbl)
|
||||
local hasAccess, reason = nil, nil
|
||||
local callback_ = callback or function(hA, r) hasAccess, reason = hA, r end
|
||||
|
||||
hook.Call("CAMI.PlayerHasAccess", defaultAccessHandler, actorPly,
|
||||
privilegeName, callback_, targetPly, extraInfoTbl)
|
||||
|
||||
if callback ~= nil then return end
|
||||
|
||||
if hasAccess == nil then
|
||||
local err = [[The function CAMI.PlayerHasAccess was used to find out
|
||||
whether Player %s has privilege "%s", but an admin mod did not give an
|
||||
immediate answer!]]
|
||||
error(string.format(err,
|
||||
actorPly:IsPlayer() and actorPly:Nick() or tostring(actorPly),
|
||||
privilegeName))
|
||||
end
|
||||
|
||||
return hasAccess, reason
|
||||
end
|
||||
|
||||
--[[
|
||||
CAMI.GetPlayersWithAccess
|
||||
Finds the list of currently joined players who have the right to perform a
|
||||
certain action.
|
||||
NOTE: this function will NOT return an immediate result!
|
||||
The result is in the callback!
|
||||
|
||||
Parameters:
|
||||
privilegeName
|
||||
string
|
||||
The name of the privilege.
|
||||
callback
|
||||
function(players)
|
||||
This function will be called with the list of players with access.
|
||||
targetPly
|
||||
Optional.
|
||||
The player on which the privilege is executed.
|
||||
extraInfoTbl
|
||||
Optional.
|
||||
Table containing extra information.
|
||||
Officially supported members:
|
||||
Fallback
|
||||
string
|
||||
Either of user/admin/superadmin. When no admin mod replies,
|
||||
the decision is based on the admin status of the user.
|
||||
Defaults to admin if not given.
|
||||
IgnoreImmunity
|
||||
bool
|
||||
Ignore any immunity mechanisms an admin mod might have.
|
||||
CommandArguments
|
||||
table
|
||||
Extra arguments that were given to the privilege command.
|
||||
]]
|
||||
function CAMI.GetPlayersWithAccess(privilegeName, callback, targetPly,
|
||||
extraInfoTbl)
|
||||
local allowedPlys = {}
|
||||
local allPlys = player.GetAll()
|
||||
local countdown = #allPlys
|
||||
|
||||
local function onResult(ply, hasAccess, _)
|
||||
countdown = countdown - 1
|
||||
|
||||
if hasAccess then table.insert(allowedPlys, ply) end
|
||||
if countdown == 0 then callback(allowedPlys) end
|
||||
end
|
||||
|
||||
for _, ply in ipairs(allPlys) do
|
||||
CAMI.PlayerHasAccess(ply, privilegeName,
|
||||
function(...) onResult(ply, ...) end,
|
||||
targetPly, extraInfoTbl)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
CAMI.SteamIDHasAccess
|
||||
Queries whether a player with a steam ID has the right to perform a certain
|
||||
action.
|
||||
Note: the player does not need to be in the server for this to
|
||||
work.
|
||||
|
||||
Note: this function does NOT return an immediate result!
|
||||
The result is in the callback!
|
||||
|
||||
Parameters:
|
||||
actorSteam
|
||||
Player
|
||||
The SteamID of the player of which is requested whether they have
|
||||
the privilege.
|
||||
privilegeName
|
||||
string
|
||||
The name of the privilege.
|
||||
callback
|
||||
function(bool, string)
|
||||
This function will be called with the answer. The bool signifies the
|
||||
yes or no answer as to whether the player is allowed. The string
|
||||
will optionally give a reason.
|
||||
targetSteam
|
||||
Optional.
|
||||
The SteamID of the player on which the privilege is executed.
|
||||
extraInfoTbl
|
||||
Optional.
|
||||
Table containing extra information.
|
||||
Officially supported members:
|
||||
IgnoreImmunity
|
||||
bool
|
||||
Ignore any immunity mechanisms an admin mod might have.
|
||||
CommandArguments
|
||||
table
|
||||
Extra arguments that were given to the privilege command.
|
||||
|
||||
Return value:
|
||||
None, the answer is given in the callback function in order to allow
|
||||
for the admin mod to perform e.g. a database lookup.
|
||||
]]
|
||||
function CAMI.SteamIDHasAccess(actorSteam, privilegeName, callback,
|
||||
targetSteam, extraInfoTbl)
|
||||
hook.Call("CAMI.SteamIDHasAccess", defaultAccessHandler, actorSteam,
|
||||
privilegeName, callback, targetSteam, extraInfoTbl)
|
||||
end
|
||||
|
||||
--[[
|
||||
CAMI.SignalUserGroupChanged
|
||||
Signify that your admin mod has changed the usergroup of a player. This
|
||||
function communicates to other admin mods what it thinks the usergroup
|
||||
of a player should be.
|
||||
|
||||
Listen to the hook to receive the usergroup changes of other admin mods.
|
||||
|
||||
Parameters:
|
||||
ply
|
||||
Player
|
||||
The player for which the usergroup is changed
|
||||
old
|
||||
string
|
||||
The previous usergroup of the player.
|
||||
new
|
||||
string
|
||||
The new usergroup of the player.
|
||||
source
|
||||
any
|
||||
Identifier for your own admin mod. Can be anything.
|
||||
]]
|
||||
function CAMI.SignalUserGroupChanged(ply, old, new, source)
|
||||
hook.Call("CAMI.PlayerUsergroupChanged", nil, ply, old, new, source)
|
||||
end
|
||||
|
||||
--[[
|
||||
CAMI.SignalSteamIDUserGroupChanged
|
||||
Signify that your admin mod has changed the usergroup of a disconnected
|
||||
player. This communicates to other admin mods what it thinks the usergroup
|
||||
of a player should be.
|
||||
|
||||
Listen to the hook to receive the usergroup changes of other admin mods.
|
||||
|
||||
Parameters:
|
||||
ply
|
||||
string
|
||||
The steam ID of the player for which the usergroup is changed
|
||||
old
|
||||
string
|
||||
The previous usergroup of the player.
|
||||
new
|
||||
string
|
||||
The new usergroup of the player.
|
||||
source
|
||||
any
|
||||
Identifier for your own admin mod. Can be anything.
|
||||
]]
|
||||
function CAMI.SignalSteamIDUserGroupChanged(steamId, old, new, source)
|
||||
hook.Call("CAMI.SteamIDUsergroupChanged", nil, steamId, old, new, source)
|
||||
end
|
||||
791
gamemodes/helix/gamemode/core/libs/thirdparty/sh_date.lua
vendored
Normal file
791
gamemodes/helix/gamemode/core/libs/thirdparty/sh_date.lua
vendored
Normal file
@@ -0,0 +1,791 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
---------------------------------------------------------------------------------------
|
||||
-- Module for date and time calculations
|
||||
--
|
||||
-- Version 2.1.1
|
||||
-- Copyright (C) 2006, by Jas Latrix (jastejada@yahoo.com)
|
||||
-- Copyright (C) 2013-2014, by Thijs Schreijer
|
||||
-- Licensed under MIT, http://opensource.org/licenses/MIT
|
||||
-- https://github.com/Tieske/date
|
||||
|
||||
--[[
|
||||
The MIT License (MIT) http://opensource.org/licenses/MIT
|
||||
|
||||
Copyright (c) 2013-2017 Thijs Schreijer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
]]
|
||||
|
||||
--[[ CONSTANTS ]]--
|
||||
local HOURPERDAY = 24
|
||||
local MINPERHOUR = 60
|
||||
local MINPERDAY = 1440 -- 24*60
|
||||
local SECPERMIN = 60
|
||||
local SECPERHOUR = 3600 -- 60*60
|
||||
local SECPERDAY = 86400 -- 24*60*60
|
||||
local TICKSPERSEC = 1000000
|
||||
local TICKSPERDAY = 86400000000
|
||||
local TICKSPERHOUR = 3600000000
|
||||
local TICKSPERMIN = 60000000
|
||||
local DAYNUM_MAX = 365242500 -- Sat Jan 01 1000000 00:00:00
|
||||
local DAYNUM_MIN = -365242500 -- Mon Jan 01 1000000 BCE 00:00:00
|
||||
local DAYNUM_DEF = 0 -- Mon Jan 01 0001 00:00:00
|
||||
local _;
|
||||
--[[ LOCAL ARE FASTER ]]--
|
||||
local type = type
|
||||
local pairs = pairs
|
||||
local error = error
|
||||
local assert = assert
|
||||
local tonumber = tonumber
|
||||
local tostring = tostring
|
||||
local string = string
|
||||
local math = math
|
||||
local os = os
|
||||
local unpack = unpack or table.unpack
|
||||
local pack = table.pack or function(...) return { n = select('#', ...), ... } end
|
||||
local setmetatable = setmetatable
|
||||
local getmetatable = getmetatable
|
||||
--[[ EXTRA FUNCTIONS ]]--
|
||||
local fmt = string.format
|
||||
local lwr = string.lower
|
||||
local upr = string.upper
|
||||
local rep = string.rep
|
||||
local len = string.len
|
||||
local sub = string.sub
|
||||
local gsub = string.gsub
|
||||
local gmatch = string.gmatch or string.gfind
|
||||
local find = string.find
|
||||
local ostime = os.time
|
||||
local osdate = os.date
|
||||
local floor = math.floor
|
||||
local ceil = math.ceil
|
||||
local abs = math.abs
|
||||
-- removes the decimal part of a number
|
||||
local function fix(n) n = tonumber(n) return n and ((n > 0 and floor or ceil)(n)) end
|
||||
-- returns the modulo n % d;
|
||||
local function mod(n,d) return n - d*floor(n/d) end
|
||||
-- rounds a number;
|
||||
local function round(n, d) d=d^10 return floor((n*d)+.5)/d end
|
||||
-- rounds a number to whole;
|
||||
local function whole(n)return floor(n+.5)end
|
||||
-- is `str` in string list `tbl`, `ml` is the minimun len
|
||||
local function inlist(str, tbl, ml, tn)
|
||||
local sl = len(str)
|
||||
if sl < (ml or 0) then return nil end
|
||||
str = lwr(str)
|
||||
for k, v in pairs(tbl) do
|
||||
if str == lwr(sub(v, 1, sl)) then
|
||||
if tn then tn[0] = k end
|
||||
return k
|
||||
end
|
||||
end
|
||||
end
|
||||
local function fnil() end
|
||||
local function fret(x)return x;end
|
||||
--[[ DATE FUNCTIONS ]]--
|
||||
local DATE_EPOCH -- to be set later
|
||||
local sl_weekdays = {
|
||||
[0]="Sunday",[1]="Monday",[2]="Tuesday",[3]="Wednesday",[4]="Thursday",[5]="Friday",[6]="Saturday",
|
||||
[7]="Sun",[8]="Mon",[9]="Tue",[10]="Wed",[11]="Thu",[12]="Fri",[13]="Sat",
|
||||
}
|
||||
local sl_meridian = {[-1]="AM", [1]="PM"}
|
||||
local sl_months = {
|
||||
[00]="January", [01]="February", [02]="March",
|
||||
[03]="April", [04]="May", [05]="June",
|
||||
[06]="July", [07]="August", [08]="September",
|
||||
[09]="October", [10]="November", [11]="December",
|
||||
[12]="Jan", [13]="Feb", [14]="Mar",
|
||||
[15]="Apr", [16]="May", [17]="Jun",
|
||||
[18]="Jul", [19]="Aug", [20]="Sep",
|
||||
[21]="Oct", [22]="Nov", [23]="Dec",
|
||||
}
|
||||
-- added the '.2' to avoid collision, use `fix` to remove
|
||||
local sl_timezone = {
|
||||
[000]="utc", [0.2]="gmt",
|
||||
[300]="est", [240]="edt",
|
||||
[360]="cst", [300.2]="cdt",
|
||||
[420]="mst", [360.2]="mdt",
|
||||
[480]="pst", [420.2]="pdt",
|
||||
}
|
||||
-- set the day fraction resolution
|
||||
local function setticks(t)
|
||||
TICKSPERSEC = t;
|
||||
TICKSPERDAY = SECPERDAY*TICKSPERSEC
|
||||
TICKSPERHOUR= SECPERHOUR*TICKSPERSEC
|
||||
TICKSPERMIN = SECPERMIN*TICKSPERSEC
|
||||
end
|
||||
-- is year y leap year?
|
||||
local function isleapyear(y) -- y must be int!
|
||||
return (mod(y, 4) == 0 and (mod(y, 100) ~= 0 or mod(y, 400) == 0))
|
||||
end
|
||||
-- day since year 0
|
||||
local function dayfromyear(y) -- y must be int!
|
||||
return 365*y + floor(y/4) - floor(y/100) + floor(y/400)
|
||||
end
|
||||
-- day number from date, month is zero base
|
||||
local function makedaynum(y, m, d)
|
||||
local mm = mod(mod(m,12) + 10, 12)
|
||||
return dayfromyear(y + floor(m/12) - floor(mm/10)) + floor((mm*306 + 5)/10) + d - 307
|
||||
--local yy = y + floor(m/12) - floor(mm/10)
|
||||
--return dayfromyear(yy) + floor((mm*306 + 5)/10) + (d - 1)
|
||||
end
|
||||
-- date from day number, month is zero base
|
||||
local function breakdaynum(g)
|
||||
local g = g + 306
|
||||
local y = floor((10000*g + 14780)/3652425)
|
||||
local d = g - dayfromyear(y)
|
||||
if d < 0 then y = y - 1; d = g - dayfromyear(y) end
|
||||
local mi = floor((100*d + 52)/3060)
|
||||
return (floor((mi + 2)/12) + y), mod(mi + 2,12), (d - floor((mi*306 + 5)/10) + 1)
|
||||
end
|
||||
--[[ for floats or int32 Lua Number data type
|
||||
local function breakdaynum2(g)
|
||||
local g, n = g + 306;
|
||||
local n400 = floor(g/DI400Y);n = mod(g,DI400Y);
|
||||
local n100 = floor(n/DI100Y);n = mod(n,DI100Y);
|
||||
local n004 = floor(n/DI4Y); n = mod(n,DI4Y);
|
||||
local n001 = floor(n/365); n = mod(n,365);
|
||||
local y = (n400*400) + (n100*100) + (n004*4) + n001 - ((n001 == 4 or n100 == 4) and 1 or 0)
|
||||
local d = g - dayfromyear(y)
|
||||
local mi = floor((100*d + 52)/3060)
|
||||
return (floor((mi + 2)/12) + y), mod(mi + 2,12), (d - floor((mi*306 + 5)/10) + 1)
|
||||
end
|
||||
]]
|
||||
-- day fraction from time
|
||||
local function makedayfrc(h,r,s,t)
|
||||
return ((h*60 + r)*60 + s)*TICKSPERSEC + t
|
||||
end
|
||||
-- time from day fraction
|
||||
local function breakdayfrc(df)
|
||||
return
|
||||
mod(floor(df/TICKSPERHOUR),HOURPERDAY),
|
||||
mod(floor(df/TICKSPERMIN ),MINPERHOUR),
|
||||
mod(floor(df/TICKSPERSEC ),SECPERMIN),
|
||||
mod(df,TICKSPERSEC)
|
||||
end
|
||||
-- weekday sunday = 0, monday = 1 ...
|
||||
local function weekday(dn) return mod(dn + 1, 7) end
|
||||
-- yearday 0 based ...
|
||||
local function yearday(dn)
|
||||
return dn - dayfromyear((breakdaynum(dn))-1)
|
||||
end
|
||||
-- parse v as a month
|
||||
local function getmontharg(v)
|
||||
local m = tonumber(v);
|
||||
return (m and fix(m - 1)) or inlist(tostring(v) or "", sl_months, 2)
|
||||
end
|
||||
-- get daynum of isoweek one of year y
|
||||
local function isow1(y)
|
||||
local f = makedaynum(y, 0, 4) -- get the date for the 4-Jan of year `y`
|
||||
local d = weekday(f)
|
||||
d = d == 0 and 7 or d -- get the ISO day number, 1 == Monday, 7 == Sunday
|
||||
return f + (1 - d)
|
||||
end
|
||||
local function isowy(dn)
|
||||
local w1;
|
||||
local y = (breakdaynum(dn))
|
||||
if dn >= makedaynum(y, 11, 29) then
|
||||
w1 = isow1(y + 1);
|
||||
if dn < w1 then
|
||||
w1 = isow1(y);
|
||||
else
|
||||
y = y + 1;
|
||||
end
|
||||
else
|
||||
w1 = isow1(y);
|
||||
if dn < w1 then
|
||||
w1 = isow1(y-1)
|
||||
y = y - 1
|
||||
end
|
||||
end
|
||||
return floor((dn-w1)/7)+1, y
|
||||
end
|
||||
local function isoy(dn)
|
||||
local y = (breakdaynum(dn))
|
||||
return y + (((dn >= makedaynum(y, 11, 29)) and (dn >= isow1(y + 1))) and 1 or (dn < isow1(y) and -1 or 0))
|
||||
end
|
||||
local function makedaynum_isoywd(y,w,d)
|
||||
return isow1(y) + 7*w + d - 8 -- simplified: isow1(y) + ((w-1)*7) + (d-1)
|
||||
end
|
||||
--[[ THE DATE MODULE ]]--
|
||||
local fmtstr = "%x %X";
|
||||
--#if not DATE_OBJECT_AFX then
|
||||
local date = {}
|
||||
setmetatable(date, date)
|
||||
-- Version: VMMMRRRR; V-Major, M-Minor, R-Revision; e.g. 5.45.321 == 50450321
|
||||
date.version = 20010001 -- 2.1.1
|
||||
--#end -- not DATE_OBJECT_AFX
|
||||
--[[ THE DATE OBJECT ]]--
|
||||
local dobj = {}
|
||||
dobj.__index = dobj
|
||||
dobj.__metatable = dobj
|
||||
-- shout invalid arg
|
||||
local function date_error_arg() return error("invalid argument(s)",0) end
|
||||
-- create new date object
|
||||
local function date_new(dn, df)
|
||||
return setmetatable({daynum=dn, dayfrc=df}, dobj)
|
||||
end
|
||||
-- is `v` a date object?
|
||||
local function date_isdobj(v)
|
||||
return (istable(v) and getmetatable(v) == dobj) and v
|
||||
end
|
||||
|
||||
--#if not NO_LOCAL_TIME_SUPPORT then
|
||||
-- magic year table
|
||||
local date_epoch, yt;
|
||||
local function getequivyear(y)
|
||||
assert(not yt)
|
||||
yt = {}
|
||||
local de, dw, dy = date_epoch:copy()
|
||||
for i = 0, 3000 do
|
||||
de:setyear(de:getyear() + 1, 1, 1)
|
||||
dy = de:getyear()
|
||||
dw = de:getweekday() * (isleapyear(dy) and -1 or 1)
|
||||
if not yt[dw] then yt[dw] = dy end --print(de)
|
||||
if yt[1] and yt[2] and yt[3] and yt[4] and yt[5] and yt[6] and yt[7] and yt[-1] and yt[-2] and yt[-3] and yt[-4] and yt[-5] and yt[-6] and yt[-7] then
|
||||
getequivyear = function(y) return yt[ (weekday(makedaynum(y, 0, 1)) + 1) * (isleapyear(y) and -1 or 1) ] end
|
||||
return getequivyear(y)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- TimeValue from daynum and dayfrc
|
||||
local function dvtotv(dn, df)
|
||||
return fix(dn - DATE_EPOCH) * SECPERDAY + (df/1000)
|
||||
end
|
||||
-- TimeValue from date and time
|
||||
local function totv(y,m,d,h,r,s)
|
||||
return (makedaynum(y, m, d) - DATE_EPOCH) * SECPERDAY + ((h*60 + r)*60 + s)
|
||||
end
|
||||
-- TimeValue from TimeTable
|
||||
local function tmtotv(tm)
|
||||
return tm and totv(tm.year, tm.month - 1, tm.day, tm.hour, tm.min, tm.sec)
|
||||
end
|
||||
-- Returns the bias in seconds of utc time daynum and dayfrc
|
||||
local function getbiasutc2(self)
|
||||
local y,m,d = breakdaynum(self.daynum)
|
||||
local h,r,s = breakdayfrc(self.dayfrc)
|
||||
local tvu = totv(y,m,d,h,r,s) -- get the utc TimeValue of date and time
|
||||
local tml = osdate("*t", tvu) -- get the local TimeTable of tvu
|
||||
if (not tml) or (tml.year > (y+1) or tml.year < (y-1)) then -- failed try the magic
|
||||
y = getequivyear(y)
|
||||
tvu = totv(y,m,d,h,r,s)
|
||||
tml = osdate("*t", tvu)
|
||||
end
|
||||
local tvl = tmtotv(tml)
|
||||
if tvu and tvl then
|
||||
return tvu - tvl, tvu, tvl
|
||||
else
|
||||
return error("failed to get bias from utc time")
|
||||
end
|
||||
end
|
||||
-- Returns the bias in seconds of local time daynum and dayfrc
|
||||
local function getbiasloc2(daynum, dayfrc)
|
||||
local tvu
|
||||
-- extract date and time
|
||||
local y,m,d = breakdaynum(daynum)
|
||||
local h,r,s = breakdayfrc(dayfrc)
|
||||
-- get equivalent TimeTable
|
||||
local tml = {year=y, month=m+1, day=d, hour=h, min=r, sec=s}
|
||||
-- get equivalent TimeValue
|
||||
local tvl = tmtotv(tml)
|
||||
|
||||
local function chkutc()
|
||||
tml.isdst = nil; local tvug = ostime(tml) if tvug and (tvl == tmtotv(osdate("*t", tvug))) then tvu = tvug return end
|
||||
tml.isdst = true; local tvud = ostime(tml) if tvud and (tvl == tmtotv(osdate("*t", tvud))) then tvu = tvud return end
|
||||
tvu = tvud or tvug
|
||||
end
|
||||
chkutc()
|
||||
if not tvu then
|
||||
tml.year = getequivyear(y)
|
||||
tvl = tmtotv(tml)
|
||||
chkutc()
|
||||
end
|
||||
return ((tvu and tvl) and (tvu - tvl)) or error("failed to get bias from local time"), tvu, tvl
|
||||
end
|
||||
--#end -- not NO_LOCAL_TIME_SUPPORT
|
||||
|
||||
--#if not DATE_OBJECT_AFX then
|
||||
-- the date parser
|
||||
local strwalker = {} -- ^Lua regular expression is not as powerful as Perl$
|
||||
strwalker.__index = strwalker
|
||||
local function newstrwalker(s)return setmetatable({s=s, i=1, e=1, c=len(s)}, strwalker) end
|
||||
function strwalker:aimchr() return "\n" .. self.s .. "\n" .. rep(".",self.e-1) .. "^" end
|
||||
function strwalker:finish() return self.i > self.c end
|
||||
function strwalker:back() self.i = self.e return self end
|
||||
function strwalker:restart() self.i, self.e = 1, 1 return self end
|
||||
function strwalker:match(s) return (find(self.s, s, self.i)) end
|
||||
function strwalker:__call(s, f)-- print("strwalker:__call "..s..self:aimchr())
|
||||
local is, ie; is, ie, self[1], self[2], self[3], self[4], self[5] = find(self.s, s, self.i)
|
||||
if is then self.e, self.i = self.i, 1+ie; if f then f(unpack(self)) end return self end
|
||||
end
|
||||
local function date_parse(str)
|
||||
local y,m,d, h,r,s, z, w,u, j, e, k, x,v,c, chkfin, dn,df;
|
||||
local sw = newstrwalker(gsub(gsub(str, "(%b())", ""),"^(%s*)","")) -- remove comment, trim leading space
|
||||
--local function error_out() print(y,m,d,h,r,s) end
|
||||
local function error_dup(q) --[[error_out()]] error("duplicate value: " .. (q or "") .. sw:aimchr()) end
|
||||
local function error_syn(q) --[[error_out()]] error("syntax error: " .. (q or "") .. sw:aimchr()) end
|
||||
local function error_inv(q) --[[error_out()]] error("invalid date: " .. (q or "") .. sw:aimchr()) end
|
||||
local function sety(q) y = y and error_dup() or tonumber(q); end
|
||||
local function setm(q) m = (m or w or j) and error_dup(m or w or j) or tonumber(q) end
|
||||
local function setd(q) d = d and error_dup() or tonumber(q) end
|
||||
local function seth(q) h = h and error_dup() or tonumber(q) end
|
||||
local function setr(q) r = r and error_dup() or tonumber(q) end
|
||||
local function sets(q) s = s and error_dup() or tonumber(q) end
|
||||
local function adds(q) s = s + tonumber(q) end
|
||||
local function setj(q) j = (m or w or j) and error_dup() or tonumber(q); end
|
||||
local function setz(q) z = (z ~= 0 and z) and error_dup() or q end
|
||||
local function setzn(zs,zn) zn = tonumber(zn); setz( ((zn<24) and (zn*60) or (mod(zn,100) + floor(zn/100) * 60))*( zs=='+' and -1 or 1) ) end
|
||||
local function setzc(zs,zh,zm) setz( ((tonumber(zh)*60) + tonumber(zm))*( zs=='+' and -1 or 1) ) end
|
||||
|
||||
if not (sw("^(%d%d%d%d)",sety) and (sw("^(%-?)(%d%d)%1(%d%d)",function(_,a,b) setm(tonumber(a)); setd(tonumber(b)) end) or sw("^(%-?)[Ww](%d%d)%1(%d?)",function(_,a,b) w, u = tonumber(a), tonumber(b or 1) end) or sw("^%-?(%d%d%d)",setj) or sw("^%-?(%d%d)",function(a) setm(a);setd(1) end))
|
||||
and ((sw("^%s*[Tt]?(%d%d):?",seth) and sw("^(%d%d):?",setr) and sw("^(%d%d)",sets) and sw("^(%.%d+)",adds))
|
||||
or sw:finish() or (sw"^%s*$" or sw"^%s*[Zz]%s*$" or sw("^%s-([%+%-])(%d%d):?(%d%d)%s*$",setzc) or sw("^%s*([%+%-])(%d%d)%s*$",setzn))
|
||||
) )
|
||||
then --print(y,m,d,h,r,s,z,w,u,j)
|
||||
sw:restart(); y,m,d,h,r,s,z,w,u,j = nil;
|
||||
repeat -- print(sw:aimchr())
|
||||
if sw("^[tT:]?%s*(%d%d?):",seth) then --print("$Time")
|
||||
_ = sw("^%s*(%d%d?)",setr) and sw("^%s*:%s*(%d%d?)",sets) and sw("^(%.%d+)",adds)
|
||||
elseif sw("^(%d+)[/\\%s,-]?%s*") then --print("$Digits")
|
||||
x, c = tonumber(sw[1]), len(sw[1])
|
||||
if (x >= 70) or (m and d and (not y)) or (c > 3) then
|
||||
sety( x + ((x >= 100 or c>3)and 0 or 1900) )
|
||||
else
|
||||
if m then setd(x) else m = x end
|
||||
end
|
||||
elseif sw("^(%a+)[/\\%s,-]?%s*") then --print("$Words")
|
||||
x = sw[1]
|
||||
if inlist(x, sl_months, 2, sw) then
|
||||
if m and (not d) and (not y) then d, m = m, false end
|
||||
setm(mod(sw[0],12)+1)
|
||||
elseif inlist(x, sl_timezone, 2, sw) then
|
||||
c = fix(sw[0]) -- ignore gmt and utc
|
||||
if c ~= 0 then setz(c, x) end
|
||||
elseif inlist(x, sl_weekdays, 2, sw) then
|
||||
k = sw[0]
|
||||
else
|
||||
sw:back()
|
||||
-- am pm bce ad ce bc
|
||||
if sw("^([bB])%s*(%.?)%s*[Cc]%s*(%2)%s*[Ee]%s*(%2)%s*") or sw("^([bB])%s*(%.?)%s*[Cc]%s*(%2)%s*") then
|
||||
e = e and error_dup() or -1
|
||||
elseif sw("^([aA])%s*(%.?)%s*[Dd]%s*(%2)%s*") or sw("^([cC])%s*(%.?)%s*[Ee]%s*(%2)%s*") then
|
||||
e = e and error_dup() or 1
|
||||
elseif sw("^([PApa])%s*(%.?)%s*[Mm]?%s*(%2)%s*") then
|
||||
x = lwr(sw[1]) -- there should be hour and it must be correct
|
||||
if (not h) or (h > 12) or (h < 0) then return error_inv() end
|
||||
if x == 'a' and h == 12 then h = 0 end -- am
|
||||
if x == 'p' and h ~= 12 then h = h + 12 end -- pm
|
||||
else error_syn() end
|
||||
end
|
||||
elseif not(sw("^([+-])(%d%d?):(%d%d)",setzc) or sw("^([+-])(%d+)",setzn) or sw("^[Zz]%s*$")) then -- sw{"([+-])",{"(%d%d?):(%d%d)","(%d+)"}}
|
||||
error_syn("?")
|
||||
end
|
||||
sw("^%s*") until sw:finish()
|
||||
--else print("$Iso(Date|Time|Zone)")
|
||||
end
|
||||
-- if date is given, it must be complete year, month & day
|
||||
if (not y and not h) or ((m and not d) or (d and not m)) or ((m and w) or (m and j) or (j and w)) then return error_inv("!") end
|
||||
-- fix month
|
||||
if m then m = m - 1 end
|
||||
-- fix year if we are on BCE
|
||||
if e and e < 0 and y > 0 then y = 1 - y end
|
||||
-- create date object
|
||||
dn = (y and ((w and makedaynum_isoywd(y,w,u)) or (j and makedaynum(y, 0, j)) or makedaynum(y, m, d))) or DAYNUM_DEF
|
||||
df = makedayfrc(h or 0, r or 0, s or 0, 0) + ((z or 0)*TICKSPERMIN)
|
||||
--print("Zone",h,r,s,z,m,d,y,df)
|
||||
return date_new(dn, df) -- no need to :normalize();
|
||||
end
|
||||
local function date_fromtable(v)
|
||||
local y, m, d = fix(v.year), getmontharg(v.month), fix(v.day)
|
||||
local h, r, s, t = tonumber(v.hour), tonumber(v.min), tonumber(v.sec), tonumber(v.ticks)
|
||||
-- atleast there is time or complete date
|
||||
if (y or m or d) and (not(y and m and d)) then return error("incomplete table") end
|
||||
return (y or h or r or s or t) and date_new(y and makedaynum(y, m, d) or DAYNUM_DEF, makedayfrc(h or 0, r or 0, s or 0, t or 0))
|
||||
end
|
||||
local tmap = {
|
||||
['number'] = function(v) return date_epoch:copy():addseconds(v) end,
|
||||
['string'] = function(v) return date_parse(v) end,
|
||||
['boolean']= function(v) return date_fromtable(osdate(v and "!*t" or "*t")) end,
|
||||
['table'] = function(v) local ref = getmetatable(v) == dobj; return ref and v or date_fromtable(v), ref end
|
||||
}
|
||||
local function date_getdobj(v)
|
||||
local o, r = (tmap[type(v)] or fnil)(v);
|
||||
return (o and o:normalize() or error"invalid date time value"), r -- if r is true then o is a reference to a date obj
|
||||
end
|
||||
--#end -- not DATE_OBJECT_AFX
|
||||
local function date_from(...)
|
||||
local arg = pack(...)
|
||||
local y, m, d = fix(arg[1]), getmontharg(arg[2]), fix(arg[3])
|
||||
local h, r, s, t = tonumber(arg[4] or 0), tonumber(arg[5] or 0), tonumber(arg[6] or 0), tonumber(arg[7] or 0)
|
||||
if y and m and d and h and r and s and t then
|
||||
return date_new(makedaynum(y, m, d), makedayfrc(h, r, s, t)):normalize()
|
||||
else
|
||||
return date_error_arg()
|
||||
end
|
||||
end
|
||||
|
||||
--[[ THE DATE OBJECT METHODS ]]--
|
||||
function dobj:normalize()
|
||||
local dn, df = fix(self.daynum), self.dayfrc
|
||||
self.daynum, self.dayfrc = dn + floor(df/TICKSPERDAY), mod(df, TICKSPERDAY)
|
||||
return (dn >= DAYNUM_MIN and dn <= DAYNUM_MAX) and self or error("date beyond imposed limits:"..self)
|
||||
end
|
||||
|
||||
function dobj:getdate() local y, m, d = breakdaynum(self.daynum) return y, m+1, d end
|
||||
function dobj:gettime() return breakdayfrc(self.dayfrc) end
|
||||
|
||||
function dobj:getclockhour() local h = self:gethours() return h>12 and mod(h,12) or (h==0 and 12 or h) end
|
||||
|
||||
function dobj:getyearday() return yearday(self.daynum) + 1 end
|
||||
function dobj:getweekday() return weekday(self.daynum) + 1 end -- in lua weekday is sunday = 1, monday = 2 ...
|
||||
|
||||
function dobj:getyear() local r,_,_ = breakdaynum(self.daynum) return r end
|
||||
function dobj:getmonth() local _,r,_ = breakdaynum(self.daynum) return r+1 end-- in lua month is 1 base
|
||||
function dobj:getday() local _,_,r = breakdaynum(self.daynum) return r end
|
||||
function dobj:gethours() return mod(floor(self.dayfrc/TICKSPERHOUR),HOURPERDAY) end
|
||||
function dobj:getminutes() return mod(floor(self.dayfrc/TICKSPERMIN), MINPERHOUR) end
|
||||
function dobj:getseconds() return mod(floor(self.dayfrc/TICKSPERSEC ),SECPERMIN) end
|
||||
function dobj:getfracsec() return mod(floor(self.dayfrc/TICKSPERSEC ),SECPERMIN)+(mod(self.dayfrc,TICKSPERSEC)/TICKSPERSEC) end
|
||||
function dobj:getticks(u) local x = mod(self.dayfrc,TICKSPERSEC) return u and ((x*u)/TICKSPERSEC) or x end
|
||||
|
||||
function dobj:getweeknumber(wdb)
|
||||
local wd, yd = weekday(self.daynum), yearday(self.daynum)
|
||||
if wdb then
|
||||
wdb = tonumber(wdb)
|
||||
if wdb then
|
||||
wd = mod(wd-(wdb-1),7)-- shift the week day base
|
||||
else
|
||||
return date_error_arg()
|
||||
end
|
||||
end
|
||||
return (yd < wd and 0) or (floor(yd/7) + ((mod(yd, 7)>=wd) and 1 or 0))
|
||||
end
|
||||
|
||||
function dobj:getisoweekday() return mod(weekday(self.daynum)-1,7)+1 end -- sunday = 7, monday = 1 ...
|
||||
function dobj:getisoweeknumber() return (isowy(self.daynum)) end
|
||||
function dobj:getisoyear() return isoy(self.daynum) end
|
||||
function dobj:getisodate()
|
||||
local w, y = isowy(self.daynum)
|
||||
return y, w, self:getisoweekday()
|
||||
end
|
||||
function dobj:setisoyear(y, w, d)
|
||||
local cy, cw, cd = self:getisodate()
|
||||
if y then cy = fix(tonumber(y))end
|
||||
if w then cw = fix(tonumber(w))end
|
||||
if d then cd = fix(tonumber(d))end
|
||||
if cy and cw and cd then
|
||||
self.daynum = makedaynum_isoywd(cy, cw, cd)
|
||||
return self:normalize()
|
||||
else
|
||||
return date_error_arg()
|
||||
end
|
||||
end
|
||||
|
||||
function dobj:setisoweekday(d) return self:setisoyear(nil, nil, d) end
|
||||
function dobj:setisoweeknumber(w,d) return self:setisoyear(nil, w, d) end
|
||||
|
||||
function dobj:setyear(y, m, d)
|
||||
local cy, cm, cd = breakdaynum(self.daynum)
|
||||
if y then cy = fix(tonumber(y))end
|
||||
if m then cm = getmontharg(m) end
|
||||
if d then cd = fix(tonumber(d))end
|
||||
if cy and cm and cd then
|
||||
self.daynum = makedaynum(cy, cm, cd)
|
||||
return self:normalize()
|
||||
else
|
||||
return date_error_arg()
|
||||
end
|
||||
end
|
||||
|
||||
function dobj:setmonth(m, d)return self:setyear(nil, m, d) end
|
||||
function dobj:setday(d) return self:setyear(nil, nil, d) end
|
||||
|
||||
function dobj:sethours(h, m, s, t)
|
||||
local ch,cm,cs,ck = breakdayfrc(self.dayfrc)
|
||||
ch, cm, cs, ck = tonumber(h or ch), tonumber(m or cm), tonumber(s or cs), tonumber(t or ck)
|
||||
if ch and cm and cs and ck then
|
||||
self.dayfrc = makedayfrc(ch, cm, cs, ck)
|
||||
return self:normalize()
|
||||
else
|
||||
return date_error_arg()
|
||||
end
|
||||
end
|
||||
|
||||
function dobj:setminutes(m,s,t) return self:sethours(nil, m, s, t) end
|
||||
function dobj:setseconds(s, t) return self:sethours(nil, nil, s, t) end
|
||||
function dobj:setticks(t) return self:sethours(nil, nil, nil, t) end
|
||||
|
||||
function dobj:spanticks() return (self.daynum*TICKSPERDAY + self.dayfrc) end
|
||||
function dobj:spanseconds() return (self.daynum*TICKSPERDAY + self.dayfrc)/TICKSPERSEC end
|
||||
function dobj:spanminutes() return (self.daynum*TICKSPERDAY + self.dayfrc)/TICKSPERMIN end
|
||||
function dobj:spanhours() return (self.daynum*TICKSPERDAY + self.dayfrc)/TICKSPERHOUR end
|
||||
function dobj:spandays() return (self.daynum*TICKSPERDAY + self.dayfrc)/TICKSPERDAY end
|
||||
|
||||
function dobj:addyears(y, m, d)
|
||||
local cy, cm, cd = breakdaynum(self.daynum)
|
||||
if y then y = fix(tonumber(y))else y = 0 end
|
||||
if m then m = fix(tonumber(m))else m = 0 end
|
||||
if d then d = fix(tonumber(d))else d = 0 end
|
||||
if y and m and d then
|
||||
self.daynum = makedaynum(cy+y, cm+m, cd+d)
|
||||
return self:normalize()
|
||||
else
|
||||
return date_error_arg()
|
||||
end
|
||||
end
|
||||
|
||||
function dobj:addmonths(m, d)
|
||||
return self:addyears(nil, m, d)
|
||||
end
|
||||
|
||||
local function dobj_adddayfrc(self,n,pt,pd)
|
||||
n = tonumber(n)
|
||||
if n then
|
||||
local x = floor(n/pd);
|
||||
self.daynum = self.daynum + x;
|
||||
self.dayfrc = self.dayfrc + (n-x*pd)*pt;
|
||||
return self:normalize()
|
||||
else
|
||||
return date_error_arg()
|
||||
end
|
||||
end
|
||||
function dobj:adddays(n) return dobj_adddayfrc(self,n,TICKSPERDAY,1) end
|
||||
function dobj:addhours(n) return dobj_adddayfrc(self,n,TICKSPERHOUR,HOURPERDAY) end
|
||||
function dobj:addminutes(n) return dobj_adddayfrc(self,n,TICKSPERMIN,MINPERDAY) end
|
||||
function dobj:addseconds(n) return dobj_adddayfrc(self,n,TICKSPERSEC,SECPERDAY) end
|
||||
function dobj:addticks(n) return dobj_adddayfrc(self,n,1,TICKSPERDAY) end
|
||||
local tvspec = {
|
||||
-- Abbreviated weekday name (Sun)
|
||||
['%a']=function(self) return sl_weekdays[weekday(self.daynum) + 7] end,
|
||||
-- Full weekday name (Sunday)
|
||||
['%A']=function(self) return sl_weekdays[weekday(self.daynum)] end,
|
||||
-- Abbreviated month name (Dec)
|
||||
['%b']=function(self) return sl_months[self:getmonth() - 1 + 12] end,
|
||||
-- Full month name (December)
|
||||
['%B']=function(self) return sl_months[self:getmonth() - 1] end,
|
||||
-- Year/100 (19, 20, 30)
|
||||
['%C']=function(self) return fmt("%.2d", fix(self:getyear()/100)) end,
|
||||
-- The day of the month as a number (range 1 - 31)
|
||||
['%d']=function(self) return fmt("%.2d", self:getday()) end,
|
||||
-- year for ISO 8601 week, from 00 (79)
|
||||
['%g']=function(self) return fmt("%.2d", mod(self:getisoyear() ,100)) end,
|
||||
-- year for ISO 8601 week, from 0000 (1979)
|
||||
['%G']=function(self) return fmt("%.4d", self:getisoyear()) end,
|
||||
-- same as %b
|
||||
['%h']=function(self) return self:fmt0("%b") end,
|
||||
-- hour of the 24-hour day, from 00 (06)
|
||||
['%H']=function(self) return fmt("%.2d", self:gethours()) end,
|
||||
-- The hour as a number using a 12-hour clock (01 - 12)
|
||||
['%I']=function(self) return fmt("%.2d", self:getclockhour()) end,
|
||||
-- The day of the year as a number (001 - 366)
|
||||
['%j']=function(self) return fmt("%.3d", self:getyearday()) end,
|
||||
-- Month of the year, from 01 to 12
|
||||
['%m']=function(self) return fmt("%.2d", self:getmonth()) end,
|
||||
-- Minutes after the hour 55
|
||||
['%M']=function(self) return fmt("%.2d", self:getminutes())end,
|
||||
-- AM/PM indicator (AM)
|
||||
['%p']=function(self) return sl_meridian[self:gethours() > 11 and 1 or -1] end, --AM/PM indicator (AM)
|
||||
-- The second as a number (59, 20 , 01)
|
||||
['%S']=function(self) return fmt("%.2d", self:getseconds()) end,
|
||||
-- ISO 8601 day of the week, to 7 for Sunday (7, 1)
|
||||
['%u']=function(self) return self:getisoweekday() end,
|
||||
-- Sunday week of the year, from 00 (48)
|
||||
['%U']=function(self) return fmt("%.2d", self:getweeknumber()) end,
|
||||
-- ISO 8601 week of the year, from 01 (48)
|
||||
['%V']=function(self) return fmt("%.2d", self:getisoweeknumber()) end,
|
||||
-- The day of the week as a decimal, Sunday being 0
|
||||
['%w']=function(self) return self:getweekday() - 1 end,
|
||||
-- Monday week of the year, from 00 (48)
|
||||
['%W']=function(self) return fmt("%.2d", self:getweeknumber(2)) end,
|
||||
-- The year as a number without a century (range 00 to 99)
|
||||
['%y']=function(self) return fmt("%.2d", mod(self:getyear() ,100)) end,
|
||||
-- Year with century (2000, 1914, 0325, 0001)
|
||||
['%Y']=function(self) return fmt("%.4d", self:getyear()) end,
|
||||
-- Time zone offset, the date object is assumed local time (+1000, -0230)
|
||||
['%z']=function(self) local b = -self:getbias(); local x = abs(b); return fmt("%s%.4d", b < 0 and "-" or "+", fix(x/60)*100 + floor(mod(x,60))) end,
|
||||
-- Time zone name, the date object is assumed local time
|
||||
['%Z']=function(self) return self:gettzname() end,
|
||||
-- Misc --
|
||||
-- Year, if year is in BCE, prints the BCE Year representation, otherwise result is similar to "%Y" (1 BCE, 40 BCE)
|
||||
['%\b']=function(self) local x = self:getyear() return fmt("%.4d%s", x>0 and x or (-x+1), x>0 and "" or " BCE") end,
|
||||
-- Seconds including fraction (59.998, 01.123)
|
||||
['%\f']=function(self) local x = self:getfracsec() return fmt("%s%.9f",x >= 10 and "" or "0", x) end,
|
||||
-- percent character %
|
||||
['%%']=function(self) return "%" end,
|
||||
-- Group Spec --
|
||||
-- 12-hour time, from 01:00:00 AM (06:55:15 AM); same as "%I:%M:%S %p"
|
||||
['%r']=function(self) return self:fmt0("%I:%M:%S %p") end,
|
||||
-- hour:minute, from 01:00 (06:55); same as "%I:%M"
|
||||
['%R']=function(self) return self:fmt0("%I:%M") end,
|
||||
-- 24-hour time, from 00:00:00 (06:55:15); same as "%H:%M:%S"
|
||||
['%T']=function(self) return self:fmt0("%H:%M:%S") end,
|
||||
-- month/day/year from 01/01/00 (12/02/79); same as "%m/%d/%y"
|
||||
['%D']=function(self) return self:fmt0("%m/%d/%y") end,
|
||||
-- year-month-day (1979-12-02); same as "%Y-%m-%d"
|
||||
['%F']=function(self) return self:fmt0("%Y-%m-%d") end,
|
||||
-- The preferred date and time representation; same as "%x %X"
|
||||
['%c']=function(self) return self:fmt0("%x %X") end,
|
||||
-- The preferred date representation, same as "%a %b %d %\b"
|
||||
['%x']=function(self) return self:fmt0("%a %b %d %\b") end,
|
||||
-- The preferred time representation, same as "%H:%M:%\f"
|
||||
['%X']=function(self) return self:fmt0("%H:%M:%\f") end,
|
||||
-- GroupSpec --
|
||||
-- Iso format, same as "%Y-%m-%dT%T"
|
||||
['${iso}'] = function(self) return self:fmt0("%Y-%m-%dT%T") end,
|
||||
-- http format, same as "%a, %d %b %Y %T GMT"
|
||||
['${http}'] = function(self) return self:fmt0("%a, %d %b %Y %T GMT") end,
|
||||
-- ctime format, same as "%a %b %d %T GMT %Y"
|
||||
['${ctime}'] = function(self) return self:fmt0("%a %b %d %T GMT %Y") end,
|
||||
-- RFC850 format, same as "%A, %d-%b-%y %T GMT"
|
||||
['${rfc850}'] = function(self) return self:fmt0("%A, %d-%b-%y %T GMT") end,
|
||||
-- RFC1123 format, same as "%a, %d %b %Y %T GMT"
|
||||
['${rfc1123}'] = function(self) return self:fmt0("%a, %d %b %Y %T GMT") end,
|
||||
-- asctime format, same as "%a %b %d %T %Y"
|
||||
['${asctime}'] = function(self) return self:fmt0("%a %b %d %T %Y") end,
|
||||
}
|
||||
function dobj:fmt0(str) return (gsub(str, "%%[%a%%\b\f]", function(x) local f = tvspec[x];return (f and f(self)) or x end)) end
|
||||
function dobj:fmt(str)
|
||||
str = str or self.fmtstr or fmtstr
|
||||
return self:fmt0((gmatch(str, "${%w+}")) and (gsub(str, "${%w+}", function(x)local f=tvspec[x];return (f and f(self)) or x end)) or str)
|
||||
end
|
||||
|
||||
dobj.format = dobj.fmt
|
||||
|
||||
function dobj.__lt(a, b) if (a.daynum == b.daynum) then return (a.dayfrc < b.dayfrc) else return (a.daynum < b.daynum) end end
|
||||
function dobj.__le(a, b) if (a.daynum == b.daynum) then return (a.dayfrc <= b.dayfrc) else return (a.daynum <= b.daynum) end end
|
||||
function dobj.__eq(a, b)return (a.daynum == b.daynum) and (a.dayfrc == b.dayfrc) end
|
||||
function dobj.__sub(a,b)
|
||||
local d1, d2 = date_getdobj(a), date_getdobj(b)
|
||||
local d0 = d1 and d2 and date_new(d1.daynum - d2.daynum, d1.dayfrc - d2.dayfrc)
|
||||
return d0 and d0:normalize()
|
||||
end
|
||||
function dobj.__add(a,b)
|
||||
local d1, d2 = date_getdobj(a), date_getdobj(b)
|
||||
local d0 = d1 and d2 and date_new(d1.daynum + d2.daynum, d1.dayfrc + d2.dayfrc)
|
||||
return d0 and d0:normalize()
|
||||
end
|
||||
function dobj.__concat(a, b) return tostring(a) .. tostring(b) end
|
||||
function dobj:__tostring() return self:fmt() end
|
||||
|
||||
function dobj:copy() return date_new(self.daynum, self.dayfrc) end
|
||||
|
||||
--[[ THE LOCAL DATE OBJECT METHODS ]]--
|
||||
function dobj:tolocal()
|
||||
local dn,df = self.daynum, self.dayfrc
|
||||
local bias = getbiasutc2(self)
|
||||
if bias then
|
||||
-- utc = local + bias; local = utc - bias
|
||||
self.daynum = dn
|
||||
self.dayfrc = df - bias*TICKSPERSEC
|
||||
return self:normalize()
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function dobj:toutc()
|
||||
local dn,df = self.daynum, self.dayfrc
|
||||
local bias = getbiasloc2(dn, df)
|
||||
if bias then
|
||||
-- utc = local + bias;
|
||||
self.daynum = dn
|
||||
self.dayfrc = df + bias*TICKSPERSEC
|
||||
return self:normalize()
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function dobj:getbias() return (getbiasloc2(self.daynum, self.dayfrc))/SECPERMIN end
|
||||
|
||||
function dobj:gettzname()
|
||||
local _, tvu, _ = getbiasloc2(self.daynum, self.dayfrc)
|
||||
return tvu and osdate("%Z",tvu) or ""
|
||||
end
|
||||
|
||||
--#if not DATE_OBJECT_AFX then
|
||||
function date.time(h, r, s, t)
|
||||
h, r, s, t = tonumber(h or 0), tonumber(r or 0), tonumber(s or 0), tonumber(t or 0)
|
||||
if h and r and s and t then
|
||||
return date_new(DAYNUM_DEF, makedayfrc(h, r, s, t))
|
||||
else
|
||||
return date_error_arg()
|
||||
end
|
||||
end
|
||||
|
||||
function date:__call(...)
|
||||
local arg = pack(...)
|
||||
if arg.n > 1 then return (date_from(...))
|
||||
elseif arg.n == 0 then return (date_getdobj(false))
|
||||
else local o, r = date_getdobj(arg[1]); return r and o:copy() or o end
|
||||
end
|
||||
|
||||
date.diff = dobj.__sub
|
||||
|
||||
function date.isleapyear(v)
|
||||
local y = fix(v);
|
||||
if not y then
|
||||
y = date_getdobj(v)
|
||||
y = y and y:getyear()
|
||||
end
|
||||
return isleapyear(y+0)
|
||||
end
|
||||
|
||||
function date.epoch() return date_epoch:copy() end
|
||||
|
||||
function date.isodate(y,w,d) return date_new(makedaynum_isoywd(y + 0, w and (w+0) or 1, d and (d+0) or 1), 0) end
|
||||
|
||||
-- Internal functions
|
||||
function date.fmt(str) if str then fmtstr = str end; return fmtstr end
|
||||
function date.daynummin(n) DAYNUM_MIN = (n and n < DAYNUM_MAX) and n or DAYNUM_MIN return n and DAYNUM_MIN or date_new(DAYNUM_MIN, 0):normalize()end
|
||||
function date.daynummax(n) DAYNUM_MAX = (n and n > DAYNUM_MIN) and n or DAYNUM_MAX return n and DAYNUM_MAX or date_new(DAYNUM_MAX, 0):normalize()end
|
||||
function date.ticks(t) if t then setticks(t) end return TICKSPERSEC end
|
||||
--#end -- not DATE_OBJECT_AFX
|
||||
|
||||
local tm = osdate("!*t", 0);
|
||||
if tm then
|
||||
date_epoch = date_new(makedaynum(tm.year, tm.month - 1, tm.day), makedayfrc(tm.hour, tm.min, tm.sec, 0))
|
||||
-- the distance from our epoch to os epoch in daynum
|
||||
DATE_EPOCH = date_epoch and date_epoch:spandays()
|
||||
else -- error will be raise only if called!
|
||||
date_epoch = setmetatable({},{__index = function() error("failed to get the epoch date") end})
|
||||
end
|
||||
|
||||
function date.serialize(object)
|
||||
return {tostring(object.daynum), tostring(object.dayfrc)}
|
||||
end
|
||||
|
||||
function date.construct(object)
|
||||
return date_isdobj(object) or (object.daynum and date_new(object.daynum, object.dayfrc) or date_new(object[1], object[2]))
|
||||
end
|
||||
|
||||
--#if not DATE_OBJECT_AFX then
|
||||
return date
|
||||
--#else
|
||||
--$return date_from
|
||||
--#end
|
||||
193
gamemodes/helix/gamemode/core/libs/thirdparty/sh_middleclass.lua
vendored
Normal file
193
gamemodes/helix/gamemode/core/libs/thirdparty/sh_middleclass.lua
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
local middleclass = {
|
||||
_VERSION = 'middleclass v4.1.1',
|
||||
_DESCRIPTION = 'Object Orientation for Lua',
|
||||
_URL = 'https://github.com/kikito/middleclass',
|
||||
_LICENSE = [[
|
||||
MIT LICENSE
|
||||
|
||||
Copyright (c) 2011 Enrique García Cota
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
]]
|
||||
}
|
||||
|
||||
local function _createIndexWrapper(aClass, f)
|
||||
if f == nil then
|
||||
return aClass.__instanceDict
|
||||
else
|
||||
return function(self, name)
|
||||
local value = aClass.__instanceDict[name]
|
||||
|
||||
if value ~= nil then
|
||||
return value
|
||||
elseif type(f) == "function" then
|
||||
return (f(self, name))
|
||||
else
|
||||
return f[name]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function _propagateInstanceMethod(aClass, name, f)
|
||||
f = name == "__index" and _createIndexWrapper(aClass, f) or f
|
||||
aClass.__instanceDict[name] = f
|
||||
|
||||
for subclass in pairs(aClass.subclasses) do
|
||||
if rawget(subclass.__declaredMethods, name) == nil then
|
||||
_propagateInstanceMethod(subclass, name, f)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function _declareInstanceMethod(aClass, name, f)
|
||||
aClass.__declaredMethods[name] = f
|
||||
|
||||
if f == nil and aClass.super then
|
||||
f = aClass.super.__instanceDict[name]
|
||||
end
|
||||
|
||||
_propagateInstanceMethod(aClass, name, f)
|
||||
end
|
||||
|
||||
local function _tostring(self) return "class " .. self.name end
|
||||
local function _call(self, ...) return self:New(...) end
|
||||
|
||||
local function _createClass(name, super)
|
||||
local dict = {}
|
||||
dict.__index = dict
|
||||
|
||||
local aClass = { name = name, super = super, static = {},
|
||||
__instanceDict = dict, __declaredMethods = {},
|
||||
subclasses = setmetatable({}, {__mode='k'}) }
|
||||
|
||||
if super then
|
||||
setmetatable(aClass.static, {
|
||||
__index = function(_,k)
|
||||
local result = rawget(dict,k)
|
||||
if result == nil then
|
||||
return super.static[k]
|
||||
end
|
||||
return result
|
||||
end
|
||||
})
|
||||
else
|
||||
setmetatable(aClass.static, { __index = function(_,k) return rawget(dict,k) end })
|
||||
end
|
||||
|
||||
setmetatable(aClass, { __index = aClass.static, __tostring = _tostring,
|
||||
__call = _call, __newindex = _declareInstanceMethod })
|
||||
|
||||
return aClass
|
||||
end
|
||||
|
||||
local function _includeMixin(aClass, mixin)
|
||||
assert(type(mixin) == 'table', "mixin must be a table")
|
||||
|
||||
for name,method in pairs(mixin) do
|
||||
if name ~= "Included" and name ~= "static" then aClass[name] = method end
|
||||
end
|
||||
|
||||
for name,method in pairs(mixin.static or {}) do
|
||||
aClass.static[name] = method
|
||||
end
|
||||
|
||||
if type(mixin.Included)=="function" then mixin:Included(aClass) end
|
||||
return aClass
|
||||
end
|
||||
|
||||
local DefaultMixin = {
|
||||
__tostring = function(self) return "instance of " .. tostring(self.class) end,
|
||||
|
||||
Initialize = function(self, ...) end,
|
||||
|
||||
IsInstanceOf = function(self, aClass)
|
||||
return type(aClass) == 'table'
|
||||
and type(self) == 'table'
|
||||
and (self.class == aClass
|
||||
or type(self.class) == 'table'
|
||||
and type(self.class.IsSubclassOf) == 'function'
|
||||
and self.class:IsSubclassOf(aClass))
|
||||
end,
|
||||
|
||||
static = {
|
||||
Allocate = function(self)
|
||||
assert(type(self) == 'table', "Make sure that you are using 'Class:Allocate' instead of 'Class.Allocate'")
|
||||
return setmetatable({ class = self }, self.__instanceDict)
|
||||
end,
|
||||
|
||||
New = function(self, ...)
|
||||
assert(type(self) == 'table', "Make sure that you are using 'Class:New' instead of 'Class.New'")
|
||||
local instance = self:Allocate()
|
||||
instance:Initialize(...)
|
||||
return instance
|
||||
end,
|
||||
|
||||
Subclass = function(self, name)
|
||||
assert(type(self) == 'table', "Make sure that you are using 'Class:Subclass' instead of 'Class.Subclass'")
|
||||
assert(type(name) == "string", "You must provide a name(string) for your class")
|
||||
|
||||
local subclass = _createClass(name, self)
|
||||
|
||||
for methodName, f in pairs(self.__instanceDict) do
|
||||
_propagateInstanceMethod(subclass, methodName, f)
|
||||
end
|
||||
subclass.Initialize = function(instance, ...) return self.Initialize(instance, ...) end
|
||||
|
||||
self.subclasses[subclass] = true
|
||||
self:Subclassed(subclass)
|
||||
|
||||
return subclass
|
||||
end,
|
||||
|
||||
Subclassed = function(self, other) end,
|
||||
|
||||
IsSubclassOf = function(self, other)
|
||||
return type(other) == 'table' and
|
||||
type(self.super) == 'table' and
|
||||
( self.super == other or self.super:IsSubclassOf(other) )
|
||||
end,
|
||||
|
||||
Include = function(self, ...)
|
||||
assert(type(self) == 'table', "Make sure you that you are using 'Class:Include' instead of 'Class.Include'")
|
||||
for _,mixin in ipairs({...}) do _includeMixin(self, mixin) end
|
||||
return self
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
function middleclass.class(name, super)
|
||||
assert(type(name) == 'string', "A name (string) is needed for the new class")
|
||||
return super and super:Subclass(name) or _includeMixin(_createClass(name), DefaultMixin)
|
||||
end
|
||||
|
||||
setmetatable(middleclass, { __call = function(_, ...) return middleclass.class(...) end })
|
||||
|
||||
ix.middleclass = middleclass
|
||||
174
gamemodes/helix/gamemode/core/libs/thirdparty/sh_netstream2.lua
vendored
Normal file
174
gamemodes/helix/gamemode/core/libs/thirdparty/sh_netstream2.lua
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
--[[
|
||||
NetStream - 2.0.0
|
||||
|
||||
Alexander Grist-Hucker
|
||||
http://www.revotech.org
|
||||
|
||||
Credits to:
|
||||
thelastpenguin for pON.
|
||||
https://github.com/thelastpenguin/gLUA-Library/tree/master/pON
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile();
|
||||
|
||||
local _player = player
|
||||
|
||||
netstream = netstream or {};
|
||||
netstream.stored = netstream.stored or {};
|
||||
|
||||
-- A function to split data for a data stream.
|
||||
function netstream.Split(data)
|
||||
local index = 1;
|
||||
local result = {};
|
||||
local buffer = {};
|
||||
|
||||
for i = 0, string.len(data) do
|
||||
buffer[#buffer + 1] = string.sub(data, i, i);
|
||||
|
||||
if (#buffer == 32768) then
|
||||
result[#result + 1] = table.concat(buffer);
|
||||
index = index + 1;
|
||||
buffer = {};
|
||||
end;
|
||||
end;
|
||||
|
||||
result[#result + 1] = table.concat(buffer);
|
||||
|
||||
return result;
|
||||
end;
|
||||
|
||||
-- A function to hook a data stream.
|
||||
function netstream.Hook(name, Callback)
|
||||
netstream.stored[name] = Callback;
|
||||
end;
|
||||
|
||||
if (SERVER) then
|
||||
util.AddNetworkString("NetStreamDS");
|
||||
|
||||
-- A function to start a net stream.
|
||||
function netstream.Start(player, name, ...)
|
||||
local recipients = {};
|
||||
local bShouldSend = false;
|
||||
local bSendPVS = false;
|
||||
|
||||
if (type(player) != "table") then
|
||||
if (!player) then
|
||||
player = _player.GetAll();
|
||||
elseif (type(player) == "Vector") then
|
||||
bSendPVS = true;
|
||||
else
|
||||
player = {player};
|
||||
end;
|
||||
end;
|
||||
|
||||
if (type(player) != "Vector") then
|
||||
for k, v in pairs(player) do
|
||||
if (type(v) == "Player") then
|
||||
recipients[#recipients + 1] = v;
|
||||
|
||||
bShouldSend = true;
|
||||
elseif (type(k) == "Player") then
|
||||
recipients[#recipients + 1] = k;
|
||||
|
||||
bShouldSend = true;
|
||||
end;
|
||||
end;
|
||||
else
|
||||
bShouldSend = true;
|
||||
end;
|
||||
|
||||
local dataTable = {...};
|
||||
local encodedData = pon.encode(dataTable);
|
||||
|
||||
if (encodedData and #encodedData > 0 and bShouldSend) then
|
||||
net.Start("NetStreamDS");
|
||||
net.WriteString(name);
|
||||
net.WriteUInt(#encodedData, 32);
|
||||
net.WriteData(encodedData, #encodedData);
|
||||
if (bSendPVS) then
|
||||
net.SendPVS(player);
|
||||
else
|
||||
net.Send(recipients);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
net.Receive("NetStreamDS", function(length, player)
|
||||
local NS_DS_NAME = net.ReadString();
|
||||
local NS_DS_LENGTH = net.ReadUInt(32);
|
||||
local NS_DS_DATA = net.ReadData(NS_DS_LENGTH);
|
||||
|
||||
if (NS_DS_NAME and NS_DS_DATA and NS_DS_LENGTH) then
|
||||
player.nsDataStreamName = NS_DS_NAME;
|
||||
player.nsDataStreamData = "";
|
||||
|
||||
if (player.nsDataStreamName and player.nsDataStreamData) then
|
||||
player.nsDataStreamData = NS_DS_DATA;
|
||||
|
||||
if (netstream.stored[player.nsDataStreamName]) then
|
||||
local bStatus, value = pcall(pon.decode, player.nsDataStreamData);
|
||||
|
||||
if (bStatus) then
|
||||
netstream.stored[player.nsDataStreamName](player, unpack(value));
|
||||
else
|
||||
ErrorNoHalt("NetStream: '"..NS_DS_NAME.."'\n"..value.."\n");
|
||||
end;
|
||||
else
|
||||
ErrorNoHalt("NetStream: Undefined hook for '"..NS_DS_NAME.."'\n")
|
||||
end;
|
||||
|
||||
player.nsDataStreamName = nil;
|
||||
player.nsDataStreamData = nil;
|
||||
end;
|
||||
end;
|
||||
|
||||
NS_DS_NAME, NS_DS_DATA, NS_DS_LENGTH = nil, nil, nil;
|
||||
end);
|
||||
else
|
||||
-- A function to start a net stream.
|
||||
function netstream.Start(name, ...)
|
||||
local dataTable = {...};
|
||||
local encodedData = pon.encode(dataTable);
|
||||
|
||||
if (encodedData and #encodedData > 0) then
|
||||
net.Start("NetStreamDS");
|
||||
net.WriteString(name);
|
||||
net.WriteUInt(#encodedData, 32);
|
||||
net.WriteData(encodedData, #encodedData);
|
||||
net.SendToServer();
|
||||
end;
|
||||
end;
|
||||
|
||||
net.Receive("NetStreamDS", function(length)
|
||||
local NS_DS_NAME = net.ReadString();
|
||||
local NS_DS_LENGTH = net.ReadUInt(32);
|
||||
local NS_DS_DATA = net.ReadData(NS_DS_LENGTH);
|
||||
|
||||
if (NS_DS_NAME and NS_DS_DATA and NS_DS_LENGTH) then
|
||||
if (netstream.stored[NS_DS_NAME]) then
|
||||
local bStatus, value = pcall(pon.decode, NS_DS_DATA);
|
||||
|
||||
if (bStatus) then
|
||||
netstream.stored[NS_DS_NAME](unpack(value));
|
||||
else
|
||||
ErrorNoHalt("NetStream: '"..NS_DS_NAME.."'\n"..value.."\n");
|
||||
end;
|
||||
else
|
||||
ErrorNoHalt("NetSteam: Undefined hook for '"..NS_DS_NAME.."'\n")
|
||||
end;
|
||||
end;
|
||||
|
||||
NS_DS_NAME, NS_DS_DATA, NS_DS_LENGTH = nil, nil, nil;
|
||||
end);
|
||||
end;
|
||||
411
gamemodes/helix/gamemode/core/libs/thirdparty/sh_pon.lua
vendored
Normal file
411
gamemodes/helix/gamemode/core/libs/thirdparty/sh_pon.lua
vendored
Normal file
@@ -0,0 +1,411 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
--[[
|
||||
DEVELOPMENTAL VERSION;
|
||||
VERSION 1.2.2
|
||||
Copyright thelastpenguin™
|
||||
You may use this for any purpose as long as:
|
||||
- You don't remove this copyright notice.
|
||||
- You don't claim this to be your own.
|
||||
- You properly credit the author, thelastpenguin™, if you publish your work based on (and/or using) this.
|
||||
If you modify the code for any purpose, the above still applies to the modified code.
|
||||
The author is not held responsible for any damages incured from the use of pon, you use it at your own risk.
|
||||
DATA TYPES SUPPORTED:
|
||||
- tables - k,v - pointers
|
||||
- strings - k,v - pointers
|
||||
- numbers - k,v
|
||||
- booleans- k,v
|
||||
- Vectors - k,v
|
||||
- Angles - k,v
|
||||
- Entities- k,v
|
||||
- Players - k,v
|
||||
CHANGE LOG
|
||||
V 1.1.0
|
||||
- Added Vehicle, NPC, NextBot, Player, Weapon
|
||||
V 1.2.0
|
||||
- Added custom handling for k,v tables without any array component.
|
||||
V 1.2.1
|
||||
- fixed deserialization bug.
|
||||
THANKS TO...
|
||||
- VERCAS for the inspiration.
|
||||
]]
|
||||
|
||||
|
||||
local pon = {};
|
||||
_G.pon = pon;
|
||||
|
||||
local type, count = type, table.Count ;
|
||||
local tonumber = tonumber ;
|
||||
local format = string.format;
|
||||
do
|
||||
local type, count = type, table.Count ;
|
||||
local tonumber = tonumber ;
|
||||
local format = string.format;
|
||||
|
||||
local encode = {};
|
||||
|
||||
local tryCache ;
|
||||
|
||||
local cacheSize = 0;
|
||||
|
||||
encode['table'] = function( self, tbl, output, cache )
|
||||
|
||||
if( cache[ tbl ] )then
|
||||
output[ #output + 1 ] = format('(%x)', cache[tbl] );
|
||||
return ;
|
||||
else
|
||||
cacheSize = cacheSize + 1;
|
||||
cache[ tbl ] = cacheSize;
|
||||
end
|
||||
|
||||
|
||||
local first = next(tbl, nil)
|
||||
local predictedNumeric = 1
|
||||
local lastKey = nil
|
||||
-- starts with a numeric dealio
|
||||
if first == 1 then
|
||||
output[#output + 1] = '{'
|
||||
|
||||
for k,v in next, tbl do
|
||||
if k == predictedNumeric then
|
||||
predictedNumeric = predictedNumeric + 1
|
||||
|
||||
local tv = type(v)
|
||||
if tv == 'string' then
|
||||
local pid = cache[v]
|
||||
if pid then
|
||||
output[#output + 1] = format('(%x)', pid)
|
||||
else
|
||||
cacheSize = cacheSize + 1
|
||||
cache[v] = cacheSize
|
||||
self.string(self, v, output, cache)
|
||||
end
|
||||
else
|
||||
self[tv](self, v, output, cache)
|
||||
end
|
||||
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
predictedNumeric = predictedNumeric - 1
|
||||
else
|
||||
predictedNumeric = nil
|
||||
end
|
||||
|
||||
if predictedNumeric == nil then
|
||||
output[#output + 1] = '[' -- no array component
|
||||
else
|
||||
output[#output + 1] = '~' -- array component came first so shit needs to happen
|
||||
end
|
||||
|
||||
for k, v in next, tbl, predictedNumeric do
|
||||
local tk, tv = type(k), type(v)
|
||||
|
||||
-- WRITE KEY
|
||||
if tk == 'string' then
|
||||
local pid = cache[ k ];
|
||||
if( pid )then
|
||||
output[ #output + 1 ] = format('(%x)', pid );
|
||||
else
|
||||
cacheSize = cacheSize + 1;
|
||||
cache[ k ] = cacheSize;
|
||||
|
||||
self.string( self, k, output, cache );
|
||||
end
|
||||
else
|
||||
self[tk](self, k, output, cache)
|
||||
end
|
||||
|
||||
-- WRITE VALUE
|
||||
if( tv == 'string' )then
|
||||
local pid = cache[ v ];
|
||||
if( pid )then
|
||||
output[ #output + 1 ] = format('(%x)', pid );
|
||||
else
|
||||
cacheSize = cacheSize + 1;
|
||||
cache[ v ] = cacheSize;
|
||||
|
||||
self.string( self, v, output, cache );
|
||||
end
|
||||
else
|
||||
self[ tv ]( self, v, output, cache );
|
||||
end
|
||||
end
|
||||
|
||||
output[#output + 1] = '}'
|
||||
end
|
||||
-- ENCODE STRING
|
||||
local gsub = string.gsub ;
|
||||
encode['string'] = function( self, str, output )
|
||||
--if tryCache( str, output ) then return end
|
||||
local estr, count = gsub( str, ";", "\\;");
|
||||
if( count == 0 )then
|
||||
output[ #output + 1 ] = '\''..str..';';
|
||||
else
|
||||
output[ #output + 1 ] = '"'..estr..'";';
|
||||
end
|
||||
end
|
||||
-- ENCODE NUMBER
|
||||
encode['number'] = function( self, num, output )
|
||||
if num%1 == 0 then
|
||||
if num < 0 then
|
||||
output[ #output + 1 ] = format( 'x%x;', -num );
|
||||
else
|
||||
output[ #output + 1 ] = format('X%x;', num );
|
||||
end
|
||||
else
|
||||
output[ #output + 1 ] = tonumber( num )..';';
|
||||
end
|
||||
end
|
||||
-- ENCODE BOOLEAN
|
||||
encode['boolean'] = function( self, val, output )
|
||||
output[ #output + 1 ] = val and 't' or 'f'
|
||||
end
|
||||
-- ENCODE VECTOR
|
||||
encode['Vector'] = function( self, val, output )
|
||||
output[ #output + 1 ] = ('v'..val.x..','..val.y)..(','..val.z..';');
|
||||
end
|
||||
-- ENCODE ANGLE
|
||||
encode['Angle'] = function( self, val, output )
|
||||
output[ #output + 1 ] = ('a'..val.p..','..val.y)..(','..val.r..';');
|
||||
end
|
||||
encode['Entity'] = function( self, val, output )
|
||||
output[ #output + 1] = 'E'..(IsValid( val ) and (val:EntIndex( )..';') or '#');
|
||||
end
|
||||
encode['Player'] = encode['Entity'];
|
||||
encode['Vehicle'] = encode['Entity'];
|
||||
encode['Weapon'] = encode['Entity'];
|
||||
encode['NPC'] = encode['Entity'];
|
||||
encode['NextBot'] = encode['Entity'];
|
||||
encode['PhysObj'] = encode['Entity'];
|
||||
|
||||
encode['nil'] = function()
|
||||
output[ #output + 1 ] = '?';
|
||||
end
|
||||
encode.__index = function( key )
|
||||
ErrorNoHalt('Type: '..key..' can not be encoded. Encoded as as pass-over value.');
|
||||
return encode['nil'];
|
||||
end
|
||||
|
||||
do
|
||||
local empty, concat = table.Empty, table.concat ;
|
||||
function pon.encode( tbl )
|
||||
local output = {};
|
||||
cacheSize = 0;
|
||||
encode[ 'table' ]( encode, tbl, output, {} );
|
||||
local res = concat( output );
|
||||
|
||||
return res;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local tonumber = tonumber ;
|
||||
local find, sub, gsub, Explode = string.find, string.sub, string.gsub, string.Explode ;
|
||||
local Vector, Angle, Entity = Vector, Angle, Entity ;
|
||||
|
||||
local decode = {};
|
||||
decode['{'] = function( self, index, str, cache )
|
||||
|
||||
local cur = {};
|
||||
cache[ #cache + 1 ] = cur;
|
||||
|
||||
local k, v, tk, tv = 1, nil, nil, nil;
|
||||
while( true )do
|
||||
tv = sub( str, index, index );
|
||||
if( not tv or tv == '~' )then
|
||||
index = index + 1;
|
||||
break ;
|
||||
end
|
||||
if( tv == '}' )then
|
||||
return index + 1, cur;
|
||||
end
|
||||
|
||||
-- READ THE VALUE
|
||||
index = index + 1;
|
||||
index, v = self[ tv ]( self, index, str, cache );
|
||||
cur[ k ] = v;
|
||||
|
||||
k = k + 1;
|
||||
end
|
||||
|
||||
while( true )do
|
||||
tk = sub( str, index, index );
|
||||
if( not tk or tk == '}' )then
|
||||
index = index + 1;
|
||||
break ;
|
||||
end
|
||||
|
||||
-- READ THE KEY
|
||||
|
||||
index = index + 1;
|
||||
index, k = self[ tk ]( self, index, str, cache );
|
||||
|
||||
-- READ THE VALUE
|
||||
tv = sub( str, index, index );
|
||||
index = index + 1;
|
||||
index, v = self[ tv ]( self, index, str, cache );
|
||||
|
||||
cur[ k ] = v;
|
||||
end
|
||||
|
||||
return index, cur;
|
||||
end
|
||||
decode['['] = function( self, index, str, cache )
|
||||
|
||||
local cur = {};
|
||||
cache[ #cache + 1 ] = cur;
|
||||
|
||||
local k, v, tk, tv = 1, nil, nil, nil;
|
||||
while( true )do
|
||||
tk = sub( str, index, index );
|
||||
if( not tk or tk == '}' )then
|
||||
index = index + 1;
|
||||
break ;
|
||||
end
|
||||
|
||||
-- READ THE KEY
|
||||
index = index + 1;
|
||||
index, k = self[ tk ]( self, index, str, cache );
|
||||
if not k then continue end
|
||||
|
||||
-- READ THE VALUE
|
||||
tv = sub( str, index, index );
|
||||
index = index + 1;
|
||||
if not self[tv] then
|
||||
print('did not find type: '..tv)
|
||||
end
|
||||
index, v = self[ tv ]( self, index, str, cache );
|
||||
|
||||
cur[ k ] = v;
|
||||
end
|
||||
|
||||
return index, cur;
|
||||
end
|
||||
|
||||
-- STRING
|
||||
decode['"'] = function( self, index, str, cache )
|
||||
local finish = find( str, '";', index, true );
|
||||
local res = gsub( sub( str, index, finish - 1 ), '\\;', ';' );
|
||||
index = finish + 2;
|
||||
|
||||
cache[ #cache + 1 ] = res;
|
||||
return index, res;
|
||||
end
|
||||
-- STRING NO ESCAPING NEEDED
|
||||
decode['\''] = function( self, index, str, cache )
|
||||
local finish = find( str, ';', index, true );
|
||||
local res = sub( str, index, finish - 1 )
|
||||
index = finish + 1;
|
||||
|
||||
cache[ #cache + 1 ] = res;
|
||||
return index, res;
|
||||
end
|
||||
|
||||
-- NUMBER
|
||||
decode['n'] = function( self, index, str, cache )
|
||||
index = index - 1;
|
||||
local finish = find( str, ';', index, true );
|
||||
local num = tonumber( sub( str, index, finish - 1 ) );
|
||||
index = finish + 1;
|
||||
return index, num;
|
||||
end
|
||||
decode['0'] = decode['n'];
|
||||
decode['1'] = decode['n'];
|
||||
decode['2'] = decode['n'];
|
||||
decode['3'] = decode['n'];
|
||||
decode['4'] = decode['n'];
|
||||
decode['5'] = decode['n'];
|
||||
decode['6'] = decode['n'];
|
||||
decode['7'] = decode['n'];
|
||||
decode['8'] = decode['n'];
|
||||
decode['9'] = decode['n'];
|
||||
decode['-'] = decode['n'];
|
||||
-- positive hex
|
||||
decode['X'] = function( self, index, str, cache )
|
||||
local finish = find( str, ';', index, true );
|
||||
local num = tonumber( sub( str, index, finish - 1), 16 );
|
||||
index = finish + 1;
|
||||
return index, num;
|
||||
end
|
||||
-- negative hex
|
||||
decode['x'] = function( self, index, str, cache )
|
||||
local finish = find( str, ';', index, true );
|
||||
local num = -tonumber( sub( str, index, finish - 1), 16 );
|
||||
index = finish + 1;
|
||||
return index, num;
|
||||
end
|
||||
|
||||
-- POINTER
|
||||
decode['('] = function( self, index, str, cache )
|
||||
local finish = find( str, ')', index, true );
|
||||
local num = tonumber( sub( str, index, finish - 1), 16 );
|
||||
index = finish + 1;
|
||||
return index, cache[ num ];
|
||||
end
|
||||
|
||||
-- BOOLEAN. ONE DATA TYPE FOR YES, ANOTHER FOR NO.
|
||||
decode[ 't' ] = function( self, index )
|
||||
return index, true;
|
||||
end
|
||||
decode[ 'f' ] = function( self, index )
|
||||
return index, false;
|
||||
end
|
||||
|
||||
-- VECTOR
|
||||
decode[ 'v' ] = function( self, index, str, cache )
|
||||
local finish = find( str, ';', index, true );
|
||||
local vecStr = sub( str, index, finish - 1 );
|
||||
index = finish + 1; -- update the index.
|
||||
local segs = Explode( ',', vecStr, false );
|
||||
return index, Vector( tonumber( segs[1] ), tonumber( segs[2] ), tonumber( segs[3] ) );
|
||||
end
|
||||
-- ANGLE
|
||||
decode[ 'a' ] = function( self, index, str, cache )
|
||||
local finish = find( str, ';', index, true );
|
||||
local angStr = sub( str, index, finish - 1 );
|
||||
index = finish + 1; -- update the index.
|
||||
local segs = Explode( ',', angStr, false );
|
||||
return index, Angle( tonumber( segs[1] ), tonumber( segs[2] ), tonumber( segs[3] ) );
|
||||
end
|
||||
-- ENTITY
|
||||
decode[ 'E' ] = function( self, index, str, cache )
|
||||
if( str[index] == '#' )then
|
||||
index = index + 1;
|
||||
return index, NULL ;
|
||||
else
|
||||
local finish = find( str, ';', index, true );
|
||||
local num = tonumber( sub( str, index, finish - 1 ) );
|
||||
index = finish + 1;
|
||||
return index, Entity( num );
|
||||
end
|
||||
end
|
||||
-- PLAYER
|
||||
decode[ 'P' ] = function( self, index, str, cache )
|
||||
local finish = find( str, ';', index, true );
|
||||
local num = tonumber( sub( str, index, finish - 1 ) );
|
||||
index = finish + 1;
|
||||
return index, Entity( num ) or NULL;
|
||||
end
|
||||
-- NIL
|
||||
decode['?'] = function( self, index, str, cache )
|
||||
return index + 1, nil;
|
||||
end
|
||||
|
||||
|
||||
function pon.decode( data )
|
||||
local _, res = decode[sub(data,1,1)]( decode, 2, data, {});
|
||||
return res;
|
||||
end
|
||||
end
|
||||
385
gamemodes/helix/gamemode/core/libs/thirdparty/sh_tween.lua
vendored
Normal file
385
gamemodes/helix/gamemode/core/libs/thirdparty/sh_tween.lua
vendored
Normal file
@@ -0,0 +1,385 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
local tween = {
|
||||
_VERSION = 'tween 2.1.1',
|
||||
_DESCRIPTION = 'tweening for lua',
|
||||
_URL = 'https://github.com/kikito/tween.lua',
|
||||
_LICENSE = [[
|
||||
MIT LICENSE
|
||||
|
||||
Copyright (c) 2014 Enrique García Cota, Yuichi Tateno, Emmanuel Oga
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
]]
|
||||
}
|
||||
|
||||
-- easing
|
||||
|
||||
-- Adapted from https://github.com/EmmanuelOga/easing. See LICENSE.txt for credits.
|
||||
-- For all easing functions:
|
||||
-- t = time == how much time has to pass for the tweening to complete
|
||||
-- b = begin == starting property value
|
||||
-- c = change == ending - beginning
|
||||
-- d = duration == running time. How much time has passed *right now*
|
||||
|
||||
local pow, sin, cos, pi, sqrt, abs, asin = math.pow, math.sin, math.cos, math.pi, math.sqrt, math.abs, math.asin
|
||||
|
||||
-- linear
|
||||
local function linear(t, b, c, d) return c * t / d + b end
|
||||
|
||||
-- quad
|
||||
local function inQuad(t, b, c, d) return c * pow(t / d, 2) + b end
|
||||
local function outQuad(t, b, c, d)
|
||||
t = t / d
|
||||
return -c * t * (t - 2) + b
|
||||
end
|
||||
local function inOutQuad(t, b, c, d)
|
||||
t = t / d * 2
|
||||
if t < 1 then return c / 2 * pow(t, 2) + b end
|
||||
return -c / 2 * ((t - 1) * (t - 3) - 1) + b
|
||||
end
|
||||
local function outInQuad(t, b, c, d)
|
||||
if t < d / 2 then return outQuad(t * 2, b, c / 2, d) end
|
||||
return inQuad((t * 2) - d, b + c / 2, c / 2, d)
|
||||
end
|
||||
|
||||
-- cubic
|
||||
local function inCubic (t, b, c, d) return c * pow(t / d, 3) + b end
|
||||
local function outCubic(t, b, c, d) return c * (pow(t / d - 1, 3) + 1) + b end
|
||||
local function inOutCubic(t, b, c, d)
|
||||
t = t / d * 2
|
||||
if t < 1 then return c / 2 * t * t * t + b end
|
||||
t = t - 2
|
||||
return c / 2 * (t * t * t + 2) + b
|
||||
end
|
||||
local function outInCubic(t, b, c, d)
|
||||
if t < d / 2 then return outCubic(t * 2, b, c / 2, d) end
|
||||
return inCubic((t * 2) - d, b + c / 2, c / 2, d)
|
||||
end
|
||||
|
||||
-- quart
|
||||
local function inQuart(t, b, c, d) return c * pow(t / d, 4) + b end
|
||||
local function outQuart(t, b, c, d) return -c * (pow(t / d - 1, 4) - 1) + b end
|
||||
local function inOutQuart(t, b, c, d)
|
||||
t = t / d * 2
|
||||
if t < 1 then return c / 2 * pow(t, 4) + b end
|
||||
return -c / 2 * (pow(t - 2, 4) - 2) + b
|
||||
end
|
||||
local function outInQuart(t, b, c, d)
|
||||
if t < d / 2 then return outQuart(t * 2, b, c / 2, d) end
|
||||
return inQuart((t * 2) - d, b + c / 2, c / 2, d)
|
||||
end
|
||||
|
||||
-- quint
|
||||
local function inQuint(t, b, c, d) return c * pow(t / d, 5) + b end
|
||||
local function outQuint(t, b, c, d) return c * (pow(t / d - 1, 5) + 1) + b end
|
||||
local function inOutQuint(t, b, c, d)
|
||||
t = t / d * 2
|
||||
if t < 1 then return c / 2 * pow(t, 5) + b end
|
||||
return c / 2 * (pow(t - 2, 5) + 2) + b
|
||||
end
|
||||
local function outInQuint(t, b, c, d)
|
||||
if t < d / 2 then return outQuint(t * 2, b, c / 2, d) end
|
||||
return inQuint((t * 2) - d, b + c / 2, c / 2, d)
|
||||
end
|
||||
|
||||
-- sine
|
||||
local function inSine(t, b, c, d) return -c * cos(t / d * (pi / 2)) + c + b end
|
||||
local function outSine(t, b, c, d) return c * sin(t / d * (pi / 2)) + b end
|
||||
local function inOutSine(t, b, c, d) return -c / 2 * (cos(pi * t / d) - 1) + b end
|
||||
local function outInSine(t, b, c, d)
|
||||
if t < d / 2 then return outSine(t * 2, b, c / 2, d) end
|
||||
return inSine((t * 2) -d, b + c / 2, c / 2, d)
|
||||
end
|
||||
|
||||
-- expo
|
||||
local function inExpo(t, b, c, d)
|
||||
if t == 0 then return b end
|
||||
return c * pow(2, 10 * (t / d - 1)) + b - c * 0.001
|
||||
end
|
||||
local function outExpo(t, b, c, d)
|
||||
if t == d then return b + c end
|
||||
return c * 1.001 * (-pow(2, -10 * t / d) + 1) + b
|
||||
end
|
||||
local function inOutExpo(t, b, c, d)
|
||||
if t == 0 then return b end
|
||||
if t == d then return b + c end
|
||||
t = t / d * 2
|
||||
if t < 1 then return c / 2 * pow(2, 10 * (t - 1)) + b - c * 0.0005 end
|
||||
return c / 2 * 1.0005 * (-pow(2, -10 * (t - 1)) + 2) + b
|
||||
end
|
||||
local function outInExpo(t, b, c, d)
|
||||
if t < d / 2 then return outExpo(t * 2, b, c / 2, d) end
|
||||
return inExpo((t * 2) - d, b + c / 2, c / 2, d)
|
||||
end
|
||||
|
||||
-- circ
|
||||
local function inCirc(t, b, c, d) return(-c * (sqrt(1 - pow(t / d, 2)) - 1) + b) end
|
||||
local function outCirc(t, b, c, d) return(c * sqrt(1 - pow(t / d - 1, 2)) + b) end
|
||||
local function inOutCirc(t, b, c, d)
|
||||
t = t / d * 2
|
||||
if t < 1 then return -c / 2 * (sqrt(1 - t * t) - 1) + b end
|
||||
t = t - 2
|
||||
return c / 2 * (sqrt(1 - t * t) + 1) + b
|
||||
end
|
||||
local function outInCirc(t, b, c, d)
|
||||
if t < d / 2 then return outCirc(t * 2, b, c / 2, d) end
|
||||
return inCirc((t * 2) - d, b + c / 2, c / 2, d)
|
||||
end
|
||||
|
||||
-- elastic
|
||||
local function calculatePAS(p,a,c,d)
|
||||
p, a = p or d * 0.3, a or 0
|
||||
if a < abs(c) then return p, c, p / 4 end -- p, a, s
|
||||
return p, a, p / (2 * pi) * asin(c/a) -- p,a,s
|
||||
end
|
||||
local function inElastic(t, b, c, d, a, p)
|
||||
local s
|
||||
if t == 0 then return b end
|
||||
t = t / d
|
||||
if t == 1 then return b + c end
|
||||
p,a,s = calculatePAS(p,a,c,d)
|
||||
t = t - 1
|
||||
return -(a * pow(2, 10 * t) * sin((t * d - s) * (2 * pi) / p)) + b
|
||||
end
|
||||
local function outElastic(t, b, c, d, a, p)
|
||||
local s
|
||||
if t == 0 then return b end
|
||||
t = t / d
|
||||
if t == 1 then return b + c end
|
||||
p,a,s = calculatePAS(p,a,c,d)
|
||||
return a * pow(2, -10 * t) * sin((t * d - s) * (2 * pi) / p) + c + b
|
||||
end
|
||||
local function inOutElastic(t, b, c, d, a, p)
|
||||
local s
|
||||
if t == 0 then return b end
|
||||
t = t / d * 2
|
||||
if t == 2 then return b + c end
|
||||
p,a,s = calculatePAS(p,a,c,d)
|
||||
t = t - 1
|
||||
if t < 0 then return -0.5 * (a * pow(2, 10 * t) * sin((t * d - s) * (2 * pi) / p)) + b end
|
||||
return a * pow(2, -10 * t) * sin((t * d - s) * (2 * pi) / p ) * 0.5 + c + b
|
||||
end
|
||||
local function outInElastic(t, b, c, d, a, p)
|
||||
if t < d / 2 then return outElastic(t * 2, b, c / 2, d, a, p) end
|
||||
return inElastic((t * 2) - d, b + c / 2, c / 2, d, a, p)
|
||||
end
|
||||
|
||||
-- back
|
||||
local function inBack(t, b, c, d, s)
|
||||
s = s or 1.70158
|
||||
t = t / d
|
||||
return c * t * t * ((s + 1) * t - s) + b
|
||||
end
|
||||
local function outBack(t, b, c, d, s)
|
||||
s = s or 1.70158
|
||||
t = t / d - 1
|
||||
return c * (t * t * ((s + 1) * t + s) + 1) + b
|
||||
end
|
||||
local function inOutBack(t, b, c, d, s)
|
||||
s = (s or 1.70158) * 1.525
|
||||
t = t / d * 2
|
||||
if t < 1 then return c / 2 * (t * t * ((s + 1) * t - s)) + b end
|
||||
t = t - 2
|
||||
return c / 2 * (t * t * ((s + 1) * t + s) + 2) + b
|
||||
end
|
||||
local function outInBack(t, b, c, d, s)
|
||||
if t < d / 2 then return outBack(t * 2, b, c / 2, d, s) end
|
||||
return inBack((t * 2) - d, b + c / 2, c / 2, d, s)
|
||||
end
|
||||
|
||||
-- bounce
|
||||
local function outBounce(t, b, c, d)
|
||||
t = t / d
|
||||
if t < 1 / 2.75 then return c * (7.5625 * t * t) + b end
|
||||
if t < 2 / 2.75 then
|
||||
t = t - (1.5 / 2.75)
|
||||
return c * (7.5625 * t * t + 0.75) + b
|
||||
elseif t < 2.5 / 2.75 then
|
||||
t = t - (2.25 / 2.75)
|
||||
return c * (7.5625 * t * t + 0.9375) + b
|
||||
end
|
||||
t = t - (2.625 / 2.75)
|
||||
return c * (7.5625 * t * t + 0.984375) + b
|
||||
end
|
||||
local function inBounce(t, b, c, d) return c - outBounce(d - t, 0, c, d) + b end
|
||||
local function inOutBounce(t, b, c, d)
|
||||
if t < d / 2 then return inBounce(t * 2, 0, c, d) * 0.5 + b end
|
||||
return outBounce(t * 2 - d, 0, c, d) * 0.5 + c * .5 + b
|
||||
end
|
||||
local function outInBounce(t, b, c, d)
|
||||
if t < d / 2 then return outBounce(t * 2, b, c / 2, d) end
|
||||
return inBounce((t * 2) - d, b + c / 2, c / 2, d)
|
||||
end
|
||||
|
||||
tween.easing = {
|
||||
linear = linear,
|
||||
inQuad = inQuad, outQuad = outQuad, inOutQuad = inOutQuad, outInQuad = outInQuad,
|
||||
inCubic = inCubic, outCubic = outCubic, inOutCubic = inOutCubic, outInCubic = outInCubic,
|
||||
inQuart = inQuart, outQuart = outQuart, inOutQuart = inOutQuart, outInQuart = outInQuart,
|
||||
inQuint = inQuint, outQuint = outQuint, inOutQuint = inOutQuint, outInQuint = outInQuint,
|
||||
inSine = inSine, outSine = outSine, inOutSine = inOutSine, outInSine = outInSine,
|
||||
inExpo = inExpo, outExpo = outExpo, inOutExpo = inOutExpo, outInExpo = outInExpo,
|
||||
inCirc = inCirc, outCirc = outCirc, inOutCirc = inOutCirc, outInCirc = outInCirc,
|
||||
inElastic = inElastic, outElastic = outElastic, inOutElastic = inOutElastic, outInElastic = outInElastic,
|
||||
inBack = inBack, outBack = outBack, inOutBack = inOutBack, outInBack = outInBack,
|
||||
inBounce = inBounce, outBounce = outBounce, inOutBounce = inOutBounce, outInBounce = outInBounce
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- private stuff
|
||||
|
||||
local function copyTables(destination, keysTable, valuesTable)
|
||||
valuesTable = valuesTable or keysTable
|
||||
local mt = getmetatable(keysTable)
|
||||
if mt and getmetatable(destination) == nil then
|
||||
setmetatable(destination, mt)
|
||||
end
|
||||
for k,v in pairs(keysTable) do
|
||||
if type(v) == 'table' then
|
||||
destination[k] = copyTables({}, v, valuesTable[k])
|
||||
else
|
||||
destination[k] = valuesTable[k]
|
||||
end
|
||||
end
|
||||
return destination
|
||||
end
|
||||
|
||||
local function checkSubjectAndTargetRecursively(subject, target, path)
|
||||
path = path or {}
|
||||
local newPath
|
||||
for k,targetValue in pairs(target) do
|
||||
newPath = copyTables({}, path)
|
||||
table.insert(newPath, tostring(k))
|
||||
if isnumber(targetValue) then
|
||||
assert(isnumber(subject[k]), "Parameter '" .. table.concat(newPath,'/') .. "' is missing from subject or isn't a number")
|
||||
elseif istable(targetValue) then
|
||||
checkSubjectAndTargetRecursively(subject[k], targetValue, newPath)
|
||||
else
|
||||
assert(isnumber(targetValue), "Parameter '" .. table.concat(newPath,'/') .. "' must be a number or table of numbers")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function checkNewParams(duration, subject, target, easing)
|
||||
assert(isnumber(duration) and duration > 0, "duration must be a positive number. Was " .. tostring(duration))
|
||||
assert(istable(target), "target must be a table. Was " .. tostring(target))
|
||||
assert(isfunction(easing), "easing must be a function. Was " .. tostring(easing))
|
||||
checkSubjectAndTargetRecursively(subject, target)
|
||||
end
|
||||
|
||||
local function getEasingFunction(easing)
|
||||
easing = easing or "linear"
|
||||
if isstring(easing) then
|
||||
local name = easing
|
||||
easing = tween.easing[name]
|
||||
if not isfunction(easing) then
|
||||
error("The easing function name '" .. name .. "' is invalid")
|
||||
end
|
||||
end
|
||||
return easing
|
||||
end
|
||||
|
||||
local function performEasingOnSubject(subject, target, initial, clock, duration, easing)
|
||||
local t,b,c,d
|
||||
for k,v in pairs(target) do
|
||||
if istable(v) then
|
||||
performEasingOnSubject(subject[k], v, initial[k], clock, duration, easing)
|
||||
else
|
||||
t,b,c,d = clock, initial[k], v - initial[k], duration
|
||||
subject[k] = easing(t,b,c,d)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function applyValues(subject, target)
|
||||
for k, v in pairs(target) do
|
||||
if (istable(v)) then
|
||||
applyValues(subject[k], v)
|
||||
else
|
||||
subject[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Tween methods
|
||||
|
||||
local Tween = {}
|
||||
local Tween_mt = {__index = Tween}
|
||||
|
||||
function Tween:set(clock)
|
||||
assert(isnumber(clock), "clock must be a positive number or 0")
|
||||
|
||||
self.initial = self.initial or copyTables({}, self.target, self.subject)
|
||||
self.clock = clock
|
||||
|
||||
if self.clock <= 0 then
|
||||
|
||||
self.clock = 0
|
||||
applyValues(self.subject, self.initial)
|
||||
|
||||
elseif self.clock >= self.duration then -- the tween has expired
|
||||
|
||||
self.clock = self.duration
|
||||
applyValues(self.subject, self.target)
|
||||
|
||||
else
|
||||
|
||||
performEasingOnSubject(self.subject, self.target, self.initial, self.clock, self.duration, self.easing)
|
||||
|
||||
end
|
||||
|
||||
return self.clock >= self.duration
|
||||
end
|
||||
|
||||
function Tween:reset()
|
||||
return self:set(0)
|
||||
end
|
||||
|
||||
function Tween:update(dt)
|
||||
assert(isnumber(dt), "dt must be a number")
|
||||
return self:set(self.clock + dt)
|
||||
end
|
||||
|
||||
|
||||
-- Public interface
|
||||
|
||||
function tween.new(duration, subject, target, easing)
|
||||
easing = getEasingFunction(easing)
|
||||
checkNewParams(duration, subject, target, easing)
|
||||
return setmetatable({
|
||||
duration = duration,
|
||||
subject = subject,
|
||||
target = target,
|
||||
easing = easing,
|
||||
clock = 0
|
||||
}, Tween_mt)
|
||||
end
|
||||
|
||||
ix.tween = tween
|
||||
338
gamemodes/helix/gamemode/core/libs/thirdparty/sh_utf8.lua
vendored
Normal file
338
gamemodes/helix/gamemode/core/libs/thirdparty/sh_utf8.lua
vendored
Normal file
@@ -0,0 +1,338 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
-- $Id: utf8.lua 179 2009-04-03 18:10:03Z pasta $
|
||||
--
|
||||
-- Provides UTF-8 aware string functions implemented in pure lua:
|
||||
-- * string.utf8len(s)
|
||||
-- * string.utf8sub(s, i, j)
|
||||
-- * string.utf8reverse(s)
|
||||
--
|
||||
-- If utf8data.lua (containing the lower<->upper case mappings) is loaded, these
|
||||
-- additional functions are available:
|
||||
-- * string.utf8upper(s)
|
||||
-- * string.utf8lower(s)
|
||||
--
|
||||
-- All functions behave as their non UTF-8 aware counterparts with the exception
|
||||
-- that UTF-8 characters are used instead of bytes for all units.
|
||||
|
||||
--[[
|
||||
Copyright (c) 2006-2007, Kyle Smith
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
--]]
|
||||
|
||||
-- ABNF from RFC 3629
|
||||
--
|
||||
-- UTF8-octets = *( UTF8-char )
|
||||
-- UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
|
||||
-- UTF8-1 = %x00-7F
|
||||
-- UTF8-2 = %xC2-DF UTF8-tail
|
||||
-- UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
|
||||
-- %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
|
||||
-- UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
|
||||
-- %xF4 %x80-8F 2( UTF8-tail )
|
||||
-- UTF8-tail = %x80-BF
|
||||
--
|
||||
|
||||
ix.util.Include("data/sh_utf8_casemap.lua")
|
||||
|
||||
-- returns the number of bytes used by the UTF-8 character at byte i in s
|
||||
-- also doubles as a UTF-8 character validator
|
||||
local function utf8charbytes (s, i)
|
||||
-- argument defaults
|
||||
i = i or 1
|
||||
|
||||
-- argument checking
|
||||
if not isstring(s) then
|
||||
error("bad argument #1 to 'utf8charbytes' (string expected, got ".. type(s).. ")")
|
||||
end
|
||||
if not isnumber(i) then
|
||||
error("bad argument #2 to 'utf8charbytes' (number expected, got ".. type(i).. ")")
|
||||
end
|
||||
|
||||
local c = s:byte(i)
|
||||
|
||||
-- determine bytes needed for character, based on RFC 3629
|
||||
-- validate byte 1
|
||||
if c > 0 and c <= 127 then
|
||||
-- UTF8-1
|
||||
return 1
|
||||
|
||||
elseif c >= 194 and c <= 223 then
|
||||
-- UTF8-2
|
||||
local c2 = s:byte(i + 1)
|
||||
|
||||
if not c2 then
|
||||
error("UTF-8 string terminated early")
|
||||
end
|
||||
|
||||
-- validate byte 2
|
||||
if c2 < 128 or c2 > 191 then
|
||||
error("Invalid UTF-8 character")
|
||||
end
|
||||
|
||||
return 2
|
||||
|
||||
elseif c >= 224 and c <= 239 then
|
||||
-- UTF8-3
|
||||
local c2 = s:byte(i + 1)
|
||||
local c3 = s:byte(i + 2)
|
||||
|
||||
if not c2 or not c3 then
|
||||
error("UTF-8 string terminated early")
|
||||
end
|
||||
|
||||
-- validate byte 2
|
||||
if c == 224 and (c2 < 160 or c2 > 191) then
|
||||
error("Invalid UTF-8 character")
|
||||
elseif c == 237 and (c2 < 128 or c2 > 159) then
|
||||
error("Invalid UTF-8 character")
|
||||
elseif c2 < 128 or c2 > 191 then
|
||||
error("Invalid UTF-8 character")
|
||||
end
|
||||
|
||||
-- validate byte 3
|
||||
if c3 < 128 or c3 > 191 then
|
||||
error("Invalid UTF-8 character")
|
||||
end
|
||||
|
||||
return 3
|
||||
|
||||
elseif c >= 240 and c <= 244 then
|
||||
-- UTF8-4
|
||||
local c2 = s:byte(i + 1)
|
||||
local c3 = s:byte(i + 2)
|
||||
local c4 = s:byte(i + 3)
|
||||
|
||||
if not c2 or not c3 or not c4 then
|
||||
error("UTF-8 string terminated early")
|
||||
end
|
||||
|
||||
-- validate byte 2
|
||||
if c == 240 and (c2 < 144 or c2 > 191) then
|
||||
error("Invalid UTF-8 character")
|
||||
elseif c == 244 and (c2 < 128 or c2 > 143) then
|
||||
error("Invalid UTF-8 character")
|
||||
elseif c2 < 128 or c2 > 191 then
|
||||
error("Invalid UTF-8 character")
|
||||
end
|
||||
|
||||
-- validate byte 3
|
||||
if c3 < 128 or c3 > 191 then
|
||||
error("Invalid UTF-8 character")
|
||||
end
|
||||
|
||||
-- validate byte 4
|
||||
if c4 < 128 or c4 > 191 then
|
||||
error("Invalid UTF-8 character")
|
||||
end
|
||||
|
||||
return 4
|
||||
|
||||
else
|
||||
error("Invalid UTF-8 character")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- returns the number of characters in a UTF-8 string
|
||||
local function utf8len (s)
|
||||
-- argument checking
|
||||
if not isstring(s) then
|
||||
error("bad argument #1 to 'utf8len' (string expected, got ".. type(s).. ")")
|
||||
end
|
||||
|
||||
local pos = 1
|
||||
local bytes = s:len()
|
||||
local len = 0
|
||||
|
||||
while pos <= bytes do
|
||||
len = len + 1
|
||||
pos = pos + utf8charbytes(s, pos)
|
||||
end
|
||||
|
||||
return len
|
||||
end
|
||||
|
||||
-- install in the string library
|
||||
if not string.utf8bytes then
|
||||
string.utf8bytes = utf8charbytes
|
||||
end
|
||||
|
||||
-- install in the string library
|
||||
if not string.utf8len then
|
||||
string.utf8len = utf8len
|
||||
end
|
||||
|
||||
|
||||
-- functions identically to string.sub except that i and j are UTF-8 characters
|
||||
-- instead of bytes
|
||||
local function utf8sub (s, i, j)
|
||||
-- argument defaults
|
||||
j = j or -1
|
||||
|
||||
-- argument checking
|
||||
if not isstring(s) then
|
||||
error("bad argument #1 to 'utf8sub' (string expected, got ".. type(s).. ")")
|
||||
end
|
||||
if not isnumber(i) then
|
||||
error("bad argument #2 to 'utf8sub' (number expected, got ".. type(i).. ")")
|
||||
end
|
||||
if not isnumber(j) then
|
||||
error("bad argument #3 to 'utf8sub' (number expected, got ".. type(j).. ")")
|
||||
end
|
||||
|
||||
local pos = 1
|
||||
local bytes = s:len()
|
||||
local len = 0
|
||||
|
||||
-- only set l if i or j is negative
|
||||
local l = (i >= 0 and j >= 0) or s:utf8len()
|
||||
local startChar = (i >= 0) and i or l + i + 1
|
||||
local endChar = (j >= 0) and j or l + j + 1
|
||||
|
||||
-- can't have start before end!
|
||||
if startChar > endChar then
|
||||
return ""
|
||||
end
|
||||
|
||||
-- byte offsets to pass to string.sub
|
||||
local startByte, endByte = 1, bytes
|
||||
|
||||
while pos <= bytes do
|
||||
len = len + 1
|
||||
|
||||
if len == startChar then
|
||||
startByte = pos
|
||||
end
|
||||
|
||||
pos = pos + utf8charbytes(s, pos)
|
||||
|
||||
if len == endChar then
|
||||
endByte = pos - 1
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return s:sub(startByte, endByte)
|
||||
end
|
||||
|
||||
-- install in the string library
|
||||
if not string.utf8sub then
|
||||
string.utf8sub = utf8sub
|
||||
end
|
||||
|
||||
|
||||
-- replace UTF-8 characters based on a mapping table
|
||||
local function utf8replace (s, mapping)
|
||||
-- argument checking
|
||||
if not isstring(s) then
|
||||
error("bad argument #1 to 'utf8replace' (string expected, got ".. type(s).. ")")
|
||||
end
|
||||
if not istable(mapping) then
|
||||
error("bad argument #2 to 'utf8replace' (table expected, got ".. type(mapping).. ")")
|
||||
end
|
||||
|
||||
local pos = 1
|
||||
local bytes = s:len()
|
||||
local charbytes
|
||||
local newstr = ""
|
||||
|
||||
while pos <= bytes do
|
||||
charbytes = utf8charbytes(s, pos)
|
||||
local c = s:sub(pos, pos + charbytes - 1)
|
||||
|
||||
newstr = newstr .. (mapping[c] or c)
|
||||
|
||||
pos = pos + charbytes
|
||||
end
|
||||
|
||||
return newstr
|
||||
end
|
||||
|
||||
|
||||
-- identical to string.upper except it knows about unicode simple case conversions
|
||||
local function utf8upper (s)
|
||||
return utf8replace(s, utf8_lc_uc)
|
||||
end
|
||||
|
||||
-- install in the string library
|
||||
if not string.utf8upper and utf8_lc_uc then
|
||||
string.utf8upper = utf8upper
|
||||
end
|
||||
|
||||
|
||||
-- identical to string.lower except it knows about unicode simple case conversions
|
||||
local function utf8lower (s)
|
||||
return utf8replace(s, utf8_uc_lc)
|
||||
end
|
||||
|
||||
-- install in the string library
|
||||
if not string.utf8lower and utf8_uc_lc then
|
||||
string.utf8lower = utf8lower
|
||||
end
|
||||
|
||||
|
||||
-- identical to string.reverse except that it supports UTF-8
|
||||
local function utf8reverse (s)
|
||||
-- argument checking
|
||||
if not isstring(s) then
|
||||
error("bad argument #1 to 'utf8reverse' (string expected, got ".. type(s).. ")")
|
||||
end
|
||||
|
||||
local bytes = s:len()
|
||||
local pos = bytes
|
||||
local charbytes
|
||||
local newstr = ""
|
||||
|
||||
while pos > 0 do
|
||||
c = s:byte(pos)
|
||||
while c >= 128 and c <= 191 do
|
||||
pos = pos - 1
|
||||
c = s:byte(pos)
|
||||
end
|
||||
|
||||
charbytes = utf8charbytes(s, pos)
|
||||
|
||||
newstr = newstr .. s:sub(pos, pos + charbytes - 1)
|
||||
|
||||
pos = pos - 1
|
||||
end
|
||||
|
||||
return newstr
|
||||
end
|
||||
|
||||
-- install in the string library
|
||||
if not string.utf8reverse then
|
||||
string.utf8reverse = utf8reverse
|
||||
end
|
||||
615
gamemodes/helix/gamemode/core/libs/thirdparty/sh_yaml.lua
vendored
Normal file
615
gamemodes/helix/gamemode/core/libs/thirdparty/sh_yaml.lua
vendored
Normal file
@@ -0,0 +1,615 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
--[[
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2017 Dominic Letz dominicletz@exosite.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
--]]
|
||||
|
||||
local table_print_value
|
||||
table_print_value = function(value, indent, done)
|
||||
indent = indent or 0
|
||||
done = done or {}
|
||||
if istable(value) and not done [value] then
|
||||
done [value] = true
|
||||
|
||||
local list = {}
|
||||
for key in pairs (value) do
|
||||
list[#list + 1] = key
|
||||
end
|
||||
table.sort(list, function(a, b) return tostring(a) < tostring(b) end)
|
||||
local last = list[#list]
|
||||
|
||||
local rep = "{\n"
|
||||
local comma
|
||||
for _, key in ipairs (list) do
|
||||
if key == last then
|
||||
comma = ''
|
||||
else
|
||||
comma = ','
|
||||
end
|
||||
local keyRep
|
||||
if isnumber(key) then
|
||||
keyRep = key
|
||||
else
|
||||
keyRep = string.format("%q", tostring(key))
|
||||
end
|
||||
rep = rep .. string.format(
|
||||
"%s[%s] = %s%s\n",
|
||||
string.rep(" ", indent + 2),
|
||||
keyRep,
|
||||
table_print_value(value[key], indent + 2, done),
|
||||
comma
|
||||
)
|
||||
end
|
||||
|
||||
rep = rep .. string.rep(" ", indent) -- indent it
|
||||
rep = rep .. "}"
|
||||
|
||||
done[value] = false
|
||||
return rep
|
||||
elseif isstring(value) then
|
||||
return string.format("%q", value)
|
||||
else
|
||||
return tostring(value)
|
||||
end
|
||||
end
|
||||
|
||||
local table_print = function(tt)
|
||||
print('return '..table_print_value(tt))
|
||||
end
|
||||
|
||||
local table_clone = function(t)
|
||||
local clone = {}
|
||||
for k,v in pairs(t) do
|
||||
clone[k] = v
|
||||
end
|
||||
return clone
|
||||
end
|
||||
|
||||
local string_trim = function(s, what)
|
||||
what = what or " "
|
||||
return s:gsub("^[" .. what .. "]*(.-)["..what.."]*$", "%1")
|
||||
end
|
||||
|
||||
local push = function(stack, item)
|
||||
stack[#stack + 1] = item
|
||||
end
|
||||
|
||||
local pop = function(stack)
|
||||
local item = stack[#stack]
|
||||
stack[#stack] = nil
|
||||
return item
|
||||
end
|
||||
|
||||
local context = function (str)
|
||||
if not isstring(str) then
|
||||
return ""
|
||||
end
|
||||
|
||||
str = str:sub(0,25):gsub("\n","\\n"):gsub("\"","\\\"");
|
||||
return ", near \"" .. str .. "\""
|
||||
end
|
||||
|
||||
local Parser = {}
|
||||
function Parser.new (self, tokens)
|
||||
self.tokens = tokens
|
||||
self.parse_stack = {}
|
||||
self.refs = {}
|
||||
self.current = 0
|
||||
return self
|
||||
end
|
||||
|
||||
local exports = {version = "1.2"}
|
||||
|
||||
local word = function(w) return "^("..w..")([%s$%c])" end
|
||||
|
||||
local tokens = {
|
||||
{"comment", "^#[^\n]*"},
|
||||
{"indent", "^\n( *)"},
|
||||
{"space", "^ +"},
|
||||
{"true", word("enabled"), const = true, value = true},
|
||||
{"true", word("true"), const = true, value = true},
|
||||
{"true", word("yes"), const = true, value = true},
|
||||
{"true", word("on"), const = true, value = true},
|
||||
{"false", word("disabled"), const = true, value = false},
|
||||
{"false", word("false"), const = true, value = false},
|
||||
{"false", word("no"), const = true, value = false},
|
||||
{"false", word("off"), const = true, value = false},
|
||||
{"null", word("null"), const = true, value = nil},
|
||||
{"null", word("Null"), const = true, value = nil},
|
||||
{"null", word("NULL"), const = true, value = nil},
|
||||
{"null", word("~"), const = true, value = nil},
|
||||
{"id", "^\"([^\"]-)\" *(:[%s%c])"},
|
||||
{"id", "^'([^']-)' *(:[%s%c])"},
|
||||
{"string", "^\"([^\"]-)\"", force_text = true},
|
||||
{"string", "^'([^']-)'", force_text = true},
|
||||
{"timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)%s+(%d%d?):(%d%d):(%d%d)%s+(%-?%d%d?):(%d%d)"},
|
||||
{"timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)%s+(%d%d?):(%d%d):(%d%d)%s+(%-?%d%d?)"},
|
||||
{"timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)%s+(%d%d?):(%d%d):(%d%d)"},
|
||||
{"timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)%s+(%d%d?):(%d%d)"},
|
||||
{"timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)%s+(%d%d?)"},
|
||||
{"timestamp", "^(%d%d%d%d)-(%d%d?)-(%d%d?)"},
|
||||
{"doc", "^%-%-%-[^%c]*"},
|
||||
{",", "^,"},
|
||||
{"string", "^%b{} *[^,%c]+", noinline = true},
|
||||
{"{", "^{"},
|
||||
{"}", "^}"},
|
||||
{"string", "^%b[] *[^,%c]+", noinline = true},
|
||||
{"[", "^%["},
|
||||
{"]", "^%]"},
|
||||
{"-", "^%-"},
|
||||
{":", "^:"},
|
||||
{"pipe", "^(|)(%d*[+%-]?)", sep = "\n"},
|
||||
{"pipe", "^(>)(%d*[+%-]?)", sep = " "},
|
||||
{"id", "^([%w][%w %-_]*)(:[%s%c])"},
|
||||
{"string", "^[^%c]+", noinline = true},
|
||||
{"string", "^[^,%c ]+"}
|
||||
};
|
||||
exports.tokenize = function (str)
|
||||
local token
|
||||
local row = 0
|
||||
local ignore
|
||||
local indents = 0
|
||||
local lastIndents
|
||||
local stack = {}
|
||||
local indentAmount = 0
|
||||
local inline = false
|
||||
str = str:gsub("\r\n","\010")
|
||||
|
||||
while #str > 0 do
|
||||
for i in ipairs(tokens) do
|
||||
local captures = {}
|
||||
if not inline or tokens[i].noinline == nil then
|
||||
captures = {str:match(tokens[i][2])}
|
||||
end
|
||||
|
||||
if #captures > 0 then
|
||||
captures.input = str:sub(0, 25)
|
||||
token = table_clone(tokens[i])
|
||||
token[2] = captures
|
||||
local str2 = str:gsub(tokens[i][2], "", 1)
|
||||
token.raw = str:sub(1, #str - #str2)
|
||||
str = str2
|
||||
|
||||
if token[1] == "{" or token[1] == "[" then
|
||||
inline = true
|
||||
elseif token.const then
|
||||
-- Since word pattern contains last char we're re-adding it
|
||||
str = token[2][2] .. str
|
||||
token.raw = token.raw:sub(1, #token.raw - #token[2][2])
|
||||
elseif token[1] == "id" then
|
||||
-- Since id pattern contains last semi-colon we're re-adding it
|
||||
str = token[2][2] .. str
|
||||
token.raw = token.raw:sub(1, #token.raw - #token[2][2])
|
||||
-- Trim
|
||||
token[2][1] = string_trim(token[2][1])
|
||||
elseif token[1] == "string" then
|
||||
-- Finding numbers
|
||||
local snip = token[2][1]
|
||||
if not token.force_text then
|
||||
if snip:match("^(%d+%.%d+)$") or snip:match("^(%d+)$") then
|
||||
token[1] = "number"
|
||||
end
|
||||
end
|
||||
|
||||
elseif token[1] == "comment" then
|
||||
ignore = true;
|
||||
elseif token[1] == "indent" then
|
||||
row = row + 1
|
||||
inline = false
|
||||
lastIndents = indents
|
||||
if indentAmount == 0 then
|
||||
indentAmount = #token[2][1]
|
||||
end
|
||||
|
||||
if indentAmount ~= 0 then
|
||||
indents = (#token[2][1] / indentAmount);
|
||||
else
|
||||
indents = 0
|
||||
end
|
||||
|
||||
if indents == lastIndents then
|
||||
ignore = true;
|
||||
elseif indents > lastIndents + 2 then
|
||||
error("SyntaxError: invalid indentation, got " .. tostring(indents)
|
||||
.. " instead of " .. tostring(lastIndents) .. context(token[2].input))
|
||||
elseif indents > lastIndents + 1 then
|
||||
push(stack, token)
|
||||
elseif indents < lastIndents then
|
||||
local input = token[2].input
|
||||
token = {"dedent", {"", input = ""}}
|
||||
token.input = input
|
||||
while lastIndents > indents + 1 do
|
||||
lastIndents = lastIndents - 1
|
||||
push(stack, token)
|
||||
end
|
||||
end
|
||||
end -- if token[1] == XXX
|
||||
token.row = row
|
||||
break
|
||||
end -- if #captures > 0
|
||||
end
|
||||
|
||||
if not ignore then
|
||||
if token then
|
||||
push(stack, token)
|
||||
token = nil
|
||||
else
|
||||
error("SyntaxError " .. context(str))
|
||||
end
|
||||
end
|
||||
|
||||
ignore = false;
|
||||
end
|
||||
|
||||
return stack
|
||||
end
|
||||
|
||||
Parser.peek = function (self, offset)
|
||||
offset = offset or 1
|
||||
return self.tokens[offset + self.current]
|
||||
end
|
||||
|
||||
Parser.advance = function (self)
|
||||
self.current = self.current + 1
|
||||
return self.tokens[self.current]
|
||||
end
|
||||
|
||||
Parser.advanceValue = function (self)
|
||||
return self:advance()[2][1]
|
||||
end
|
||||
|
||||
Parser.accept = function (self, type)
|
||||
if self:peekType(type) then
|
||||
return self:advance()
|
||||
end
|
||||
end
|
||||
|
||||
Parser.expect = function (self, type, msg)
|
||||
return self:accept(type) or
|
||||
error(msg .. context(self:peek()[1].input))
|
||||
end
|
||||
|
||||
Parser.expectDedent = function (self, msg)
|
||||
return self:accept("dedent") or (self:peek() == nil) or
|
||||
error(msg .. context(self:peek()[2].input))
|
||||
end
|
||||
|
||||
Parser.peekType = function (self, val, offset)
|
||||
return self:peek(offset) and self:peek(offset)[1] == val
|
||||
end
|
||||
|
||||
Parser.ignore = function (self, items)
|
||||
local advanced
|
||||
repeat
|
||||
advanced = false
|
||||
for _,v in pairs(items) do
|
||||
if self:peekType(v) then
|
||||
self:advance()
|
||||
advanced = true
|
||||
end
|
||||
end
|
||||
until advanced == false
|
||||
end
|
||||
|
||||
Parser.ignoreSpace = function (self)
|
||||
self:ignore{"space"}
|
||||
end
|
||||
|
||||
Parser.ignoreWhitespace = function (self)
|
||||
self:ignore{"space", "indent", "dedent"}
|
||||
end
|
||||
|
||||
Parser.parse = function (self)
|
||||
|
||||
local ref = nil
|
||||
if self:peekType("string") and not self:peek().force_text then
|
||||
local char = self:peek()[2][1]:sub(1,1)
|
||||
if char == "&" then
|
||||
ref = self:peek()[2][1]:sub(2)
|
||||
self:advanceValue()
|
||||
self:ignoreSpace()
|
||||
elseif char == "*" then
|
||||
ref = self:peek()[2][1]:sub(2)
|
||||
return self.refs[ref]
|
||||
end
|
||||
end
|
||||
|
||||
local result
|
||||
local c = {
|
||||
indent = self:accept("indent") and 1 or 0,
|
||||
token = self:peek()
|
||||
}
|
||||
push(self.parse_stack, c)
|
||||
|
||||
if c.token[1] == "doc" then
|
||||
result = self:parseDoc()
|
||||
elseif c.token[1] == "-" then
|
||||
result = self:parseList()
|
||||
elseif c.token[1] == "{" then
|
||||
result = self:parseInlineHash()
|
||||
elseif c.token[1] == "[" then
|
||||
result = self:parseInlineList()
|
||||
elseif c.token[1] == "id" then
|
||||
result = self:parseHash()
|
||||
elseif c.token[1] == "string" then
|
||||
result = self:parseString("\n")
|
||||
elseif c.token[1] == "timestamp" then
|
||||
result = self:parseTimestamp()
|
||||
elseif c.token[1] == "number" then
|
||||
result = tonumber(self:advanceValue())
|
||||
elseif c.token[1] == "pipe" then
|
||||
result = self:parsePipe()
|
||||
elseif c.token.const == true then
|
||||
self:advanceValue();
|
||||
result = c.token.value
|
||||
else
|
||||
error("ParseError: unexpected token '" .. c.token[1] .. "'" .. context(c.token.input))
|
||||
end
|
||||
|
||||
pop(self.parse_stack)
|
||||
while c.indent > 0 do
|
||||
c.indent = c.indent - 1
|
||||
local term = "term "..c.token[1]..": '"..c.token[2][1].."'"
|
||||
self:expectDedent("last ".. term .." is not properly dedented")
|
||||
end
|
||||
|
||||
if ref then
|
||||
self.refs[ref] = result
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
Parser.parseDoc = function (self)
|
||||
self:accept("doc")
|
||||
return self:parse()
|
||||
end
|
||||
|
||||
Parser.inline = function (self)
|
||||
local current = self:peek(0)
|
||||
if not current then
|
||||
return {}, 0
|
||||
end
|
||||
|
||||
local inline = {}
|
||||
local i = 0
|
||||
|
||||
while self:peek(i) and not self:peekType("indent", i) and current.row == self:peek(i).row do
|
||||
inline[self:peek(i)[1]] = true
|
||||
i = i - 1
|
||||
end
|
||||
return inline, -i
|
||||
end
|
||||
|
||||
Parser.isInline = function (self)
|
||||
local _, i = self:inline()
|
||||
return i > 0
|
||||
end
|
||||
|
||||
Parser.parent = function(self, level)
|
||||
level = level or 1
|
||||
return self.parse_stack[#self.parse_stack - level]
|
||||
end
|
||||
|
||||
Parser.parentType = function(self, type, level)
|
||||
return self:parent(level) and self:parent(level).token[1] == type
|
||||
end
|
||||
|
||||
Parser.parseString = function (self)
|
||||
if self:isInline() then
|
||||
local result = self:advanceValue()
|
||||
|
||||
--[[
|
||||
- a: this looks
|
||||
flowing: but is
|
||||
no: string
|
||||
--]]
|
||||
local types = self:inline()
|
||||
if types["id"] and types["-"] then
|
||||
if not self:peekType("indent") or not self:peekType("indent", 2) then
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
a: 1
|
||||
b: this is
|
||||
a flowing string
|
||||
example
|
||||
c: 3
|
||||
--]]
|
||||
if self:peekType("indent") then
|
||||
self:expect("indent", "text block needs to start with indent")
|
||||
local addtl = self:accept("indent")
|
||||
|
||||
result = result .. "\n" .. self:parseTextBlock("\n")
|
||||
|
||||
self:expectDedent("text block ending dedent missing")
|
||||
if addtl then
|
||||
self:expectDedent("text block ending dedent missing")
|
||||
end
|
||||
end
|
||||
return result
|
||||
else
|
||||
--[[
|
||||
a: 1
|
||||
b:
|
||||
this is also
|
||||
a flowing string
|
||||
example
|
||||
c: 3
|
||||
--]]
|
||||
return self:parseTextBlock("\n")
|
||||
end
|
||||
end
|
||||
|
||||
Parser.parsePipe = function (self)
|
||||
local pipe = self:expect("pipe")
|
||||
self:expect("indent", "text block needs to start with indent")
|
||||
local result = self:parseTextBlock(pipe.sep)
|
||||
self:expectDedent("text block ending dedent missing")
|
||||
return result
|
||||
end
|
||||
|
||||
Parser.parseTextBlock = function (self, sep)
|
||||
local token = self:advance()
|
||||
local result = string_trim(token.raw, "\n")
|
||||
local indents = 0
|
||||
while self:peek() ~= nil and ( indents > 0 or not self:peekType("dedent") ) do
|
||||
local newtoken = self:advance()
|
||||
while token.row < newtoken.row do
|
||||
result = result .. sep
|
||||
token.row = token.row + 1
|
||||
end
|
||||
if newtoken[1] == "indent" then
|
||||
indents = indents + 1
|
||||
elseif newtoken[1] == "dedent" then
|
||||
indents = indents - 1
|
||||
else
|
||||
result = result .. string_trim(newtoken.raw, "\n")
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
Parser.parseHash = function (self, hash)
|
||||
hash = hash or {}
|
||||
local indents = 0
|
||||
|
||||
if self:isInline() then
|
||||
local id = self:advanceValue()
|
||||
self:expect(":", "expected semi-colon after id")
|
||||
self:ignoreSpace()
|
||||
if self:accept("indent") then
|
||||
indents = indents + 1
|
||||
hash[id] = self:parse()
|
||||
else
|
||||
hash[id] = self:parse()
|
||||
if self:accept("indent") then
|
||||
indents = indents + 1
|
||||
end
|
||||
end
|
||||
self:ignoreSpace();
|
||||
end
|
||||
|
||||
while self:peekType("id") do
|
||||
local id = self:advanceValue()
|
||||
self:expect(":","expected semi-colon after id")
|
||||
self:ignoreSpace()
|
||||
hash[id] = self:parse()
|
||||
self:ignoreSpace();
|
||||
end
|
||||
|
||||
while indents > 0 do
|
||||
self:expectDedent("expected dedent")
|
||||
indents = indents - 1
|
||||
end
|
||||
|
||||
return hash
|
||||
end
|
||||
|
||||
Parser.parseInlineHash = function (self)
|
||||
local id
|
||||
local hash = {}
|
||||
local i = 0
|
||||
|
||||
self:accept("{")
|
||||
while not self:accept("}") do
|
||||
self:ignoreSpace()
|
||||
if i > 0 then
|
||||
self:expect(",","expected comma")
|
||||
end
|
||||
|
||||
self:ignoreWhitespace()
|
||||
if self:peekType("id") then
|
||||
id = self:advanceValue()
|
||||
if id then
|
||||
self:expect(":","expected semi-colon after id")
|
||||
self:ignoreSpace()
|
||||
hash[id] = self:parse()
|
||||
self:ignoreWhitespace()
|
||||
end
|
||||
end
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
return hash
|
||||
end
|
||||
|
||||
Parser.parseList = function (self)
|
||||
local list = {}
|
||||
while self:accept("-") do
|
||||
self:ignoreSpace()
|
||||
list[#list + 1] = self:parse()
|
||||
|
||||
self:ignoreSpace()
|
||||
end
|
||||
return list
|
||||
end
|
||||
|
||||
Parser.parseInlineList = function (self)
|
||||
local list = {}
|
||||
local i = 0
|
||||
self:accept("[")
|
||||
while not self:accept("]") do
|
||||
self:ignoreSpace()
|
||||
if i > 0 then
|
||||
self:expect(",","expected comma")
|
||||
end
|
||||
|
||||
self:ignoreSpace()
|
||||
list[#list + 1] = self:parse()
|
||||
self:ignoreSpace()
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
return list
|
||||
end
|
||||
|
||||
Parser.parseTimestamp = function (self)
|
||||
local capture = self:advance()[2]
|
||||
|
||||
return os.time{
|
||||
year = capture[1],
|
||||
month = capture[2],
|
||||
day = capture[3],
|
||||
hour = capture[4] or 0,
|
||||
min = capture[5] or 0,
|
||||
sec = capture[6] or 0
|
||||
}
|
||||
end
|
||||
|
||||
exports.Eval = function (str)
|
||||
return Parser:new(exports.tokenize(str)):parse()
|
||||
end
|
||||
|
||||
exports.Read = function(file_name)
|
||||
if file.Exists(file_name, 'GAME') then
|
||||
local local_name = file_name:gsub('%.y([a]?)ml', '.local.y%1ml')
|
||||
|
||||
if file.Exists(local_name, 'GAME') then
|
||||
file_name = local_name
|
||||
end
|
||||
|
||||
return Parser:new(exports.tokenize(file.Read(file_name, 'GAME'))):parse()
|
||||
end
|
||||
end
|
||||
|
||||
exports.Dump = table_print
|
||||
|
||||
ix.yaml = exports
|
||||
663
gamemodes/helix/gamemode/core/libs/thirdparty/sv_mysql.lua
vendored
Normal file
663
gamemodes/helix/gamemode/core/libs/thirdparty/sv_mysql.lua
vendored
Normal file
@@ -0,0 +1,663 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
--[[
|
||||
mysql - 1.0.3
|
||||
A simple MySQL wrapper for Garry's Mod.
|
||||
|
||||
Alexander Grist-Hucker
|
||||
http://www.alexgrist.com
|
||||
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Alex Grist-Hucker
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
--]]
|
||||
|
||||
mysql = mysql or {
|
||||
module = "sqlite"
|
||||
}
|
||||
|
||||
local QueueTable = {}
|
||||
local tostring = tostring
|
||||
local table = table
|
||||
|
||||
--[[
|
||||
Replacement tables
|
||||
--]]
|
||||
|
||||
local Replacements = {
|
||||
sqlite = {
|
||||
Create = {
|
||||
{"UNSIGNED ", ""},
|
||||
{"NOT NULL AUTO_INCREMENT", ""}, -- assuming primary key
|
||||
{"AUTO_INCREMENT", ""},
|
||||
{"INT%(%d*%)", "INTEGER"},
|
||||
{"INT ", "INTEGER"}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
--[[
|
||||
Phrases
|
||||
--]]
|
||||
|
||||
local MODULE_NOT_EXIST = "[mysql] The %s module does not exist!\n"
|
||||
|
||||
--[[
|
||||
Begin Query Class.
|
||||
--]]
|
||||
|
||||
local QUERY_CLASS = {}
|
||||
QUERY_CLASS.__index = QUERY_CLASS
|
||||
|
||||
function QUERY_CLASS:New(tableName, queryType)
|
||||
local newObject = setmetatable({}, QUERY_CLASS)
|
||||
newObject.queryType = queryType
|
||||
newObject.tableName = tableName
|
||||
newObject.selectList = {}
|
||||
newObject.insertList = {}
|
||||
newObject.updateList = {}
|
||||
newObject.createList = {}
|
||||
newObject.whereList = {}
|
||||
newObject.orderByList = {}
|
||||
return newObject
|
||||
end
|
||||
|
||||
function QUERY_CLASS:Escape(text)
|
||||
return mysql:Escape(tostring(text))
|
||||
end
|
||||
|
||||
function QUERY_CLASS:ForTable(tableName)
|
||||
self.tableName = tableName
|
||||
end
|
||||
|
||||
function QUERY_CLASS:Where(key, value)
|
||||
self:WhereEqual(key, value)
|
||||
end
|
||||
|
||||
function QUERY_CLASS:WhereEqual(key, value)
|
||||
self.whereList[#self.whereList + 1] = "`"..key.."` = '"..self:Escape(value).."'"
|
||||
end
|
||||
|
||||
function QUERY_CLASS:WhereNotEqual(key, value)
|
||||
self.whereList[#self.whereList + 1] = "`"..key.."` != '"..self:Escape(value).."'"
|
||||
end
|
||||
|
||||
function QUERY_CLASS:WhereLike(key, value, format)
|
||||
format = format or "%%%s%%"
|
||||
self.whereList[#self.whereList + 1] = "`"..key.."` LIKE '"..string.format(format, self:Escape(value)).."'"
|
||||
end
|
||||
|
||||
function QUERY_CLASS:WhereNotLike(key, value, format)
|
||||
format = format or "%%%s%%"
|
||||
self.whereList[#self.whereList + 1] = "`"..key.."` NOT LIKE '"..string.format(format, self:Escape(value)).."'"
|
||||
end
|
||||
|
||||
function QUERY_CLASS:WhereGT(key, value)
|
||||
self.whereList[#self.whereList + 1] = "`"..key.."` > '"..self:Escape(value).."'"
|
||||
end
|
||||
|
||||
function QUERY_CLASS:WhereLT(key, value)
|
||||
self.whereList[#self.whereList + 1] = "`"..key.."` < '"..self:Escape(value).."'"
|
||||
end
|
||||
|
||||
function QUERY_CLASS:WhereGTE(key, value)
|
||||
self.whereList[#self.whereList + 1] = "`"..key.."` >= '"..self:Escape(value).."'"
|
||||
end
|
||||
|
||||
function QUERY_CLASS:WhereLTE(key, value)
|
||||
self.whereList[#self.whereList + 1] = "`"..key.."` <= '"..self:Escape(value).."'"
|
||||
end
|
||||
|
||||
function QUERY_CLASS:WhereIn(key, value)
|
||||
value = istable(value) and value or {value}
|
||||
|
||||
local values = ""
|
||||
local bFirst = true
|
||||
|
||||
for k, v in pairs(value) do
|
||||
values = values .. (bFirst and "" or ", ") .. "'" .. self:Escape(v) .. "'"
|
||||
bFirst = false
|
||||
end
|
||||
|
||||
self.whereList[#self.whereList + 1] = "`"..key.."` IN ("..values..")"
|
||||
end
|
||||
|
||||
function QUERY_CLASS:OrderByDesc(key)
|
||||
self.orderByList[#self.orderByList + 1] = "`"..key.."` DESC"
|
||||
end
|
||||
|
||||
function QUERY_CLASS:OrderByAsc(key)
|
||||
self.orderByList[#self.orderByList + 1] = "`"..key.."` ASC"
|
||||
end
|
||||
|
||||
function QUERY_CLASS:Callback(queryCallback)
|
||||
self.callback = queryCallback
|
||||
end
|
||||
|
||||
function QUERY_CLASS:Select(fieldName)
|
||||
self.selectList[#self.selectList + 1] = "`"..fieldName.."`"
|
||||
end
|
||||
|
||||
function QUERY_CLASS:Insert(key, value)
|
||||
self.insertList[#self.insertList + 1] = {"`"..key.."`", "'"..self:Escape(value).."'"}
|
||||
end
|
||||
|
||||
function QUERY_CLASS:Update(key, value)
|
||||
self.updateList[#self.updateList + 1] = {"`"..key.."`", "'"..self:Escape(value).."'"}
|
||||
end
|
||||
|
||||
function QUERY_CLASS:Create(key, value)
|
||||
self.createList[#self.createList + 1] = {"`"..key.."`", value}
|
||||
end
|
||||
|
||||
function QUERY_CLASS:Add(key, value)
|
||||
self.add = {"`"..key.."`", value}
|
||||
end
|
||||
|
||||
function QUERY_CLASS:Drop(key)
|
||||
self.drop = "`"..key.."`"
|
||||
end
|
||||
|
||||
function QUERY_CLASS:PrimaryKey(key)
|
||||
self.primaryKey = "`"..key.."`"
|
||||
end
|
||||
|
||||
function QUERY_CLASS:Limit(value)
|
||||
self.limit = value
|
||||
end
|
||||
|
||||
function QUERY_CLASS:Offset(value)
|
||||
self.offset = value
|
||||
end
|
||||
|
||||
local function ApplyQueryReplacements(mode, query)
|
||||
if (!Replacements[mysql.module]) then
|
||||
return query
|
||||
end
|
||||
|
||||
local result = query
|
||||
local entries = Replacements[mysql.module][mode]
|
||||
|
||||
for i = 1, #entries do
|
||||
result = string.gsub(result, entries[i][1], entries[i][2])
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
local function BuildSelectQuery(queryObj)
|
||||
local queryString = {"SELECT"}
|
||||
|
||||
if (!istable(queryObj.selectList) or #queryObj.selectList == 0) then
|
||||
queryString[#queryString + 1] = " *"
|
||||
else
|
||||
queryString[#queryString + 1] = " "..table.concat(queryObj.selectList, ", ")
|
||||
end
|
||||
|
||||
if (isstring(queryObj.tableName)) then
|
||||
queryString[#queryString + 1] = " FROM `"..queryObj.tableName.."` "
|
||||
else
|
||||
ErrorNoHalt("[mysql] No table name specified!\n")
|
||||
return
|
||||
end
|
||||
|
||||
if (istable(queryObj.whereList) and #queryObj.whereList > 0) then
|
||||
queryString[#queryString + 1] = " WHERE "
|
||||
queryString[#queryString + 1] = table.concat(queryObj.whereList, " AND ")
|
||||
end
|
||||
|
||||
if (istable(queryObj.orderByList) and #queryObj.orderByList > 0) then
|
||||
queryString[#queryString + 1] = " ORDER BY "
|
||||
queryString[#queryString + 1] = table.concat(queryObj.orderByList, ", ")
|
||||
end
|
||||
|
||||
if (isnumber(queryObj.limit)) then
|
||||
queryString[#queryString + 1] = " LIMIT "
|
||||
queryString[#queryString + 1] = queryObj.limit
|
||||
|
||||
if (isnumber(queryObj.offset)) then
|
||||
queryString[#queryString + 1] = " OFFSET "
|
||||
queryString[#queryString + 1] = queryObj.offset
|
||||
end
|
||||
end
|
||||
|
||||
return table.concat(queryString)
|
||||
end
|
||||
|
||||
local function BuildInsertQuery(queryObj, bIgnore)
|
||||
local suffix = (bIgnore and (mysql.module == "sqlite" and "INSERT OR IGNORE INTO" or "INSERT IGNORE INTO") or "INSERT INTO")
|
||||
local queryString = {suffix}
|
||||
local keyList = {}
|
||||
local valueList = {}
|
||||
|
||||
if (isstring(queryObj.tableName)) then
|
||||
queryString[#queryString + 1] = " `"..queryObj.tableName.."`"
|
||||
else
|
||||
ErrorNoHalt("[mysql] No table name specified!\n")
|
||||
return
|
||||
end
|
||||
|
||||
for i = 1, #queryObj.insertList do
|
||||
keyList[#keyList + 1] = queryObj.insertList[i][1]
|
||||
valueList[#valueList + 1] = queryObj.insertList[i][2]
|
||||
end
|
||||
|
||||
if (#keyList == 0) then
|
||||
return
|
||||
end
|
||||
|
||||
queryString[#queryString + 1] = " ("..table.concat(keyList, ", ")..")"
|
||||
queryString[#queryString + 1] = " VALUES ("..table.concat(valueList, ", ")..")"
|
||||
|
||||
return table.concat(queryString)
|
||||
end
|
||||
|
||||
local function BuildUpdateQuery(queryObj)
|
||||
local queryString = {"UPDATE"}
|
||||
|
||||
if (isstring(queryObj.tableName)) then
|
||||
queryString[#queryString + 1] = " `"..queryObj.tableName.."`"
|
||||
else
|
||||
ErrorNoHalt("[mysql] No table name specified!\n")
|
||||
return
|
||||
end
|
||||
|
||||
if (istable(queryObj.updateList) and #queryObj.updateList > 0) then
|
||||
local updateList = {}
|
||||
|
||||
queryString[#queryString + 1] = " SET"
|
||||
|
||||
for i = 1, #queryObj.updateList do
|
||||
updateList[#updateList + 1] = queryObj.updateList[i][1].." = "..queryObj.updateList[i][2]
|
||||
end
|
||||
|
||||
queryString[#queryString + 1] = " "..table.concat(updateList, ", ")
|
||||
end
|
||||
|
||||
if (istable(queryObj.whereList) and #queryObj.whereList > 0) then
|
||||
queryString[#queryString + 1] = " WHERE "
|
||||
queryString[#queryString + 1] = table.concat(queryObj.whereList, " AND ")
|
||||
end
|
||||
|
||||
if (isnumber(queryObj.offset)) then
|
||||
queryString[#queryString + 1] = " OFFSET "
|
||||
queryString[#queryString + 1] = queryObj.offset
|
||||
end
|
||||
|
||||
return table.concat(queryString)
|
||||
end
|
||||
|
||||
local function BuildDeleteQuery(queryObj)
|
||||
local queryString = {"DELETE FROM"}
|
||||
|
||||
if (isstring(queryObj.tableName)) then
|
||||
queryString[#queryString + 1] = " `"..queryObj.tableName.."`"
|
||||
else
|
||||
ErrorNoHalt("[mysql] No table name specified!\n")
|
||||
return
|
||||
end
|
||||
|
||||
if (istable(queryObj.whereList) and #queryObj.whereList > 0) then
|
||||
queryString[#queryString + 1] = " WHERE "
|
||||
queryString[#queryString + 1] = table.concat(queryObj.whereList, " AND ")
|
||||
end
|
||||
|
||||
if (isnumber(queryObj.limit)) then
|
||||
queryString[#queryString + 1] = " LIMIT "
|
||||
queryString[#queryString + 1] = queryObj.limit
|
||||
end
|
||||
|
||||
return table.concat(queryString)
|
||||
end
|
||||
|
||||
local function BuildDropQuery(queryObj)
|
||||
local queryString = {"DROP TABLE"}
|
||||
|
||||
if (isstring(queryObj.tableName)) then
|
||||
queryString[#queryString + 1] = " `"..queryObj.tableName.."`"
|
||||
else
|
||||
ErrorNoHalt("[mysql] No table name specified!\n")
|
||||
return
|
||||
end
|
||||
|
||||
return table.concat(queryString)
|
||||
end
|
||||
|
||||
local function BuildTruncateQuery(queryObj)
|
||||
local queryString = {"TRUNCATE TABLE"}
|
||||
|
||||
if (isstring(queryObj.tableName)) then
|
||||
queryString[#queryString + 1] = " `"..queryObj.tableName.."`"
|
||||
else
|
||||
ErrorNoHalt("[mysql] No table name specified!\n")
|
||||
return
|
||||
end
|
||||
|
||||
return table.concat(queryString)
|
||||
end
|
||||
|
||||
local function BuildCreateQuery(queryObj)
|
||||
local queryString = {"CREATE TABLE IF NOT EXISTS"}
|
||||
|
||||
if (isstring(queryObj.tableName)) then
|
||||
queryString[#queryString + 1] = " `"..queryObj.tableName.."`"
|
||||
else
|
||||
ErrorNoHalt("[mysql] No table name specified!\n")
|
||||
return
|
||||
end
|
||||
|
||||
queryString[#queryString + 1] = " ("
|
||||
|
||||
if (istable(queryObj.createList) and #queryObj.createList > 0) then
|
||||
local createList = {}
|
||||
|
||||
for i = 1, #queryObj.createList do
|
||||
if (mysql.module == "sqlite") then
|
||||
createList[#createList + 1] = queryObj.createList[i][1].." "..ApplyQueryReplacements("Create", queryObj.createList[i][2])
|
||||
else
|
||||
createList[#createList + 1] = queryObj.createList[i][1].." "..queryObj.createList[i][2]
|
||||
end
|
||||
end
|
||||
|
||||
queryString[#queryString + 1] = " "..table.concat(createList, ", ")
|
||||
end
|
||||
|
||||
if (isstring(queryObj.primaryKey)) then
|
||||
queryString[#queryString + 1] = ", PRIMARY KEY"
|
||||
queryString[#queryString + 1] = " ("..queryObj.primaryKey..")"
|
||||
end
|
||||
|
||||
queryString[#queryString + 1] = " )"
|
||||
|
||||
return table.concat(queryString)
|
||||
end
|
||||
|
||||
local function BuildAlterQuery(queryObj)
|
||||
local queryString = {"ALTER TABLE"}
|
||||
|
||||
if (isstring(queryObj.tableName)) then
|
||||
queryString[#queryString + 1] = " `"..queryObj.tableName.."`"
|
||||
else
|
||||
ErrorNoHalt("[mysql] No table name specified!\n")
|
||||
return
|
||||
end
|
||||
|
||||
if (istable(queryObj.add)) then
|
||||
queryString[#queryString + 1] = " ADD "..queryObj.add[1].." "..ApplyQueryReplacements("Create", queryObj.add[2])
|
||||
elseif (isstring(queryObj.drop)) then
|
||||
if (mysql.module == "sqlite") then
|
||||
ErrorNoHalt("[mysql] Cannot drop columns in sqlite!\n")
|
||||
return
|
||||
end
|
||||
|
||||
queryString[#queryString + 1] = " DROP COLUMN "..queryObj.drop
|
||||
end
|
||||
|
||||
return table.concat(queryString)
|
||||
end
|
||||
|
||||
function QUERY_CLASS:Execute(bQueueQuery)
|
||||
local queryString = nil
|
||||
local queryType = string.lower(self.queryType)
|
||||
|
||||
if (queryType == "select") then
|
||||
queryString = BuildSelectQuery(self)
|
||||
elseif (queryType == "insert") then
|
||||
queryString = BuildInsertQuery(self)
|
||||
elseif (queryType == "insert ignore") then
|
||||
queryString = BuildInsertQuery(self, true)
|
||||
elseif (queryType == "update") then
|
||||
queryString = BuildUpdateQuery(self)
|
||||
elseif (queryType == "delete") then
|
||||
queryString = BuildDeleteQuery(self)
|
||||
elseif (queryType == "drop") then
|
||||
queryString = BuildDropQuery(self)
|
||||
elseif (queryType == "truncate") then
|
||||
queryString = BuildTruncateQuery(self)
|
||||
elseif (queryType == "create") then
|
||||
queryString = BuildCreateQuery(self)
|
||||
elseif (queryType == "alter") then
|
||||
queryString = BuildAlterQuery(self)
|
||||
end
|
||||
|
||||
if (isstring(queryString)) then
|
||||
if (!bQueueQuery) then
|
||||
return mysql:RawQuery(queryString, self.callback)
|
||||
else
|
||||
return mysql:Queue(queryString, self.callback)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
End Query Class.
|
||||
--]]
|
||||
|
||||
function mysql:Select(tableName)
|
||||
return QUERY_CLASS:New(tableName, "SELECT")
|
||||
end
|
||||
|
||||
function mysql:Insert(tableName)
|
||||
return QUERY_CLASS:New(tableName, "INSERT")
|
||||
end
|
||||
|
||||
function mysql:InsertIgnore(tableName)
|
||||
return QUERY_CLASS:New(tableName, "INSERT IGNORE")
|
||||
end
|
||||
|
||||
function mysql:Update(tableName)
|
||||
return QUERY_CLASS:New(tableName, "UPDATE")
|
||||
end
|
||||
|
||||
function mysql:Delete(tableName)
|
||||
return QUERY_CLASS:New(tableName, "DELETE")
|
||||
end
|
||||
|
||||
function mysql:Drop(tableName)
|
||||
return QUERY_CLASS:New(tableName, "DROP")
|
||||
end
|
||||
|
||||
function mysql:Truncate(tableName)
|
||||
return QUERY_CLASS:New(tableName, "TRUNCATE")
|
||||
end
|
||||
|
||||
function mysql:Create(tableName)
|
||||
return QUERY_CLASS:New(tableName, "CREATE")
|
||||
end
|
||||
|
||||
function mysql:Alter(tableName)
|
||||
return QUERY_CLASS:New(tableName, "ALTER")
|
||||
end
|
||||
|
||||
local UTF8MB4 = "ALTER DATABASE %s CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci"
|
||||
|
||||
-- A function to connect to the MySQL database.
|
||||
function mysql:Connect(host, username, password, database, port, socket, flags)
|
||||
port = port or 3306
|
||||
|
||||
if (self.module == "mysqloo") then
|
||||
if (!istable(mysqloo)) then
|
||||
require("mysqloo")
|
||||
end
|
||||
|
||||
if (mysqloo) then
|
||||
if (self.connection and self.connection:ping()) then
|
||||
return
|
||||
end
|
||||
|
||||
local clientFlag = flags or 0
|
||||
|
||||
if (!isstring(socket)) then
|
||||
self.connection = mysqloo.connect(host, username, password, database, port)
|
||||
else
|
||||
self.connection = mysqloo.connect(host, username, password, database, port, socket, clientFlag)
|
||||
end
|
||||
|
||||
self.connection.onConnected = function(connection)
|
||||
local success, error_message = connection:setCharacterSet("utf8mb4")
|
||||
|
||||
if (!success) then
|
||||
ErrorNoHalt("Failed to set MySQL encoding!\n")
|
||||
ErrorNoHalt(error_message .. "\n")
|
||||
else
|
||||
self:RawQuery(string.format(UTF8MB4, database))
|
||||
end
|
||||
|
||||
mysql:OnConnected()
|
||||
end
|
||||
|
||||
self.connection.onConnectionFailed = function(database, errorText)
|
||||
mysql:OnConnectionFailed(errorText)
|
||||
end
|
||||
|
||||
self.connection:connect()
|
||||
|
||||
timer.Create("mysql.KeepAlive", 300, 0, function()
|
||||
self.connection:ping()
|
||||
end)
|
||||
else
|
||||
ErrorNoHalt(string.format(MODULE_NOT_EXIST, self.module))
|
||||
end
|
||||
elseif (self.module == "sqlite") then
|
||||
timer.Simple(0, function()
|
||||
mysql:OnConnected()
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- A function to query the MySQL database.
|
||||
function mysql:RawQuery(query, callback, flags, ...)
|
||||
if (self.module == "mysqloo") then
|
||||
local queryObj = self.connection:query(query)
|
||||
|
||||
queryObj:setOption(mysqloo.OPTION_NAMED_FIELDS)
|
||||
|
||||
queryObj.onSuccess = function(queryObj, result)
|
||||
if (callback) then
|
||||
local bStatus, value = pcall(callback, result, true, tonumber(queryObj:lastInsert()))
|
||||
|
||||
if (!bStatus) then
|
||||
error(string.format("[mysql] MySQL Callback Error!\n%s\n", value))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
queryObj.onError = function(queryObj, errorText)
|
||||
ErrorNoHalt(string.format("[mysql] MySQL Query Error!\nQuery: %s\n%s\n", query, errorText))
|
||||
end
|
||||
|
||||
queryObj:start()
|
||||
elseif (self.module == "sqlite") then
|
||||
local result = sql.Query(query)
|
||||
|
||||
if (result == false) then
|
||||
error(string.format("[mysql] SQL Query Error!\nQuery: %s\n%s\n", query, sql.LastError()))
|
||||
else
|
||||
if (callback) then
|
||||
local bStatus, value = pcall(callback, result, true, tonumber(sql.QueryValue("SELECT last_insert_rowid()")))
|
||||
|
||||
if (!bStatus) then
|
||||
error(string.format("[mysql] SQL Callback Error!\n%s\n", value))
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
ErrorNoHalt(string.format("[mysql] Unsupported module \"%s\"!\n", self.module))
|
||||
end
|
||||
end
|
||||
|
||||
-- A function to add a query to the queue.
|
||||
function mysql:Queue(queryString, callback)
|
||||
if (isstring(queryString)) then
|
||||
QueueTable[#QueueTable + 1] = {queryString, callback}
|
||||
end
|
||||
end
|
||||
|
||||
-- A function to escape a string for MySQL.
|
||||
function mysql:Escape(text)
|
||||
if (self.connection) then
|
||||
if (self.module == "mysqloo") then
|
||||
return self.connection:escape(text)
|
||||
end
|
||||
else
|
||||
return sql.SQLStr(text, true)
|
||||
end
|
||||
end
|
||||
|
||||
-- A function to disconnect from the MySQL database.
|
||||
function mysql:Disconnect()
|
||||
if (self.connection) then
|
||||
if (self.module == "mysqloo") then
|
||||
self.connection:disconnect(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mysql:Think()
|
||||
if (#QueueTable > 0) then
|
||||
if (istable(QueueTable[1])) then
|
||||
local queueObj = QueueTable[1]
|
||||
local queryString = queueObj[1]
|
||||
local callback = queueObj[2]
|
||||
|
||||
if (isstring(queryString)) then
|
||||
self:RawQuery(queryString, callback)
|
||||
end
|
||||
|
||||
table.remove(QueueTable, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- A function to set the module that should be used.
|
||||
function mysql:SetModule(moduleName)
|
||||
self.module = moduleName
|
||||
end
|
||||
|
||||
-- Called when the database connects sucessfully.
|
||||
function mysql:OnConnected()
|
||||
MsgC(Color(25, 235, 25), "[mysql] Connected to the database!\n")
|
||||
|
||||
hook.Run("DatabaseConnected")
|
||||
end
|
||||
|
||||
-- Called when the database connection fails.
|
||||
function mysql:OnConnectionFailed(errorText)
|
||||
ErrorNoHalt(string.format("[mysql] Unable to connect to the database!\n%s\n", errorText))
|
||||
|
||||
hook.Run("DatabaseConnectionFailed", errorText)
|
||||
end
|
||||
|
||||
-- A function to check whether or not the module is connected to a database.
|
||||
function mysql:IsConnected()
|
||||
return self.module == "mysqloo" and (self.connection and self.connection:ping()) or self.module == "sqlite"
|
||||
end
|
||||
|
||||
return mysql
|
||||
Reference in New Issue
Block a user