Skip to content

Bulletin Board by Night Shift Studio ​

Visit our Discord / Homepage / Store !


Table of contents ​


Requirements / Dependencies ​

The following resources are required for nss_pinboard to work:

  • A character framework: VORP Core or RSG Core
  • A MySQL resource: ghmattimysql or oxmysql

Framework ​

Config.Framework names the framework: "vorp", "rsg" or "auto" (default), which takes the one that runs. The board may start before the framework and the database, it waits for them.

VORP CoreRSG Core
Character idcharIdentifiercitizenid
Job and rankjob, jobGradejob.name, job.grade.level
Group (Config.GroupRemovePermissions and others)User groupHighest permission (god, developer, headadmin, admin, mod, helper), user without any
Admin (Config.NameOfAdminGroup)User groupPermission, checked the way RSG checks it
Pinning service pays withMoneyCash
Notifications with Config.UseCustomTips = falseVORP tipsRSG notify

Character ids are text: restrict_*_by_callback get "12" on VORP and the citizenid on RSG.


Changelog ​

See CHANGELOG.md for more information.


Setup ​

  1. Ensure that the nss_pinboard folder is in your resources folder.
  2. Rename config.demo.lua to config.lua and fill in the values.
    1. If you want to use prepared bulletin boards see optional ymap now.
  3. Rename secure.demo.lua to secure.lua and fill in your Discord webhook urls.
  4. Execute db.sql on your database. Missing tables and columns of newer versions are also added on resource start.
  5. Add ensure nss_pinboard to your server.cfg.
  6. Restart your server.

Optional: ymap ​

You can use this bulletin_boards.ymap to place bulletin boards to prepared locations in your map. The bulletin_boards_config.lua file contains the coordinates for the bulletin boards for the script.

  1. Copy and replace Config.Posters from bulletin_boards_config.lua into your config.lua

  2. Create a new resource folder.

  3. Create a stream folder inside the new resource folder.

  4. Copy the bulletin_boards.ymap file into the stream folder.

  5. Add fxmanifest.lua with the following content:

    lua
    fx_version "adamant"
    game "rdr3"
    rdr3_warning "I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships."
       
    this_is_a_map "yes"
  6. Add ensure <new_resource_name> to your server.cfg.

  7. Restart your server.


UI style ​

Config.UiStyle decides the look of menus, dialogs and the admin panel. The boards themselves look the same in both.

ValueLook
"classic"The original look (default).
"ink"Ink panels with torn edges in the style of the RDR2 menus. Every button is a small ink plate, dialogs and admin windows use the same parts, and everything can also be worked with the keyboard.

The style is read when the resource starts. Change it and restart the resource.


Text notices ​

A text notice is written straight onto its paper, section by section. The small buttons above a section:

ButtonDoes
KindHeadline, text, fine print or divider
FontPrint (the font of the board), slab serif or handwriting. For a divider: its pattern
AlignmentLeft, centre or right
B, I, UBold, italic, underlined
ColourThe inks of the time, and with FreeColor any colour from a colour picker
RemoveTakes the section out

Bold, italic, underlined and colour go to the marked words, with nothing marked to the whole section. Pasted text arrives as plain text. When the text no longer fits on the paper, the editor says so before it is pinned.

lua
Config.TextPoster = {
    FreeColor = true, -- false offers only the inks
}

A colour too light for the paper is darkened to a contrast of at least 3 to 1 against the darkest paper, its hue stays. The picker shows the darkened colour.

The server rebuilds every notice from known fields and accepts it only from a player standing at the board. Limits: 20 sections, 2000 characters and 200 formatted pieces per section, 64 KB per notice. The Discord log shows bold, italic and underlined as Markdown, colours do not show there.


Investigation wall ​

A second kind of board: instead of a grid of notices it offers a free cork surface. Players pin notes, typed documents, photos and sketches anywhere on it, stick in pins and stretch coloured threads between them, the way an investigation is laid out in a sheriff's office. Several players can work on the same wall at once and see each other's changes right away.

Creating a wall ​

  • Config board: add board_type = "investigation" to the entry in Config.Posters (see config.demo.lua).
  • Database board: choose the board type "Investigation wall" in the admin panel (/boardadmin), when creating a board or later under "Edit".

restrict_view_by_jobs / restrict_view_by_callback decide who may look at the wall, restrict_create_by_jobs / restrict_create_by_callback who may work on it. Admins may always do both. Everybody else can look at the cards, hold them up close and see who stands at the wall.

What players can do ​

ActionHow
Pin up a cardButtons above the wall: note, document, photo, sketch, pin. The card appears in the middle of the view.
Write on a note or documentRight after pinning it up, or "Write" below the wall. Documents know bold, italic, underlined, four inks, three sizes, two alignments and three papers.
Draw on a sketch"Write" below the wall: pencil in three strengths and four inks, an eraser for whole lines, and five backgrounds (cork, paper, lined, squared, dotted).
Move, resize, turnDrag a card, the lower right handle resizes, the upper right handle turns it.
Choose several cardsShift or Ctrl click, or draw a frame on the empty cork.
Stretch a thread"Thread", then the card it starts at and the one it ends at. Five colours.
Untie a threadClick the thread, then "Untie thread" or Delete.
To the front / to the backButtons below the wall.
Take down"Take down" or Delete. The threads tied to the card go with it.
Swap a photoChoose the photo, "Swap photo". Place, size, angle, layer and threads stay.
Look closerDouble click a card, or "Look closer". Only the player sees it.
UndoCtrl+Z or "Undo", up to undo_steps own steps while the wall is open.
Zoom and move the viewMouse wheel, buttons above the wall, right or middle mouse button. Every player has their own view.

A card someone moves or writes on is held for everybody else and shows the name of that player. The hold ends when they let go, or after lock_seconds if they lost the connection. A change made on an older state of a card is refused instead of overwriting the newer one.

Settings ​

Config.InvestigationWall in config.demo.lua sets the limits (cards, threads, lines of a sketch, length of texts), how long a card is held, the pointers of the other players (show_cursors, off by default), anonymous names, the number of changes a player may send per second, the steps to undo and how close a player has to stand. Everything is checked on the server.

Photos load straight from the server of their image link, which then learns the IP address of everybody looking at the wall. Config.ImageServerAllowlist limits image links to servers you trust, for image notices and for photos alike.

Templates ​

wall_templates.lua holds templates of cards and threads. "Put up example" in the admin panel pins the template showcase (in Config.language) to a wall, "Clear wall" takes everything off it. Other resources use fillWall and clearWall.


Board models ​

Config.BoardProps lists the models a board can stand on. While placing a board in the admin panel, Config.PlacementFootKey switches through them, in the fine placement the model can also be chosen in the panel. Models of other resources can be listed as long as those resources are streamed on the server:

lua
Config.BoardProps = {
    { model = "mp005_p_mp_bountyboard01x", label = "Bounty board" },
    { model = "mp005_p_mp_bountyboard02x", label = "Bounty board with feet" },
    { model = "my_corkboard_01", label = "Cork board" }, -- from another resource
}

Every entry names the model and its label in the placement panel. Two more values are optional:

KeyMeaningDefault
prompt_distanceMetres in front of the board where its prompt waitsConfig.DbBoardPromptOffset
prompt_heightMetres above the origin of the model where its prompt waits1.0

The origin of a board standing on the ground is at its feet, a board hung on a wall needs a lower prompt_height:

lua
{ model = "my_wall_board", label = "Wall board", prompt_distance = 0.6, prompt_height = 0.2 },

An entry without a model, a label that is no text, a value that is no number or a model listed twice is reported in the server and client console and left out or set to its default. Without any usable entry the two bounty boards of the game are offered.

Boards placed before 2.0.0 keep their bounty board. A board keeps standing on its model when the model is taken out of the list, only no new board can be placed on it.

The fine placement also tilts a board: pitch leans it forward and back, roll to the sides, e.g. to lean it against a wall. Moving a board later keeps its tilt.


Vermin ​

Cockroaches and spiders crawl across the open board by day, moths circle the lantern at night. They run inside the UI only, players may squash them. The crawlers pass behind the lantern, the moths fly in front of it.

They are optional: Config.Vermin.enabled = false switches them off, and so does leaving the block out of the config. Switched off, the UI reads no picture for them and draws nothing for them. While they crawl it draws a new frame all the time, on a server that counts every frame they are best left off.

KeyMeaning
enabledtrue for vermin on the boards
initial_countCritters already on the board when it opens
spawn_chanceChance in percent that one appears, rolled every spawn_interval_ms
spawn_interval_msHow often that chance is rolled
max_aliveNever more at the same time
moths_at_nightMoths around the lantern at night
spider_chanceChance in percent that a crawler is a spider, 0 for none
squashableClicking a critter squashes it
squash_soundA faint crunch when one is squashed

EVENTS ​

Client events ​

nss_pinboard:open ​

Opens the bulletin board for the given city.

Ensure to not open the bulletin board multiple times.

city is the name (id) of the bulletin board that you have used in your config.

Client usage

lua
TriggerEvent('nss_pinboard:open', 'city')

Server usage

lua
TriggerClientEvent('nss_pinboard:open', player_id, 'city')

Client command usage

Simple example to use events as commands...

lua
RegisterCommand("popen", function(_, args, _)
    local city_name = args[1] or nil
    TriggerEvent("nss_pinboard:open", city_name)
end)

RegisterCommand("pclose", function()
    TriggerEvent("nss_pinboard:close")
end)

nss_pinboard:close ​

Closes the bulletin current open bulletin board.

Client usage

lua
TriggerEvent('nss_pinboard:close')

Server usage

lua
TriggerClientEvent('nss_pinboard:close', player_id)

Server exports ​

New since 2.0.0. All of them only work on investigation walls, city is the name of the board.

getWall(city) ​

Everything on a wall: { items = {...}, threads = {...} }, or nil if the board is no investigation wall.

lua
local wall = exports.nss_pinboard:getWall('Sheriff Office Wall')
print(#wall.items .. ' cards, ' .. #wall.threads .. ' threads')

clearWall(city) ​

Takes every card and thread off a wall. Players at the wall see it at once. Returns true on success.

fillWall(city, template_name) ​

Pins the cards of a template from wall_templates.lua to a wall. What already hangs there stays. Returns the number of cards put up, or nil if the board or the template does not exist.

lua
exports.nss_pinboard:fillWall('Sheriff Office Wall', 'showcase')

getWallViewers(city) ​

Who stands at a wall right now: { { source = 12, name = "Josiah Kern", can_edit = true }, ... }.


FAQ ​

Why sometimes images from discord are not available? ​

Discord has introduced an expiry restriction for images.

See the following links for more information:

As long as there is no simple solution for this, we recommend that your players refrain from using Discord links.

You can use Config.ImageServerBlacklist to block specific domains like discord.com or cdn.discordapp.com to prevent the use of Discord links.


NIGHTSHIFT STUDIO Documentation