Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- *********************************************
- * Basic Class System for GMod - by thomasfn *
- *********************************************
- sh_class.lua - Loads the core class system
- */
- local CLASS_VERSION = 1.00
- local PULL_DATA = {}
- if (class_sys) then
- if (class_sys.Version >= CLASS_VERSION) then return MsgN( "Not loading class system, already loaded. Version:(Me=" .. CLASS_VERSION .. ",Other=" .. class_sys.Version .. ")" ) end
- PULL_DATA = { class_sys.PullFactories(), class_sys.PullInstances(), class_sys.PullFlags() }
- MsgN( "Reloading class system. Version:(Me=" .. CLASS_VERSION .. ",Other=" .. class_sys.Version .. ")" )
- end
- class_sys = {}
- class_sys.Version = CLASS_VERSION
- local Factories = PULL_DATA[1] or {}
- local Instances = PULL_DATA[2] or {}
- local Flags = PULL_DATA[3] or {}
- for i=1, #Instances do
- Instances[i]._instancepulled = true
- end
- for i=1, #Factories do
- Factories[i]._factorypulled = true
- end
- function class_sys.PullFactories()
- return Factories
- end
- function class_sys.PullInstances()
- return Instances
- end
- function class_sys.PullFlags()
- return Flags
- end
- local function IterateBaseClasses( class, iterator, includehost, ... )
- local base = (includehost and class) or Factories[ class._baseclass ]
- while (base) do
- local result = iterator( class, base, ... )
- if (result) then return result end
- base = Factories[ base._baseclass ]
- end
- end
- local BaseClass = {}
- local function LocateBase_It( class, base, func )
- //print( "LocateBase_It: " .. class._name .. ":" .. base._name .. " {" .. tostring( func ) .. "}" )
- if (base._registry[ func ]) then return base end
- end
- function BaseClass:CallBase( name, ... )
- local origin = debug.getinfo( 2, "f" ).func
- local base = IterateBaseClasses( self, LocateBase_It, true, origin )
- if (base) then base = Factories[ base._baseclass ] end
- if (base) then return base[ name ]( self, ... ) end
- end
- local function GetBaseChain_It( class, base, tbl )
- table.insert( tbl, base )
- end
- function BaseClass:GetBaseChain( includehost )
- local tmp = {}
- IterateBaseClasses( self, GetBaseChain_It, includehost, tmp )
- return tmp
- end
- function BaseClass:CallConstructor( ... )
- local basechain = self:GetBaseChain( true )
- for i=#basechain, 1, -1 do
- local base = basechain[i]
- local constructor = base[ base._subname ]
- if (constructor) then constructor( self, ... ) end
- end
- end
- local function Is_It( class, base, name )
- if (base._name == name) then return true end
- end
- function BaseClass:Is( name )
- return IterateBaseClasses( self, Is_It, true, name ) or false
- end
- function BaseClass:Equals( other )
- return rawequal( self, other )
- end
- function BaseClass:Type()
- return self._name
- end
- local FactoryMeta = {}
- function FactoryMeta.__index( tbl, key )
- local base = Factories[ rawget( tbl, "_baseclass" ) ]
- if (base) then
- return base[ key ]
- else
- return BaseClass[ key ]
- end
- end
- function FactoryMeta.__newindex( tbl, key, val )
- if (type( val ) == "function") then
- local registry = rawget( tbl, "_registry" )
- registry[ val ] = true
- end
- rawset( tbl, key, val )
- end
- local metaGlobal = { __index = _G }
- function class( name, _lvl )
- if (Factories[ name ]) then return error( "Class '" .. name .. "' already exists", 3 ) end
- Instances[ name ] = 0
- local factory = setmetatable( {}, FactoryMeta )
- factory._registry = {}
- factory._name = name
- factory._abstract = false
- factory._static = false
- factory._baseclass = ""
- factory._implements = {}
- factory._class = true
- factory._meta = {}
- function factory._meta.__index( tbl, key )
- if (type( key ) == "number") then
- local idxfunc = factory.Index
- if (idxfunc) then return idxfunc( tbl, key ) end
- end
- return factory[ key ]
- end
- function factory._meta.__eq( tbl, other )
- return tbl:Equals( other )
- end
- function factory._meta.__gc( tbl )
- if (Instances[ name ]) then Instances[ name ] = Instances[ name ] - 1 end
- end
- local subparts = string.Explode( ".", name )
- local subname = subparts[ #subparts ]
- local caller = debug.getinfo( _lvl or 2, "f" ).func
- local env = setmetatable( {}, metaGlobal )
- env[ subname ] = factory
- setfenv( caller, env )
- Factories[ name ] = factory
- factory._subname = subname
- return function( base )
- factory._baseclass = base
- end
- end
- function abstract_class( name, _lvl )
- local func = class( name, _lvl or 3 )
- Factories[ name ]._abstract = true
- Instances[ name ] = nil
- return func
- end
- function wrapper_class( name, base, metatable, validator )
- if (base) then
- class( name )( base )
- else
- class( name )
- end
- local env = getfenv( wrapper_class )
- local c = env[ name ]
- c[ name ] = function( self, obj )
- if (not validator( obj )) then return error( "Object is not valid", 4 ) end
- self.Object = obj
- end
- for key, val in pairs( metatable ) do
- local val = val
- if (type( val ) == "function") then
- c[ key ] = function( self, ... )
- if (not validator( self.Object )) then return error( "Object is not valid", 4 ) end
- return val( self.Object, ... )
- end
- end
- end
- end
- function static_class( name )
- local func = class( name, 3 )
- Factories[ name ]._static = true
- local caller = debug.getinfo( 2, "f" ).func
- local env = getfenv( caller )
- function env.static_finalise()
- Factories[ name ]._static = false
- _G[ name ] = new( name )
- Factories[ name ]._static = true
- Instances[ name ] = nil
- env.static_finalise = nil
- end
- return func
- end
- function new( name, ... )
- local factory = Factories[ name ]
- if (not factory) then return error( "Failed to create instance of class '" .. name .. "' (class not found)", 3 ) end
- if (factory._abstract) then return error( "Failed to create instance of class '" .. name .. "' (class is abstract)", 2 ) end
- if (factory._static) then return error( "Failed to create instance of class '" .. name .. "' (class is static)", 2 ) end
- if (factory._factorypulled) then ErrorNoHalt( "Warning: Class '" .. name .. "' was pulled from a previous version of class_sys.\n" ) end
- local meta = factory._meta
- if ((not meta.inited) and factory.InitMeta) then
- factory.InitMeta( meta )
- meta.inited = true
- end
- local o = setmetatable( {}, meta )
- o:CallConstructor( ... )
- if (o.PostConstructor) then o:PostConstructor() end
- Instances[ name ] = Instances[ name ] + 1
- return o
- end
- function class_flag( name )
- if (Flags[ name ]) then return true end
- Flags[ name ] = true
- return false
- end
- function factory_exists( name )
- return Factories[ name ] ~= nil
- end
- function factory_wipe( name )
- Factories[ name ] = nil
- end
- function ClassMemoryStats()
- return Instances
- end
- if (CLIENT) then
- concommand.Add( "cl_class_stats", function( ply, com, args )
- print( "INSTANCE COUNT" )
- for key, val in pairs( Instances ) do
- print( key .. ": " .. val )
- end
- end )
- end
- if (SERVER) then
- concommand.Add( "sv_class_stats", function( ply, com, args )
- print( "INSTANCE COUNT" )
- for key, val in pairs( Instances ) do
- print( key .. ": " .. val )
- end
- end )
- end
- function ValidClass( obj, name )
- if (type( obj ) ~= "table") then return false end
- if (name) then
- return obj._class and obj:Is( name )
- else
- return obj._class
- end
- end
- /* DEFAULT CLASSES */
- abstract_class "ICallable"
- function ICallable.InitMeta( meta )
- meta.__call = function( self, ... )
- return self:Call( ... )
- end
- end
- function ICallable:Call() end
- function ICallable:Proxy()
- return function( ... ) return self( ... ) end
- end
- abstract_class "IDetour" ("ICallable")
- function IDetour:IDetour( old, override )
- self.OldFunc = old
- if (override and ValidClass( old, "IDetour" )) then self.OldFunc = old.OldFunc end
- end
- function IDetour:Call( ... )
- local result = self:Func( ... )
- if (result) then
- return result
- else
- return self.OldFunc( ... )
- end
- end
- function IDetour:Func( ... ) end
Advertisement
Add Comment
Please, Sign In to add comment