Pointshop2 = KInventory --mean hack to share databases, Pointshop2 = {} --[[ Pointshop2 Main file, last modifed on 19.01.2018, Revision {{ user_id }} --]] --Find all registered items that use the pointshop base function Pointshop2.GetRegisteredItems( ) local pointshopItems = {} for className, itemClass in pairs( KInventory.Items ) do if subclassOf( KInventory.Items.base_pointshop_item, itemClass ) then if itemClass.isBase then continue end table.insert( pointshopItems, itemClass ) end end return pointshopItems end function Pointshop2.GetItemClassByName( name ) return KInventory.Items[name] end --[[ Warning: convenience function to be used with care. Item names are NOT unique! ]]-- function Pointshop2.GetItemClassByPrintName( name ) local itemClass for _, class in pairs( KInventory.Items ) do if string.lower( class:GetPrintName( ) ) == string.lower( name ) then itemClass = class break end end return itemClass end --[[ hookName = { item1, item2, item3 } ]]-- Pointshop2.ITEM_HOOK_LOOKUP = {} local ITEM_HOOK_LOOKUP = Pointshop2.ITEM_HOOK_LOOKUP -- Called when the item is equipped function Pointshop2.ActivateItemHooks(item) local class = item.class local hookNames = {} repeat local registeredHooks = class.static._registeredHooks or {} for hookName, _ in pairs(registeredHooks) do hookNames[hookName] = true end class = class.super until class == Object for hookName, _true in pairs(hookNames) do ITEM_HOOK_LOOKUP[hookName] = ITEM_HOOK_LOOKUP[hookName] or {} if not table.HasValue(ITEM_HOOK_LOOKUP[hookName], item) then table.insert(ITEM_HOOK_LOOKUP[hookName], item) end end end function Pointshop2.DeactivateItemHooks(item) for hookName, tbl in pairs( ITEM_HOOK_LOOKUP ) do ITEM_HOOK_LOOKUP[hookName] = LibK._.filter( tbl, function( _item ) return _item != item end ) end end --[[ The hook specified in name is called for every item that is equipped by a player. Arguments are passed unmodified and unfiltered. ]]-- Pointshop2.ITEM_HOOK_REGISTRY = { } function Pointshop2.AddItemHook( hookName, itemClass ) if itemClass.name == "DummyClass" then return end itemClass.static._registeredHooks = itemClass.static._registeredHooks or {} itemClass.static._registeredHooks[hookName] = true hook.Add(hookName, "PS2_ItemHooks_" .. hookName, function(...) local itemsForThisHook = ITEM_HOOK_LOOKUP[hookName] or {} local toRemove = {} for k, item in ipairs(itemsForThisHook) do -- Owner of the item has disconnected, remove the item from the hook lookup if not IsValid(item:GetOwner()) then toRemove[item] = true continue end if item[hookName] then item[hookName](item, ...) end end if #toRemove > 0 then -- Remove items with invalid owners ITEM_HOOK_LOOKUP[hookName] = LibK._.filter(itemsForThisHook, function(item) return not toRemove[item] end) end end) end function Pointshop2.LoadPersistentItem( persistentItem ) if not persistentItem then debug.Trace( ) end local baseClass = Pointshop2.GetItemClassByName( persistentItem.ItemPersistence.baseClass ) if not baseClass then KLogf( 2, "[WARN] Invalid base class %s", persistentItem.ItemPersistence.baseClass ) debug.Trace( ) return end local className = tostring( persistentItem.ItemPersistence.id ) local internalName = "KInventory.Items." .. className KInventory.Items[className] = class( internalName, baseClass ) KInventory.Items[className].static.className = className KInventory.Items[className].static.originFilePath = "Pointshop2_Generated" KInventory.Items[className].static._persistenceId = persistentItem.id KInventory.Items[className].static.isBase = false baseClass.generateFromPersistence( KInventory.Items[className], persistentItem ) KLogf( 4, " -> Loaded persistent item %s", className ) return KInventory.Items[className] end --Get all item classes that were dynamically created from mysql function Pointshop2.GetPersistentItems( ) local persistent = {} for k, v in pairs( Pointshop2.GetRegisteredItems( ) ) do if v.originFilePath == "Pointshop2_Generated" then table.insert( persistent, v ) end end return persistent end function Pointshop2.GetCreatorControlForClass( itemClass ) local base = itemClass.super.className for _, mod in pairs( Pointshop2.Modules ) do for _, itemInfo in pairs( mod.Blueprints ) do if itemInfo.base == base then return itemInfo.creator, itemInfo.noModal end end end end function Pointshop2.GetPersistenceClassForItemClass( itemClass ) local baseClass = itemClass while baseClass do if baseClass.getPersistence( ) then return baseClass.getPersistence( ) end baseClass = baseClass.super end end if SERVER then function Pointshop2.GetSlotContainingItemId( ply, itemId ) local slot for k, v in pairs( ply.PS2_Slots ) do if v.itemId == itemId then slot = v end end return slot end end function Pointshop2.GetItemInSlot( ply, slotName ) if not ply.PS2_Slots then return nil end if CLIENT then return ply.PS2_Slots[slotName] end for _, slot in pairs( ply.PS2_Slots ) do if slot.itemId then return KInventory.ITEMS[slot.itemId] end end end function Pointshop2.GetServerById( id ) local servers = Pointshop2.GetSetting("Pointshop 2", "InternalSettings.Servers" ) for k, v in pairs( servers ) do if v.id == id then return v end end end function Pointshop2.GetServerIpAndPort( ) return unpack( string.Split( game.GetIPAddress(), ":" ) ) end function Pointshop2.CalculateServerHash( ) local ip, port = Pointshop2.GetServerIpAndPort( ) return util.CRC( ip .. port ) end local serverId function Pointshop2.GetCurrentServerId( ) if not serverId then serverId = Pointshop2.GetSetting( "Pointshop 2", "InternalSettings.ServerId" ) end return serverId end Pointshop2.GamemodeModules = {} function Pointshop2.NotifyGamemodeModuleLoaded( gamemodeName, mod ) Pointshop2.GamemodeModules[gamemodeName] = mod end function Pointshop2.IsCurrentGamemodePluginPresent( ) return Pointshop2.GetCurrentGamemodePlugin( ) != nil end function Pointshop2.GetCurrentGamemodePlugin( ) return Pointshop2.GamemodeModules[engine.ActiveGamemode( )] end function Pointshop2.GetCategoryByName( name ) local categories, mappings if CLIENT then categories, mappings = Pointshop2View:getInstance( ).itemCategories, Pointshop2View:getInstance( ).itemMappings else categories, mappings = Pointshop2Controller:getInstance( ).itemCategories, Pointshop2Controller:getInstance( ).itemMappings end local category for k, v in pairs( categories ) do if v.label == name then category = table.Copy( v ) break end end if not category then return false end category.items = {} --Populate with item mappings for k, v in pairs( mappings ) do if v.categoryId == category.id then table.insert( category.items, Pointshop2.GetItemClassByName( v.itemClass ) ) end end return category end --[[ Used to send RPCs on items to client: Allows you to call client functions on items from the server with minimal effort. Should only be called on items that are equipped! ]]-- if SERVER then util.AddNetworkString( "PS2_ItemClientRPC" ) util.AddNetworkString( "PS2_ItemServerRPC" ) function Pointshop2.ItemClientRPC( item, funcName, ... ) net.Start( "PS2_ItemClientRPC" ) net.WriteUInt( item.id, 32 ) net.WriteString( funcName ) net.WriteTable( { ... } ) net.Broadcast( ) end net.Receive( "PS2_ItemServerRPC", function( len, ply ) local itemId = net.ReadUInt( 32 ) local funcName = net.ReadString() local args = net.ReadTable( ) if LibK.Debug then local argsStr = "" for k, v in pairs( args ) do argsStr = argsStr .. tostring( v ) if k < #args then argsStr = argsStr .. ", " end end KLogf( 4, "Pointshop2.ItemServerRPC(%i, %s, %s) len %i", itemId, funcName, argsStr, len ) end local item = KInventory.ITEMS[itemId] if not item then KLogf( 3, "[WARN] Received RPC for uncached item %i", itemId ) return end if item:GetOwner( ) != ply then KLogf( 3, "[WARN] Player %s tried to RPC for other player's item %i", ply:Nick( ), itemId ) return end if not item[funcName] then KLogf( 2, "[ERROR] Invalid RPC Method %s for itemId %s, name %s, class %s, method does not exist", funcName, itemId, item:GetPrintName( ), item.class.className or "" ) return end if not item.class.static.RPCMethods[funcName] then KLogf( 2, "[ERROR] Invalid RPC Method %s for itemId %s, name %s, class %s, method is not whitelisted. Are you using ITEM.static.AllowRPC( funcName )?", funcName, itemId, item:GetPrintName( ), item.class.className or "" ) return end item[funcName]( item, unpack( args ) ) end ) else net.Receive( "PS2_ItemClientRPC", function( len ) local itemId = net.ReadUInt( 32 ) local funcName = net.ReadString() local args = net.ReadTable( ) if LibK.Debug then local argsStr = "" for k, v in pairs( args ) do argsStr = argsStr .. tostring( v ) if k < #args then argsStr = argsStr .. ", " end end KLogf( 4, "Pointshop2.ItemClientRPC(%i, %s, %s) len %i", itemId, funcName, argsStr, len ) end local item = KInventory.ITEMS[itemId] if not item then KLogf( 3, "[WARN] Received RPC for uncached item %i", itemId ) return end if not item[funcName] then KLogf( 3, "[WARN] Received invalid RPC method %s for item %s", funcName, item.class:GetPrintName( ) ) return end item[funcName]( item, unpack( args ) ) end ) function Pointshop2.ItemServerRPC( item, funcName, ... ) net.Start( "PS2_ItemServerRPC" ) net.WriteUInt( item.id, 32 ) net.WriteString( funcName ) net.WriteTable( { ... } ) net.SendToServer( ) end end function Pointshop2.BuildTree( flatStructure, itemMappings ) return Pointshop2.CategoryTree:new( flatStructure, itemMappings ) end --[[ Developer utility Function, prints item names and their classes: 1: Lamp Hat 2: SMG1 ]]-- function Pointshop2.PrintItemClasses() local str = LibK._(Pointshop2.GetRegisteredItems()):chain() :map(function(item) return { className = item.className, name = item:GetPrintName() } end) :sort(function(a, b) if tonumber(a.className) and tonumber(b.className) then return tonumber(a.className) < tonumber(b.className) elseif tonumber(a) and not tonumber(b) then return false else return a.className < b.className end end) :map(function(entry) return entry.className .. ": " .. entry.name end) :join("\n") :value() return str end function Pointshop2.GenerateItemClass( className, baseClassName, moduleName ) if KInventory.Items[className] then LibK.GLib.Error("Class " .. className .. " is already registered with Pointshop 2") end local baseClass = KInventory.Items[baseClassName] if not baseClass then LibK.GLib.Error("Class " .. baseClassName .. " is not registered with Pointshop 2") end local newClass = class( "KInventory.Items" .. className, baseClass ) newClass.static.className = className -- For the error hint when trying to edit it newClass.static.originFilePath = LibK.GLib and LibK.GLib.Lua and ( LibK.GLib.Lua.StackTrace().RawFrames[2].source .. '(' .. moduleName .. ')' ) or moduleName newClass.static.isBase = false newClass.static.UUID = className KInventory.Items[className] = newClass return newClass end