Pointshop2 documentation¶
Pointshop 2 is the next generation shop system for Garry’s Mod. Its features include:
- Live item editing
- Lua-less creation of items
- Inventory and Item slots
- PAC3 Integration
The official website where you can download Pointshop 2 for free is https://github.com/Kamshak/Pointshop2/
If you need any help setting up Pointshop 2 or you are experiencing some issues you can join official PS2 Discord server at https://discord.gg/N9DmwwX
- DLCs available(some DLCs may not be availible or may not work properly!):
- Boosters: https://github.com/Kamshak/ps2-boosters
- Gambling: https://github.com/Kamshak/ps2-gamble
- Permanent Weapons: https://github.com/Kamshak/ps2-permaweaps
- Crates & Drops: https://github.com/Kamshak/ps2-drops
- Airdrops: https://github.com/Kamshak/ps2_airdrops
- Texthats: https://github.com/Kamshak/ps2-texthat
- Advent Calendar: https://scriptfodder.com/scripts/view/1799
- Masks: https://scriptfodder.com/scripts/view/12
- Achievements: https://scriptfodder.com/scripts/view/11
This is the documentation site for Pointshop 2. You can find guides and explanation of various options here. If you are a developer you will also find detailed instructions for interacting with the script.
Getting Started¶
Installation¶
To install Pointshop2 simply extract the zip you downloaded into the addons folder. This will give you two folders: addons/pointshop2 and addons/libk.
Next install PAC3, the newest version can always be found here. Download and extract the zip, too. This will give you addons/pac3-master.
You also need to add Pointshop 2 content to your server’s workshop collection (see below).
Final structure when everything is installed:
- garrysmod
- addons
- libk
- pac3
- pointshop2
Installing Workshop Content to the Server¶
You need to add the Content Addon to you server’s workshop collection for PS2 to work.
If you have not set up a server workshop collection, follow these steps:
- Generating a web api authorization key: In order to use a workshop collection on your server, it must first have a web api authorization key. You can get one here. Once you have your key, add a new launch parameter to your srcds.exe command line:
-authkey YOURAUTHKEYHERE
. - Creating a workshop collection: Next create a workshop collection here. Select Server Content as Type and fill the rest of the fields. Next add the Content Addon. It’s easier to find if you subscribe/fav it first.
- Publish the collection: On the last page when creating the collection, click “Publish”. You might have to agree to the Steam TOS to proceed. The URL of the collection should look something like this when you are finished:
http://steamcommunity.com/sharedfiles/filedetails/?id=913621233
. Write down the numbers from the URL. - Add the collection to your server: Once you have written down the workshop id from the previous step, add a new launch parameter to your srcds.exe command line:
+host_workshop_collection 123123123
, replacing the numbers with the id. Your launch parameters should now include both, the workshop collection and the authkey from step 1:+host_workshop_collection 123123123 -authkey YOURAUTHKEYHERE
.
Configuration¶
Pointshop2 requires no initial configuration! Once it is installed you are ready to go! Restart your server and press F3 to open the menu. You can find all settings under the “Management” tab.
If you don’t see “Management” tab you either don’t have administration addon or you are not admin.
If you already have addon such as ULX go to your server’s console. You can access XGUI with either “!menu” chat command or xgui
console command. I suggest binding XGUI to any key for quick access. Use bind x xgui
in console to bind command. Replace x with your key.
If you don’t have such addon installed download ULX and ULib from Github or add those to your server’s workshop collection.
To add yourself as admin type ulx adduser *your name* superadmin
.
Advanced Configuration¶
There are a few options in Pointshop2 that can be used to integrate the script more tightly into your system.
MySQL Setup¶
By default SQLite (via sv.db) is used to store all player and pointshop data. If you have a MySQL server you can also use MySQL with the script. This has the advantage of being more efficient for large amounts of data, enabling you to share items across multiple servers and allowing you to display data on the web.
If you want to switch from SQLite to MySQL you need to convert your database. We have created a tool where you can upload your SQLite database (located in your server’s garrysmod folder) and download a .sql.gz file that you can import with phpmyadmin. SQLite to MySQL
To enable MySQL please follow these steps:
- Install the gmsv_mysqloo module: Download the module from facepunch and follow the installation instructions for your operating system at the bottom of the post.
- Enable MySQL within LibK: LibK is used for all database operations of Pointshop2. To enable MySQL support go into the configuration file addons/libk/lua/libk/server/sv_libk_config.lua. Set
LibK.SQL.UseMysql = true
and update the remaining settings with your database connection details. If you are hosting the database on a different machine than the gamemserver, make sure to allow external connections to the database. - Test the configuration: After a server restart Pointshop2 will now connect to MySQL. If there are any errors when connecting to the database they will be shown in the server console and logged to garrysmod/data/LibK_Error.txt serverside.
Troubleshooting and reporting bugs¶
When you are experiencing issues with pointshop 2 please follow these steps. For a fast solution include as much information as possible. Report bugs and problems through Discord #support channel.
- Turn on debug mode: Follow the steps outlined here to enable verbose logging: Developer Options.
- Create a minimal test case: Try to reduce the steps needed to create the problem. Once you have found the quickest reliable way to create a problem note down the steps in a step by step fashion.
- Capture the load log: When the script loads it outputs a lot of information to the console. In your report include this, from both server and client console. If something goes wrong during load other errors can happen. The load log is printed on connect (clientside) and after a map change (serverside).
- Include client and server console logs: Include the client and server console logs from when the issue happens. Include a bit before and after, including too much is not a problem. Use a pastebin like http://hastebin.com/ for storing the information.
- Include server configuration: Are you using MySQL or SQLite? Do you use any custom extensions or any DLC? Which administration mod do you use? Which gamemode do you run?
Importing and exporting items and categories¶
Pointshop 2 allows importing and exporting items to text. You can use this feature to make backups of the shop or to transfer the item and category setup between servers.
Exporting and importing items can only be done trough lua commands. You can however run these through the server console by prefixing them with lua_run. Check Export & Import
Example workflow:
-- On Server 1:
Pointshop2Controller:getInstance():exportItems() -- A filename is printed to the console
Pointshop2Controller:getInstance():exportCategoryOrganization() -- A filename is printed to the console
-- You would now go into the data directory and transfer files from the first to the second server
-- On Server 2:
Pointshop2Controller:getInstance():importItemsFromFile( "filename_1.txt" ) -- The filename from the first command
Pointshop2Controller:getInstance():importCategoriesFromFile( "filename_2.txt" ) -- The filename from the second command
Note
Graphical import/export features and importing/exporting of wallets and inventories is planned and will be added in a future update.
Item Creation¶
Trail Creation¶
The pointshop comes with a few trails readily available and it is very easy to add your own. If you wish to do this, simply place the files inside materials/trails and as long as this is correct, they will be picked up. When making your own, it is recommended to use a size of 128x128 and in VTF format, as .png can lead to crashes. When handling the .VMT, use these specifics to avoid blurring or blocky previews:
"UnlitGeneric"
{
"$basetexture" "trails/dollar"
"$vertexalpha" 1
"$vertexcolor" 1
}
To get your image to an actual Pointshop item, go to the second tab called Management. Now you should be on a tab called ‘Create Items’, with options to select the type. Go to Trail to bring up the basic settings menu, where you can personalize the item you are going to make. Once you are happy with the name and price, click the image preview next to the file path. This will bring up a box displaying all functioning materials inside /trails. Hover over them to play an animated preview, which will give some indication of how they look in-game. Once happy, save the item and if successful, will be found in Uncategorised Items, located inside the Manage Items tab. The last step is to move it into a category, which can achieved via drag and drop.
Adding custom playermodels¶
To create a playermodel simply go to Mangement -> Create Item -> Playermodel. Click on the playermodel preview to bring up the selector. You can then pick a playermodel and change bodygroups and skin, if the model provides them.
To add new playermodels to the shop from workshop, simply install the workshop addon to the server collection (see GMod wiki). The addon is now installed to the server. To make sure that players download the addon on join you need to have a matching resource.AddWorkshop in your lua/autorun/server directory. (Details see Xenonservers’ Guide to Workshop). When you bring up the playermodel creator the model can now be picked. Sometimes addons don’t register the models as playermodels so the picker cannot find them. In this case you can extract the workshop addon to find out the model path and put the path into the manual entry text field next to the preview entry. Press enter once you’ve entered the model to apply it.
Accessory/Hat Creation¶
Hats in pointshop2 are PAC3 items. As well as the ordinary single prop-based hats you’ll find in any Pointshop, here you also have the ability use PAC. This allows you to create animated hats, add particles, position hats interactively onto different models and even create full armor or accessories. This can all be done without any lua knowledge and allows you to easily create hats that are absolutely unique to your server.
When creating a hat you have two options:
- Using the ordinary PAC3 editor and importing the outfits into Pointshop 2
- Using the PAC3 editor embedded within the Pointshop2 hat editor
Generally it is recommended to use the first way, this allows you to use the full editor and gives you more options. The best approach is to first create the PAC outfits in sandbox and then use the Hat Creator within the Management Tab to create a pointshop item from it. In gamemodes that do not derive from sandbox (for example TTT or Murder) the PAC editor cannot be used. In this case you can still use the Pointshop2 Hat Editor to create and position hats.
Introduction into PAC¶
PAC (short for Player Appearance Customizer) is an addon made by CapsAdmin. It allows you to fully customize your looks.
First of all, grab the addon from the Workshop here. Once it’s installed, load up Garry’s Mod in sandbox and press c (or whatever key is bound to open the context menu). Underneath the small button to change your player model, you’ll find another that opens up the PAC editor.
In short, PAC is an addon that allows you to build costumes out of props and various other tools available, such as lighting, particles and even text. To use it, you choose a prop from the sandbox spawn menu, use sliders to move it into a location you’re happy with and repeat until finished. The first thing you’ll want to do after installing is turning on advanced features. Do this by going to third tab, options, and hitting the second part down, you’ll then have easy access to everything.
From here, what you make with PAC is entirely up to you, so it’s recommended to just play around until you feel familiar. One aspect that makes costume creation a lot easier is the ability to t-pose your model, meaning they do not move around which can cause issues getting positions exactly right. Access this via the fourth tab, players. It’s the first button and can be changed upon demand, if you wish to preview your costume in an animated manner.
When working on PAC items that are not head-based, it is vital to change the bone to one that correctly suits the position of your costume. For example, if you are placing a model on the player’s chest, go the orange orientation tab of PAC and click the button for it, which will bring up a list of bones that the prop can be attached to. In this scenario, you would click ‘chest’ or ‘amulet’ although it will really depend on what you are making. Failure to do so will usually cause costumes to fall out of place when moving around or in different standing positions.
Further information, tutorials and example items:
The Accessory/Hat Maker¶
One of the main features of Pointshop2 is to make item creation much easier and fluid. The Accessory/Hat Maker is the tool used to create PAC3 powered Hats and Accessories. This includes Pets, Hats and various other items that modify the look of the player.
The editor can be accessed within the Management tab under “Create Items”. Select Accessory/Hat and the editor will open. To create an item follow these steps:
- Fill out the basic information: Fill out the basic fields such as name, point costs and a description.
- Create or import the base outfit: To do this, simply click on the Open Editor button and select the respective option. This outfit is applied to all models by default. CS:S Playermodels usually require slightly different positioning of the items.
- Add model specific outfits: To modify the item positions for CS:S or other playermodels, click the “Add” button beneath the main editor button. You can now choose to create an outfit for all CS:S models or choose a model manually. After selecting this option you can clone the base outfit and adapt the positions. Please not that the outfit is only cloned when you click this button, if you change the main outfit after cloning the changes will not automatically apply to all model specific outfits. In order to fix this simple reclone the outfit by selectiong the option within the model specific outfits table.
- Create a shop icon: Icons for PAC items are automatically generated. To specify from where the icon should look at the item you can use the icon editor. Within the item positioner you will usually click on the “Icon Snapshot” button. This will initialize the icon for you. To fine tune the icon’s view you can use the sliders next to the icon.
- Create an inventory icon: To update the inventory icon follow the same procedure as for the shop icon. Please note that creating a new icon snapshot will overwrite previous changes. It is recommended that you use the sliders for the inventory icon after creating the shop icon.
Slots¶
To avoid clipping and keep everything organized, items are categorized by different slots, which can be viewed via the inventory tab. This allows for multiple accessories on the player, such as head, pets, etc. Items are not set to a single slot, meaning they can be used in multiple areas if the user wishes to do so.
To assign an item to a slot simply check the checkboxes in the item editor. Only slots that were created for Accessory/Hat items can be used, so a PAC item cannot be put into a Trail slot.
Developer Information¶
Modification Guidelines¶
- Never modify code files: When extending or modifying pointshop 2 the first guideline is to never modify any of the core files. You can use hooks and global functions to extend the script or modify functionality. This makes sure that there are as little conflicts between addons as possible. If you need a specific hook or if modification of core files is a much easier solution to a general problem, please get in touch.
- Skin your panels only in derma skins: To make sure that skins can provide a consistent experience, it is important that Paint functions are never directly overwritten. Instead use Derma_Hook and extend the base skin. This gives skin creator the chance to support your addon without messy hooks and overwrites.
- Avoid global variables: Use local variables or create a single global table for your addon to store globals. This avoids cluttering the global namespace, is faster and avoids conflicts.
- Avoid direct database queries: Pointshop 2 makes heavy use of LibK as a database abstraction layer. This enables easy swapping of the databases and makes it possible to avoid many security issues. While you are not required to use LibK models you are encouraged to do so as it automates table creation and removal and allows you to hook into the export, import and backup mechanisms of Pointshop 2 without additional work.
Getting Started¶
To get started with Pointshop 2 development, first read the information on module creation. Modules are the main way to modify and extend Pointshop 2. They provide many automated facilities that make it very easy to extend the script.
After that a good way to start is to check out the examples.
Developer Options¶
To make development and debugging of the script easier there are a few options for developers. If you experience any errors please also turn these settings on as it will help track errors down.
Within addons/libk/lua/libk/shared/2_sh_libk.lua LibK developer settings can be configured.
Defaults¶
LibK.Debug = false
LibK.LogLevel = 2 –Requires Debug
LibK.LogSQL = false
Developer¶
LibK.Debug = true
LibK.LogLevel = 4 –Requires Debug
LibK.LogSQL = true
LibK.LogSQL
logs every query that is generated and sent to the database. This can slow down the server significantly and creates large log files. Only use it if needed.
The reload command¶
For easier development the pointshop2_reload
command to fully reload the script was added. It requires LibK to be in debug mode as well as the user to be an administrator. The command will reload every part of the script, including the database. You can use this to quickly test changes without having to change the map. The command only works for existing files, when adding new files you have to do a map change.
Note
The pointshop2_reload
command is currently broken on linux as file changes are not properly picked up by the game.
Examples¶
- Full tutorial to create an item: https://physgun.netlify.app/pointshop-2/custom-item-part1/
- Bodygroups Chooser by AlphaWolf: https://github.com/snowywolf/Pointshop-2-Bodygroups
- Blur Skin by AlphaWolf: https://github.com/snowywolf/Pointshop-2-Skin
- Full tutorial on how to create a low gravity item: Tutorial Code
Module Creation¶
Modules are the best way to extend pointshop. Through them new item creators can be added.
Note
This is a very technical description with very little example code. It is intended for reference use. You can find a step-by-step tutorial here: Learn how to create a Pointshop 2 item in 3 easy steps
Structure¶
The module structure is very simple. Each module is a folder within the lua/ps2/modules folder. Every file in this folder is recursively loaded by the module loader. The realm is determined by the file prefix (sh, cl, sv). Client files are automatically AddCSLuaFile’d.
Within this folder the module description file sh_module.lua needs to be placed.
Here you set up the module table (MODULE
) which contains information such as the author and name of the module, then register it using Poinsthop2.RegisterModule()
.
Adding custom Item Types¶
Note
Creating custom item types is an advanced topic and requires an understanding of object oriented patterns. It is recommended to look at the items included in the script as an example when reading this section. Good candidates are the Trail and Playermodel items, which show very simple items. A complex example is provided with the Accessory/Hat, which uses multiple data models and a complex item creator.
Users should be able to create and modify items through the ingame gui.
To understand the way items are created in Pointshop2 it is important to know that each item is handled on it’s own and is unique. This means that even if the user owns ten items of the same type each is saved and handled individually. Technically, each item is an instance of a item class. Thus each “item” that is displayed for purchase at a shop is actually an item class. Instances of this class are the items which can be found in a player’s inventory.
Internally this is achieved using the following components:
- Persistence: The persistence is the data model that is used to save all user defined properties (for example the model for a playermodel item, but also the item name and description). On server start the persistence is read and classes are dynamically generated.
- Item Base: The item base defines the functionality of an item. This is defined in a lua file within lua/kinv/items/pointshop. Item bases can use mixins and extend existing bases. All item bases should extend
base_pointshop_item
. - Item Creator: This is the derma control which is used to create or modify an item. It inherits from
DPointshopItemCreator
.
Note
Unlike in pointshop 1, in pointshop 2 an item is an instance of an item class. A shop item is the representation of that class.
Creating a persistence¶
The first step when creating a custom item type is to create it’s persistence. A persistence needs to be a LibK model, which is done by including the DatabaseModel
mixin.
Create a new file within your module called sh_model_<itemname>persistence.lua:
Pointshop2.ExamplePersistence = class( "Pointshop2.ExamplePersistence" )
local ExamplePersistence = Pointshop2.ExamplePersistence
ExamplePersistence.static.DB = "Pointshop2" --Use the database configured for Pointshop2
ExamplePersistence.static.model = {
tableName = "ps2_examplepersistence", --needs to be unique. This is the table the fields are stored in
fields = {
--holds the reference to the basic information (description, name, price)
itemPersistenceId = "int",
--Define your custom fields here. You can use all of the libk fieldtypes here. Usually you will need int or string
property1 = "string",
property2 = "int",
--To save a table: e.g. item.property3 = { hello: 123 }
property3 = "luadata",
},
belongsTo = {
-- Makes LibK automatically join the basic information table each time
-- it is received from the database.
ItemPersistence = {
class = "Pointshop2.ItemPersistence",
foreignKey = "itemPersistenceId",
onDelete = "CASCADE" --Persistence is deleted when the base is deleted. This is required.
}
}
}
ExamplePersistence:include( DatabaseModel ) --include the DatabaseModel mixin
The model can be customized to contain as many fields as you need. If you need to save tables or nested data, consider joining another model (and creating a new belongsTo relationship) or simply use a field type that is serialized (json or luadata).
After doing this, a table will automatically be created and the model can now be used with LibK, which means that no queries have to be written to save or update items.
Implementing saving and updating logic¶
Note
LibK makes heavy use of promises. Using promises is required when saving or modifying models. They allow easy handling of asynchronous processes wihtout the need of messy nested callback chains. The promises script used (by Lexic) follows the javascript promises specification and the jQuery interface. More information: General introduction, The jQuery interface documentation
When a pointshop item is created using an Item Creator, the persistence is passed a “save table”. This table’s structure is filled by the Item Creator Derma Control. Usually it simply contains the model fields. The same function is called for updating items once they are modified. For this the static function createOrUpdateFromSaveTable
has to be added. It creates (or on update retrieves) an instance of the own and any required models and then saves it to the database. All fields that the user can configure when creating a custom item need to be included into the model.
Add the following to your persistence file you created in the last step:
function ExamplePersistence.static.createOrUpdateFromSaveTable( saveTable, doUpdate )
-- Firstly, save or update the basic item information.
local promise = Pointshop2.ItemPersistence.createOrUpdateFromSaveTable( saveTable, doUpdate )
:Then( function( itemPersistence )
// First we fetch or create our persistence instance.
if doUpdate then
--We need to update an existing item.
--Find the instance by using the itemPersistenceId and return it.
return ExamplePersistence.findByItemPersistenceId( itemPersistence.id )
else
local exampleInstance = ExamplePersistence:new( )
exampleInstance.itemPersistenceId = itemPersistence.id
return exampleInstance
end
end )
:Then( function( exampleInstance )
// Then we update all fields
exampleInstance.property1 = saveTable.property1
// And save changes to the database
return exampleInstance:save( )
end )
return promise
end
This concludes all of the serverside code that is needed for handling the creation and modification of items.
Creating the item base¶
The next step is to create the item base for your item type. To do this, create a new file within lua/kinv/items/pointshop. The name should be sh_base_<itemname>.lua
you can also put your file into a subdirectory. Inside of the item base you can now overwrite any of the pointshop base functions and add item hooks as required.
The file contains:
ITEM.PrintName = "Pointshop Example Item Type"
ITEM.baseClass = "base_pointshop_item"
function ITEM.static.getPersistence( )
return Pointshop2.ExamplePersistence --The name of the persistence model created in the last step
end
function ITEM:OnEquip( )
-- Your logic.
local itemOnwer = self:GetOwner()
end
function ITEM:OnHolster()
end
function ITEM.static.generateFromPersistence( itemTable, persistenceItem )
ITEM.super.generateFromPersistence( itemTable, persistenceItem.ItemPersistence )
itemTable.property1 = persistenceItem.property1
end
Please note the function generateFromPersistence. In this function you load all data from the item persisence into the item class.
To generate the item class first call the super class’ method by invoking ITEM.super.generateFromPersistence( itemTable, persistenceItem.ItemPersistence )
. Then you simply copy your item’s properties over to the item class. You should set these to to the itemTable.static
table since they belong to a class itself and not an instance (which would be an instantiated item in the player’s inventory).
-
ITEM.static.
generateFromPersistence
(itemTable, persistenceItem)¶ Decodes all information from the persistenceItem and adds fields and methods to the itemTable field.
itemTable: A table containing the created class. persistenceItem: An instance of this item’s persistence.
Within the item base you can also specify your own, custom icon controls for both, the shop and the inventory.
Adding the clientside creator¶
The last step is to create a custom editor control, which is shown when clicking the create item button. This is very easy to do, simply create a new file inside your module, called D<youritem>Creator
. It should inherit from DPointshopItemCreator
and overwrite the SaveItem(saveTable)
and EditItem(persistence, itemClass)
methods. The SaveItem
method populates the save table passed as argument with the settings set in the item creator. The EditItem
method poulates the editor with the settings stored in the persistence. For ease of access the relevant itemClass is also passed as data from the persistence might be accessible easier in there.
Example template:
local PANEL = {}
function PANEL:Init()
self.textEntry = vgui.Create( "DTextEntry" )
self:addFormItem( "Property 1", self.textEntry )
end
function PANEL:SaveItem( saveTable )
self.BaseClass.SaveItem( self, saveTable )
saveTable.property1 = self.textEntry:GetText( )
end
function PANEL:EditItem( persistence, itemClass )
self.BaseClass.EditItem( self, persistence.ItemPersistence, itemClass )
self.textEntry:SetText( persistence.property1 )
end
vgui.Register( "DExampleCreator", PANEL, "DItemCreator" )
Putting it all together: The blueprint¶
The only thing left to do now is to link the item to the menu and register it with the modules. This is done within sh_module.lua. Simply define all of your components in a Blueprint
.
Example:
MODULE.Blueprints = {
{
label = "Example Item",
base = "base_example", --The name is deduced from the filename
icon = "pointshop2/playermodel.png", --Icon
creator = "DExampleCreator"
},
Creating a slot for your item¶
Slots are created using the function Pointshop2.AddEquipmentSlot()
Example:
Pointshop2.AddEquipmentSlot( "Example", function( item )
--Check if the item is an example item
return instanceOf( Pointshop2.GetItemClassByName( "base_example" ), item )
end )
OPTIONAL: Adding custom Settings¶
Pointshop 2 has a builtin, extensible settings system. A module can add custom settings buttons to the builtin settings tab (Management -> Settings) which can then be used to create a GUI. The system first initializes the settings from the Lua table and copies the defaults, then reads settings from the database. To create custom settings you need the following components: the settings table, a settings button and a settings editor.
The Settings Table¶
The settings table is a table defined inside of sh_module.lua:
MODULE.Settings = {}
MODULE.Settings.Server = {}
MODULE.Settings.Shared = {}
The table is devided into server and shared settings. Shared settings are synchronized with all clients, server settings are only available on the server. Each of these tables can contain multiple :lua:class:`SettingsCategory`s. A category consists of a path, an info table and a number of Settings attached to it.
Example:
MODULE.Settings.Server.Kills = {
info = {
label = "Kill Rewards"
},
DelayReward = {
value = true,
label = "Delay Rewards until round end",
tooltip = "Use this to prevent players to meta-game using the kill notifications. Kill points are collected and awarded at round end.",
},
}
In this example a server-side category “Kills” is created, with the label “Kill Rewards” and a single (boolean) setting called DelayReward. The path of this setting would be “Kills.DelayReward”. You can add as many categories and settings as you like. Be careful not to define a setting in both, the shared and server table with the same path which could lead to conflicts.
Settings Button¶
The next step is to define a button which can be used to open the settings editor. This is also done within sh_module.lua.
Example:
MODULE.SettingButtons = {
{
label = "Point Rewards",
icon = "pointshop2/hand129.png",
control = "DTerrortownConfigurator"
}
}
This defines a button with the label “Point Rewards” and the icon “pointshop2/hand129.png”. On click a DTerrortownConfigurator control is created. The control should implement the Configurator
interface. For details see the next section.
Adding the Configurator¶
Within your module create a new clientside file where you define the configurator control. The configurator control is a derma control which has the methods of the Configurator
interface.
The easiest way is to simply create a control inheriting from DSettingsEditor
and using the method AutoAddSettingsTable
. This automatically populates the settings window with the appropriate input elements for each type you supplied in the settings table.
Example:
local PANEL = {}
function PANEL:Init( )
self:SetSkin( Pointshop2.Config.DermaSkin )
self:SetTitle( "TTT Reward Settings" )
self:SetSize( 300, 600 )
self:AutoAddSettingsTable( Pointshop2.GetModule( "TTT Integration" ).Settings.Server, self )
self:AutoAddSettingsTable( Pointshop2.GetModule( "TTT Integration" ).Settings.Shared, self )
end
function PANEL:DoSave( )
Pointshop2View:getInstance( ):saveSettings( self.mod, "Shared", self.settings )
end
derma.DefineControl( "DTerrortownConfigurator", "", PANEL, "DSettingsEditor" )
This example adds all, shared and server settings to the configurator and sends them to the server on save. This is all that is needed to create modifiable, synchronized settings that are saved to the database and can be changed using an ingame editor.
Accessing the Settings¶
To use the settings in your script simply use Pointshop2.GetSetting()
.
Adding custom Tabs¶
It is possible to add new tabs to various sections of the shop.
You can add a tab to the top navigation by using Pointshop2:AddTab()
. Inside of the inventory tab you can add pages to the side navigation by using Pointshop2:AddInventoryPanel()
. It is also possible to add new pages to the side nav of the management tab by using Pointshop2:AddManagementPanel()
.
Getting and Setting player points¶
In Pointshop 2 points are stored in a player’s wallet (Wallet
). A wallet is a table that contains points and premiumPoints.
Wallets are only networked to their owner and to all admins by default. If you want to display points on a scoreboard, you need to tick the setting “Broadcast Wallets” in the General Settings. This will send everyone’s wallet to everyone.
Use ply.PS2_Wallet to access a player’s wallet.
local points, premiumPoints = 0, 0
if ply.PS2_Wallet then
points, premiumPoints = ply.PS2_Wallet.points, ply.PS2_Wallet.premiumPoints
end
print( points, premiumPoints )
To manipulate a wallet use
PLAYER:PS2_AddStandardPoints()
There is also a console command available to give points to a specific steamid. You can use this with your donation system:
-
ps2_addpoints <steamId> <currencyType> <points>
Gives points to a specific SteamID. Works even if the player has never joined the server.
steamId: SteamID of the player in the STEAM_x_x:xxxxxxxxxx format
currencyType: Currency to give. Can be points or premiumPoints
points: Amount of points to give
Getting via MySQL (for loadingscreens etc)¶
To get a player’s points from a pointshop2 mysql database you can use the following query:
SELECT w.points AS points, w.premiumPoints AS premiumPoints
FROM ps2_wallet w, libk_player p
WHERE w.ownerId = p.id
AND p.player = "STEAM_0:0:19299911"
To get points via steamid64 you can use this query:
SELECT w.points AS points, w.premiumPoints AS premiumPoints
FROM ps2_wallet w, libk_player p
WHERE w.ownerId = p.id
AND p.steam64 = "76561197998865550"
The result row of these queries will contain a points and premiumPoints collumn.
Giving Items¶
To give an item to a player you can use
-
PLAYER:
PS2_EasyAddItem
(itemClassName, purchaseData, suppressNotify)¶ Gives an item to the player.
itemClassName: Class name of the item
purchaseData: [OPTIONAL] A table in the format { time = os.time(), amount = 123, currency = “points”, origin = “LUA” }. amount is a number, currency can be “points” or “premiumPoints”. This is used to calculate the sell price of the item. Origin is a string to track how the item was given. It has no set format.
suppressNotify: [OPTIONAL] If set to true the “New Item Received” popup doesn’t show up.
Examples¶
In these examples please note that there can be multiple items with the same print name. It is better to give an item by class name. To determine the class name you either look at the database directly (className is the persistence id of the item) or use PrintTable(Pointshop2.GetRegisteredItems())
/*
* Gives a random item from the shop to a player
*/
function GiveRandomItem( ply )
local items = Pointshop2.GetRegisteredItems( )
local itemClass = table.Random( items )
return ply:PS2_EasyAddItem( itemClass.className )
end
GiveRandomItem( player.GetByID( 1 ) )
/*
* Gives a item with the specified name to the player
*/
function GiveItemByPrintName( ply, printName )
local itemClass = Pointshop2.GetItemClassByPrintName( printName )
if not itemClass then
error( "Invalid item " .. tostring( printName ) )
end
return ply:PS2_EasyAddItem( itemClass.className )
end
GiveItemByPrintName( player.GetByID( 1 ), "Gas Mask" )
Creating Pointshop Skins¶
Pointshop 2 skins are implemented as derma skins. This means that the Paint functions of Panels are passed to a skin. If you are creating a skin you cannot overwrite or modify any of the files but have to do your skinning entirely through a skin.
The name of the skin which is used is set within the main configuration file at lua/ps2/shared/sh_config.lua. The default flatui skin can be found in lua/ps2/client/cl_dermaskin_flatui.lua. The inventory is seperately skinned through the skin configured in lua/kinv/shared/sh_config.lua, the default skin can be found in lua/kinv/client/cl_dermaskin.lua
Example Skins¶
- Blur Skin by AlphaWolf: https://github.com/snowywolf/Pointshop-2-Skin
Types of Hooks¶
There are two types of hooks that you can use to customize looks and behaviour:
- Layout Hooks: These are always called after initialization of the component. You can use this hook to replace components with custom components or to reposition components.
- Paint Hooks: These work like the normal panel:Paint hooks, use this to customize the appearance of the different panels.
If you are missing a hook on a component that you want to customize, please send Kamshak a pm on scriptfodder.
Fonts¶
Fonts are defined as skin properties and can be customized through a custom skin as well.
Addings slots to existing modules¶
Sometimes you will want an extra accessory or other type of slot. Since it is not recommended to create slots directly within the files that define them, a way to create new slots is described here.
Using the customizing addon¶
It is recommended to extend Pointshop 2 using a seperate addon. Simply download this addon and extract it into your addons folder: Download. Put your new slot code into pointshop2-customizing/lua/ps2/modules/pointshop2/sh_customslots.lua
. As an example code to create a new accessory slot is already included (see below for code explanation).
Adding accessory slots¶
To add an accessory slot, use the function Pointshop2.AddHatSlot()
. This requires the Accessory/Hat module to be fully loaded, which is why the function should be called inside of the hook PS2_ModulesLoaded
.
Example:
-- Adds a new Accessory slot
hook.Add( "PS2_ModulesLoaded", "AddCustomSlots", function( )
Pointshop2.AddHatSlot( "Accessory 3" )
end )
Adding weapon slots¶
To add a weapon slot, use the function Pointshop2.AddWeaponsSlot()
. This requires the Permanent Weapons module to be fully loaded, which is why the function should be called inside of the hook PS2_ModulesLoaded
.
Example:
-- Adds a new Accessory slot
hook.Add( "PS2_ModulesLoaded", "AddKnifeSlot", function( )
Pointshop2.AddWeaponsSlot( "Knife" )
end )
Adding other slot types¶
Other slot types usually do not have convenience functions like the Accessory type. It is still possible to add these slots by duplicating the code. The slot code is defined in the file sh_slots.lua
which can be found in the module’s main folder.
It is also possible to define entirely custom slot types (for example VIP slots, universal slots, etc.) using Pointshop2.AddEquipmentSlot()
Developer API Reference¶
Use this to look up classes or methods.
Note
Not every class is documented here. Look at the source code for usage examples. This is intended to explain data structures that might not be obvious at first as well as documenting the public interface.
Modules¶
-
class
Blueprint
¶ A blueprint defines all properties needed for a custom item.
-
class
SettingsCategory
¶ A table representing a category that contains one or more settings. The category’s path is indicated by it’s key in the table. The
info
key is used to provide a readable name for the category to be used in the configurator component. It contains multiple Settings, the path is again provided by the key.
-
class
MODULE
¶ The module information table. Contains information such as a module’s blueprints and settings. This is to be defined in the module’s sh_module.lua
-
Name
¶ The name of the module.
-
Author
¶ The author of the module
-
RestrictGamemodes
¶ A table containing gamemodes that this module is restricted to. The module will only be loaded if the active gamemode is in the list.
-
Settings
¶ A table containing the settings of the module. A seperate table for each realm exists.
Settings.Server
is only sent to admins when changing the settings,Settings.Shared
is synced with all clients. Accessing Settings is done by callingPointshop2.GetSetting()
. Each realm settings table defines Settings that can be accessed and configured easily and can contain multipleSettingsCategory
s. Settings registered this way are automatically saved the the database when changed.
-
SettingsButton
¶ A table containing information about the settings button that will show up in the management tab. The table has three elements:
label
: The label of the buttonicon
: The icon of the buttoncontrol
: The derma control that is created when clicking the button
-
-
Pointshop2.
GetSetting
(moduleName, path)¶ Retrieves a setting value that was defined in MODULE.Settings. Automatically uses the default or database saved value.
- modName: The MODULE.Name of the module where the setting is defined
- path: The category and name of the setting, seperated by a “.”
Example:
print(Pointshop2.GetSetting("TTTIntegration", "RoundWin.Innocent"))
-
Pointshop2.
AddEquipmentSlot
(name, itemValidFunction)¶ Registers a new equipment slot.
Name:label of the slot that is shown underneath the slot’s panel in the inventory. itemValidFunction: A function that takes an item as an argument and returns whether or not it can be equipped in the slot.
-
Pointshop2.
AddHatSlot
(name)¶ Adds a new slot that behaves exactly like the existing Hat/Accessory slots.
-
Pointshop2:
AddTab
(label, controlName, shouldShow)¶ Adds a new tab to the top navigation of the pointshop.
- label: The label of the tab.
- controlName: The derma control that is created as panel.
- shouldShow: optional A function returning whether or not the player should be able to see this tab.
-
Pointshop2:
AddManagementPanel
(label, icon, controlName, shouldShow)¶ Adds a new tab to the side navigation of the management panel.
- label: The label of the tab
- icon: The tab’s icon
- controlName: The derma control that is created as panel
- shouldShow: optional A function returning whether or not the player should be able to see this tab
Example:
derma.DefineControl( "DPointshopManagementTab_Settings", "", PANEL, "DPanel" ) Pointshop2:AddManagementPanel( "Settings", "pointshop2/advanced.png", "DPointshopManagementTab_Settings", function( ) return PermissionInterface.query( LocalPlayer(), "pointshop2 managemodules" ) end )
-
Pointshop2:
AddInventoryPanel
(label, icon, controlName, shouldShow)¶ Adds a new tab to the side navigation of the management panel.
- label: The label of the tab
- icon: The tab’s icon
- controlName: The derma control that is created as panel
- shouldShow: optional A function returning whether or not the player should be able to see this tab
Player integration¶
-
class
Wallet
¶ In Pointshop 2 points are stored in a player’s wallet. A wallet is a LibK model instance, you can use :save() on it after changing it.
-
points
¶ The standard points of a player.
The premium (donator) points of a player
-
-
PLAYER:
PS2_AddStandardPoints
(points, message, small)¶ Awards points to a player. If a message is specified it will show up in their pointfeed.
points: Amount of points given message: Message displayed to the pointfeed small: Use the small print (for bonus points related to a primary event)
-
PLAYER:
PS2_AddPremiumPoints
(points)¶ Adds premium points to a player’s wallet.
points: Amount of points given
Export & Import¶
-
Pointshop2Controller:
exportItems
()¶ Exports all items of the shop into a timestamped text file. The name of the file is written to console. The file is written into the data directory.
-
Pointshop2Controller:
exportCategoryOrganization
()¶ Exports all categories and item->category mappings of the shop into a timestamped text file. The name of the file is written to console. The file is written into the data directory.
-
Pointshop2Controller:
importCategoriesFromFile
(filename)¶ Imports categories and item->category mappings of the shop from a text file.
filename: Name/path of the file to import from as string, relative to the data directory.
-
Pointshop2Controller:
importItemsFromFile
(filename)¶ Imports items from a text file.
filename: Name/path of the file to import from as string, relative to the data directory.