PavlovArtists Weapon Skin Pack




Description

PavlovArtists Weapon Skin Pack is the first ever server and client mod that works across all maps released for Pavlov Shack. It gives the players a menu in which they can manage skins for their weapons. The skins are visible to other players and are applied to the weapon permanently until it despawns, so players can trade weapons and mags along with their skins, or steal them from their foes.
The mod gets installed on players' headset when the map rotates, so first time joiners won't see the menu or the skins just yet.


Sideloading

The skin pack should download automatically when the map rotates, but map downloads through the game aren't always the most reliable. If you're struggling with it, you can download the mod separately and copy it to your headset manually. These sideloaded archives also may contain higher-resolution textures than the server version.
SVR_PavlovArtists_Mod_WeaponSkinPack.zip (Shack Live)
SVR_PavlovArtists_Mod_WeaponSkinPack.zip (Shack RC)

Server Installation

This guide assumes the dedicated server was set up on a Linux machine according to instructions at PavlovVR Wiki.

  • Download PavlovArtistsWeaponSkinPack.zip (Shack Live) or PavlovArtistsWeaponSkinPackRC.zip (Shack RC)
  • Extract it into /home/steam/pavlovserver/
  • You can verify that it's correctly extracted by checking that the file /home/steam/pavlovserver/Pavlov/Saved/Config/ModSave/WeaponSkinPack/serverconfig.json is present
  • Put MapRotation=(MapId="SVR_PavlovArtists_Mod_WeaponSkinPack", GameMode="CUSTOM") between every map in your rotation in /home/steam/pavlovserver/Pavlov/Saved/Config/LinuxServer/Game.ini
    • It should look like this:
      MapRotation=(MapId="santorini", GameMode="SND")
      MapRotation=(MapId="SVR_PavlovArtists_Mod_WeaponSkinPack", GameMode="CUSTOM")
      MapRotation=(MapId="datacenter", GameMode="TDM")
      MapRotation=(MapId="SVR_PavlovArtists_Mod_WeaponSkinPack", GameMode="CUSTOM")
      MapRotation=(MapId="sand", GameMode="SND")
      MapRotation=(MapId="SVR_PavlovArtists_Mod_WeaponSkinPack", GameMode="CUSTOM")
      MapRotation=(MapId="industry", GameMode="DM")
      MapRotation=(MapId="SVR_PavlovArtists_Mod_WeaponSkinPack", GameMode="CUSTOM")
                              
    • Don't worry, it won't be any actually playable maps inserted in the rotation. The SVR_PavlovArtists_Mod_WeaponSkinPack will rotate to the next one right when it starts. It will prolong the time it takes to get to the next map by 30s or so, but it's necessary to ensure the skin pack will download to your players.

Configuration (JSON storage)

By default the mod stores server configuration and player data in JSON format in your server's ModSave directory. This should be good enough for smaller private servers with up to hundreds of total visitors. If you own a large server network, look into the HTTP storage section.
The server can be configured by editing /home/steam/pavlovserver/Pavlov/Saved/Config/ModSave/WeaponSkinPack/serverconfig.json
These are the configuration options in the file

  • Mode
  • The mode controls default availability of skins in the menu. The options for it are:
  • "Free" - all skins are available to everyone and you don't have to purchase them. Consider using this mode on your server if you have only occasional visitors and you'd like your players to have fun with custom skins.
  • "Restricted" - no skins are available to anyone by default. You have to explicitly enable specific skins either for all players or for specific players. Consider using this mode in heavily moderated communities like PCL, or on servers where you want only your admins/VIPs to own skins.
  • "Paid" - all skins are available to everyone, but players have to purchase them for in-game points. Consider using this mode when you want to reward players that play a lot on your server, so that they can buy the skins wich will give them prestige among others. Don't forget to set TrackScore to true if you enable this mode.
  • TrackScore
  • Set to true if players should be awarded in-game currency for points. One point on Pavlov scoreboard amounts to $10. Generally you want to set this to true when you're running "Mode": "Paid", so that players can actually get the currency for the skins they have to buy.
  • PriceMultiplier
  • Multiplies the skin prices with this number to make them either more expensive or cheaper relative to the default prices. Consider increasing the multiplier on servers where players are awarded a lot of points in short amount of time (DM, TDM...), or on servers with dedicated community of frequently returning players, so that everyone doesn't have all skins on day 2 and have nothing to work towards.
  • SkinConfig
  • Allows you to change the default availability and price setting for certain skins to all players. Each entry in this list takes the form of a skin id with sub-entries Mode and Price.
  • Mode - overrides the server-wide Mode for this skin. So if you're using server-wide Restricted mode, here you can enable individual skins for all players by setting them as Free.
  • The valid values are basically the same as for the server-wide Mode:
  • "Free" - The skin will be available for free to everyone
  • "Restricted" - the skin won't be available to anyone (unless explicitly allowed for individual players in PlayerConfig section)
  • "Paid" - the skin will be available to everyone, but players have to purchase it for in-game points
  • Price - overrides the price of this skin in Paid mode. Note that this price is final, so it isn't affected by PriceMultiplier.
  • Example:
  • "Mode": "Paid",
    "SkinConfig":
    {
        "m4_mark":
        {
            "Price": 100
        },
        "ak47_goldtrim":
        {
            "Mode": "Restricted"
        }
    }
                              
  • The server has economy enabled, the skin "m4_mark" has its price reduced to $100, and the skin "ak47_goldtrim" isn't available for anyone to purchase.
  • PlayerConfig
  • Allows you to change the availability of skins for specific players. Each entry in this list takes the form of a player name, with following sub-entries:
  • Mode - overrides the server-wide or skin-specific availability setting for this player. As usual the valid values are Free, Restricted and Paid. You can also skip this setting and it will use the default configuration for the skin
  • AllowedSkins - list of skin IDs which are normally Restricted, but are available for this player anyway. Consider restricting some skin and make it available only to certain players with this setting as an event or season reward or someting.
  • RestrictedSkins - list of skin IDs which are normally Free or Paid, but are restricted for this player anyway. Honestly I don't know what I'd use this for, but since there's the AllowedSkins list, we might as well have the opposite.
  • Example:
  • "Mode": "Paid",
    "SkinConfig":
    {
      "ak47_goldtrim":
      {
        "Mode": "Restricted",
        "Price": 0
      }
    },
    "PlayerConfig":
    {
      "markyxl":
      {
        "Mode": "Free"
      },
      "CHALK":
      {
        "AllowedSkins": ["ak47_goldtrim"]
      }
    }
                              
  • The server has economy enabled, the skin "ak47_goldtrim" is restricted only to season winners, but it's free to those who have access. Player "markyxl" is an admin who has access to all skins including the restricted AK. Player "CHALK" is a season winner, so he has access to the restricted AK skin.

Configuration (HTTP storage)

If you own a server with larger playerbase, then you might want to consider saving the player data and server config in a database. The mod can communicate with the storage over HTTP. You can either use a storage server by someone else (although none exist at the time of writing this), or implement your own based on the HTTP spec below. Note that this method is intended only for a handful of very experienced people owning large server networks.
To use http storage, replace the entire contents of /home/steam/pavlovserver/Pavlov/Saved/Config/ModSave/WeaponSkinPack/serverconfig.json with following config attributes instead:

  • RemoteUrl - the url of the endpoint, including protocol and port.
  • ServerKey - a key that serves two purposes
  • As a password so that the backend accepts requests only from your game server and not just anyone if they happen to find out the url of your enpoint. Note that this key is transferred in headers in plaintext, so be cautious about its content especially over HTTP. Sorry about this not being more secure, but we're running game servers here, not banking system.
  • As an identifier of the server if you have multiple servers connected to the same storage backend. Since server config like Mode is acquired from the http server as well, it allows you to run different servers with different economy settings, while still sharing the player data.
  • Example (entire serverconfig.json file):
  • {
      "RemoteUrl": "http://192.168.144.1:5000/pavlovWeaponSkinPack",
      "ServerKey": "mysupersecretpassword:server1"
    }
                            
Note that upon activating http storage, all other JSON settings from the file will be ignored and used from the server instead.

HTTP REST API Specification

Warning: If you're a regular server owner you really shouldn't read this. This section is intended for 2 or 3 people in the whole Pavlov community.
All requests are done with the GET verb.
All parameters are passed to the mod in headers.
Headers present in every request:

  • serverkey - the same string that the server has in ServerKey in serverconfig.json. Use this to recognize from which server the request came in.
  • cmd - the operation the request is supposed to perform, see the list below. Normally this would be part of the URL, but since everything is in headers, then what the hell

Commands:
  • Get Server Config - returns server config in response body in the same JSON format as serverconfig.json described above. Called only once on round start
  • cmd: sconfig
  • Additional parameters: none
  • Response body: server config in the same JSON format as serverconfig.json described above, except the PlayerConfig section which isn't used here; there are other requests for that
  • Sample cURL request: curl http://localhost:5265/pavlovWeaponSkinPack --header "serverkey: abc123" --header "cmd: sconfig"
  • Sample reply: {"Mode":"Paid","TrackScore":true,"PriceMultiplier":0.5}
  • Get Player Config - returns infrequently changed properties of a player. Called when a player joins and whenever the player buys a skin
  • cmd: pconfig
  • Additional parameters:
  • player - Oculus name of the player
  • Response body: player config in the same JSON format as serverconfig.json described above, with one additional field OwnedSkins, which lists skin IDs wich the player bought in Paid mode
  • Sample cURL request: curl http://localhost:5265/pavlovWeaponSkinPack --header "serverkey: abc123" --header "cmd: pconfig" --header "player: markyxl"
  • Sample reply: {"Mode":"Paid","AllowedSkins":["ak47_goldtrim"],"RestrictedSkins":[],"OwnedSkins":["m4_mark", "ak47_goldtrim"]}
  • Get Player State - returns frequently changed properties of a player - currently only Cash. Called whenever a player score changes when economy is enabled
  • cmd: pstate
  • Additional parameters:
  • player - Oculus name of the player
  • Response body: JSON with field Cash and integer value of the player's cash
  • Sample cURL request: curl http://localhost:5265/pavlovWeaponSkinPack --header "serverkey: abc123" --header "cmd: pstate" --header "player: markyxl"
  • Sample reply: {"Cash":798}
  • Change Player Cash - modify the amount of currency the player has available
  • cmd: changecash
  • Additional parameters:
  • player - Oculus name of the player
  • cashdelta - Either positive or negative integer how much the player's Cash should change relative to current amount
  • Response body: empty. You can actually return whatever, but it won't be parsed
  • Sample cURL request: curl http://localhost:5265/pavlovWeaponSkinPack --header "serverkey: abc123" --header "cmd: changecash" --header "player: markyxl" --header "cashdelta: 2000"
  • Sample reply: empty
  • Buy Skin - modify the list of OwnedSkins of the player and reduce his available currency with the price of the skin
  • cmd: buyskin
  • Additional parameters:
  • player - Oculus name of the player
  • skin - Skin ID to add to the OwnedSkins list replied in future pconfig requests
  • price - The cost of the skin. A positive integer that should be subtracted from the player's available currency. If you're wondering if it isn't weird that the price is sent like this instead of being internal, then it's because I don't want you to have to replicate all the logic with price multiplier, modes, and per-player prices in the backend.
  • Response body: empty. You can actually return whatever, but it won't be parsed
  • Sample cURL request: curl http://localhost:5265/pavlovWeaponSkinPack --header "serverkey: abc123" --header "cmd: buyskin" --header "player: markyxl" --header "skin: m4_klair" --header "price: 200"
  • Sample reply: empty