nss_pinboard - changelog
2.1.0 (2026-09-30)
Features
- Add RSG Core support.
Config.Frameworkchooses"vorp","rsg"or"auto", which takes the one that runs. On RSG the group of a player is their highest permission (god,developer,headadmin,admin,mod,helper,userwithout any) and the pinning service takes cash. - The props for the new board are available at <https://kitty.tebex.io/package/7368644> FOR FREE!, along with many other beautiful things. Have a look!
Changes
vorp_coreis no longer a fixed dependency. On start the board waits for the database, the framework is looked up on first use.- The creator of notices, cards and threads is stored as text in
creator_char_id: VORP counts its characters, RSG names them. The columncreator_vorp_char_idis renamed on resource start, stored ids stay valid. restrict_view_by_callbackandrestrict_create_by_callbackgetchar_idas text.- On RSG a job change updates the boards right away.
What must be considered during update?
Add
Config.Frameworkto yourconfig.lua(seeNew since 2.1.0marks). Without it"auto"is used.The creator columns are changed on resource start. If your database user may not alter tables, run:
sqlUPDATE `nss_pinboard_posters` SET `creator_vorp_char_id` = 0 WHERE `creator_vorp_char_id` IS NULL; ALTER TABLE `nss_pinboard_posters` CHANGE COLUMN `creator_vorp_char_id` `creator_char_id` VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'Character of the creator: VORP charIdentifier or RSG citizenid'; ALTER TABLE `nss_pinboard_wall_items` CHANGE COLUMN `creator_vorp_char_id` `creator_char_id` VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'Character of the creator: VORP charIdentifier or RSG citizenid'; ALTER TABLE `nss_pinboard_wall_threads` CHANGE COLUMN `creator_vorp_char_id` `creator_char_id` VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'Character of the creator: VORP charIdentifier or RSG citizenid';A
restrict_*_by_callbackthat checkschar_idcompares it as text now:char_id == "12".
2.0.0 (2026-09-30)
Features
- Add the investigation wall, a second board type with a free cork surface. Players pin notes, typed documents, photos and sketches, set pins and stretch threads between them. Cards can be moved, resized, rotated, layered, selected in groups and held up close with a double click. Several players work on the same wall at once and see every change right away. Set
board_type = "investigation"inConfig.Postersor choose the board type in the admin panel. Limits are set inConfig.InvestigationWall. The props for the new board are available at <https://kitty.tebex.io/package/7368644>, along with many other beautiful things. Have a look! - Add wall templates (
wall_templates.lua) with "Put up example" and "Clear wall" in the admin panel. - Add server exports
getWall,clearWall,fillWallandgetWallViewers. - Add formatting to text notices: bold, italic, underline and colour for marked words, a font per section (print, slab serif, handwriting), fine print and dividers. Six period inks,
Config.TextPoster.FreeColoradds a colour picker. Colours too light for the paper are darkened. The editor warns when the text no longer fits on the paper. - Add the ink UI style (
Config.UiStyle = "ink"): menus, dialogs and admin panel in the style of the RDR2 menus, with keyboard control."classic"stays the default. - Add board models (
Config.BoardProps). The admin picks the prop while placing a board, streamed models of other resources can be listed, each with its own prompt position. - Add pitch and roll to the board placement.
- Add
Config.ImageServerAllowlistto limit image links to trusted servers. - Add
Config.OpenByHoldingto open a board by holding the key.
Changes
Config.PlacementFootKeynow switches throughConfig.BoardPropsinstead of toggling the feet.- Image links with a backslash, a user name or a port are refused.
- Boards moved or changed in the admin panel update for every player right away.
- Cockroaches and spiders crawl behind the lantern, moths fly in front of it.
Config.Vermin.enabled = falseswitches the vermin off completely, nothing runs for them in the UI.
Fixes
- Fix a manipulated notice hiding every notice after it on the board. The server now rebuilds every notice from known fields.
- Fix notices being pinned from anywhere by a modified client. The server checks that the player stands at the board.
- Fix job restrictions: with only
restrict_view_by_jobsor onlyrestrict_create_by_jobsset, the server let every player through. - Fix a refused notice being reported as pinned after 10 seconds and the typed text being lost.
- Fix notices longer than 4096 characters missing in the Discord log.
- Fix changed view restrictions and deleted boards not reaching players already online.
- Fix Escape on an open question in the admin panel closing the panel behind it.
- Fix moths flying to a corner on boards without a lantern.
What must be considered during update?
New tables and columns are created on resource start. If your database user may not create or alter tables, run:
sqlCREATE TABLE IF NOT EXISTS `nss_pinboard_wall_items` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, `board_city` VARCHAR(255) NOT NULL COMMENT 'Board the card hangs on (= partition key)', `kind` VARCHAR(16) NOT NULL COMMENT 'note, text, photo, sketch or pin', `pos_x` FLOAT NOT NULL DEFAULT 0 COMMENT 'Centre in wall units', `pos_y` FLOAT NOT NULL DEFAULT 0 COMMENT 'Centre in wall units', `width` SMALLINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Wall units', `height` SMALLINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Wall units', `rotation` FLOAT NOT NULL DEFAULT 0 COMMENT 'Degrees', `z_index` INT NOT NULL DEFAULT 0 COMMENT 'Stacking order', `content_json` MEDIUMTEXT DEFAULT NULL COMMENT 'JSON content, depends on kind', `version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'Raised on every change, keeps an older change from overwriting a newer one', `creator_vorp_char_id` INT UNSIGNED NOT NULL DEFAULT 0, `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX `idx_board_city` (`board_city`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; CREATE TABLE IF NOT EXISTS `nss_pinboard_wall_threads` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, `board_city` VARCHAR(255) NOT NULL COMMENT 'Board the thread hangs on (= partition key)', `item_a` INT UNSIGNED NOT NULL COMMENT 'Card or pin the thread starts at', `item_b` INT UNSIGNED NOT NULL COMMENT 'Card or pin the thread ends at', `color` VARCHAR(16) NOT NULL DEFAULT 'red', `creator_vorp_char_id` INT UNSIGNED NOT NULL DEFAULT 0, `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, INDEX `idx_board_city` (`board_city`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; ALTER TABLE `nss_pinboard_boards` ADD COLUMN `pitch` FLOAT NOT NULL DEFAULT 0 COMMENT 'Tilt forward and back in degrees' AFTER `heading`, ADD COLUMN `roll` FLOAT NOT NULL DEFAULT 0 COMMENT 'Tilt to the sides in degrees' AFTER `pitch`, ADD COLUMN `board_type` VARCHAR(16) NOT NULL DEFAULT 'notices' COMMENT 'notices = notice board, investigation = investigation wall' AFTER `trigger_only`, ADD COLUMN `prop_model` VARCHAR(64) DEFAULT NULL COMMENT 'Prop model name, NULL = bounty board chosen by has_foot' AFTER `board_type`;New language keys added (see
New since 2.0.0marks). Please add them to your language file(s).Compare your
config.demo.luawith yourconfig.luato consider new options (seeNew since 2.0.0marks).New file
wall_templates.lua, it holds the templates for investigation walls.Job restrictions are now enforced on the server exactly as configured. Check the restrictions of your boards.
1.7.0 (2026-08-14)
Features
- Add the office stamp: notices pinned to every board at once show who handed them in (character name, board and
Config.StampYear) on a slip in the large view. Notices pinned at a single board stay anonymous. - Add a pin animation (
Config.PinAnimation): the character nails the notice to the board. - Add vermin on the board (
Config.Vermin): cockroaches and spiders by day, moths around the lantern at night. Players can squash them.
Security
- The stamp is built on the server only. A client cannot sign a notice with another name.
What must be considered during update?
- New columns
creator_nameandcreator_locationonnss_pinboard_postersare added on resource start. - New language keys added (see
New since 1.7.0marks). Please add them to your language file(s). - Compare your
config.demo.luawith yourconfig.luato consider new options (seeNew since 1.7.0marks).
1.6.1 (2026-07-20)
Fixes
- Fix cancelling the "where to pin" question pinning a free notice anyway. The question now has a Cancel button, Escape and a click beside it cancel as well.
- Fix an open create dialog staying on screen after the board was closed.
What must be considered during update?
- Nothing.
1.6.0 (2026-06-17)
Security
- All notice permissions are enforced on the server: create, view and remove restrictions, "post everywhere at once", the pinning service and image links (scheme, extension, length,
Config.ImageServerBlacklist). Text notices are length-limited. restrict_*_by_callbackstays client-side, the server evaluates it where possible. Use job restrictions for guaranteed access control.- The NUI now also escapes
<,>,"and'.
Fixes
- Fix board props spawning only within half of
Config.BoardViewDistance. - Fix the NUI not being answered after a server timeout.
- Fix the
Config.BlipHashtype check. - Fix a memory leak of NUI response callbacks.
- Fix the day and night look of an open board updating only once.
- Fix image notices with a missing image using only three of the ripped paper variants.
Performance
- Add database indexes on
nss_pinboard_posters(location,created_at). - Outdated notices are removed hourly in one batch instead of on every board open.
- Support
oxmysqlbesidesghmattimysql.
What must be considered during update?
The new indexes are added on resource start. To add them manually instead, run:
sqlALTER TABLE `nss_pinboard_posters` ADD INDEX `idx_location` (`location`); ALTER TABLE `nss_pinboard_posters` ADD INDEX `idx_created_at` (`created_at`);If you relied on
restrict_*_by_callbackfor security, switch torestrict_create_by_jobs/restrict_view_by_jobs.
1.5.0 (2026-02-27)
- Add in-game admin board management. Admins can place, edit, delete, reposition and teleport to boards directly in-game via a configurable chat command (
Config.AdminBoardCommand, default:boardadmin). - Boards created via the admin panel are stored in the database (
nss_pinboard_boardstable) and merged withconfig.luaboards on startup. Database boards take precedence over config.lua boards with the same city name. - Add live placement preview with walk/fine mode and position/heading sliders.
- Add board reposition: move an existing board to a new position via placement mode from the board list.
- Add "Migrate Config Boards" button to copy all
config.luaboards into the database (callbacks are not migrated). - Add proximity-based prop spawning for database boards (chunk system, configurable via
Config.BoardViewDistance). - Add Lua callback support for database boards (stored as source text, compiled at runtime via
load()). - Add configurable prompt offset for database boards (
Config.DbBoardPromptOffset, default:0.5). - Fix blip cleanup on resource stop: blips were not removed because the wrong handle was stored.
- Block admin panel while a pinboard is open.
- UI improvements: icon buttons, scrollable dialogs, side-by-side job restriction columns, consistent title styling.
- Add freestanding board prop toggle (
has_foot). Boards can use the freestanding prop model with feet (mp005_p_mp_bountyboard02x). Toggle via G-key during placement or via the foot checkbox in the placement UI. - Add two board types: Board with Prop (spawns a bounty board prop) and Trigger Point Only (no prop, just a trigger location). New boards prompt for type selection. Config-migrated boards are automatically set to trigger-only. Board type is shown as icon in the board list.
- Add admin audit log for board management. All board create, edit, delete and import actions are now logged with character name, Steam ID and timestamp. Edit actions include a detailed diff of changed fields. Logs can be viewed via a global log button or per-board log icon in the admin panel. Infinite scrolling loads entries in batches of 50.
- Add
Config.BoardLogRetentionDays(default:90). Board log entries older than this many days are automatically deleted on resource start. Set tonilto keep log entries forever.
What must be considered during update?
- New database tables: Run the following SQL statements in your database:
CREATE TABLE IF NOT EXISTS `nss_pinboard_board_logs`
(
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`action` ENUM ('create','edit','delete','import') NOT NULL,
`board_city` VARCHAR(255) NOT NULL,
`char_name` VARCHAR(255) NOT NULL DEFAULT '',
`steam_id` VARCHAR(64) NOT NULL DEFAULT '',
`details` TEXT DEFAULT NULL COMMENT 'JSON diff of changed fields (edit action)',
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX `idx_board_city` (`board_city`),
INDEX `idx_created_at` (`created_at`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;CREATE TABLE IF NOT EXISTS `nss_pinboard_boards`
(
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'Unique board identifier',
`city` VARCHAR(255) NOT NULL COMMENT 'Unique board name (= partition key for posters)',
`group_name` VARCHAR(255) NOT NULL COMMENT 'Board group (used for pinning service)',
`coord_x` FLOAT NOT NULL DEFAULT 0 COMMENT 'World position X',
`coord_y` FLOAT NOT NULL DEFAULT 0 COMMENT 'World position Y',
`coord_z` FLOAT NOT NULL DEFAULT 0 COMMENT 'World position Z',
`heading` FLOAT NOT NULL DEFAULT 0 COMMENT 'Heading in degrees',
`alternative_style` TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Use indoor/alternative NUI look',
`hide_blip` TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Hide map blip',
`prevent_text_posters` TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Disallow text posters',
`prevent_image_posters` TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Disallow image posters',
`restrict_view_by_jobs` TEXT DEFAULT NULL COMMENT 'JSON: {"JobName":grade}',
`restrict_create_by_jobs` TEXT DEFAULT NULL COMMENT 'JSON: {"JobName":grade}',
`restrict_view_by_callback` TEXT DEFAULT NULL COMMENT 'Lua source for view callback',
`restrict_create_by_callback` TEXT DEFAULT NULL COMMENT 'Lua source for create callback',
`has_foot` TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Use freestanding prop model with feet',
`trigger_only` TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Trigger point only (no prop spawned)',
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Timestamp of creation',
UNIQUE KEY `uk_city` (`city`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;- New language keys added (see
New since 1.5.0marks). Please add them to your language file(s). - Compare your
config.demo.luawith yourconfig.luato consider new options (seeNew since 1.5.0marks).
1.4.1 (2026-02-15)
- Fix support for webp images.
What must be considered during update?
- Nothing.
1.4.0 (2025-11-21)
- Add
restrict_view_by_callbackto poster config to allow custom view restrictions via callback function, e.g. for subscriptions. - Add
restrict_create_by_callbackto poster config to allow custom creation restrictions via callback function, e.g. for subscriptions. - Add
nss_pinboard:reInitializeclient event to re-initialize pinboard data without reloading the resource, e.g. if subscription status changed.
What must be considered during update?
- Compare your
config.demo.luawith yourconfig.luato consider new options (seeNew since 1.4.0marks).
1.3.5 (2025-11-17)
- Move discord webhooks from
config.luato a server readonly config filesecure.luato hide webhook urls from clients. Config.DiscordWebhookis now insecure.lua.- Individual webhooks for posters are now in
secure.luaas well, seeConfig.PosterIndividualDiscordWebhooks.
What must be considered during update?
- New file
secure.luamust be created fromsecure.demo.luain the resource root folder. - Transfer your existing webhook configuration from
config.luato newsecure.luafile (seeNew since 1.3.5marks).
1.3.4 (2025-02-17)
- Add events to open/close pinboard.
What must be considered during update?
- Nothing.
1.3.3 (2025-01-14)
- Fix
RemoveBliperror if no number is given (since client artefact 12295).
What must be considered during update?
- Compare your
config.demo.luawith yourconfig.luato consider new options (seeNew since 1.3.2marks).
1.3.2 (2024-11-10)
- Add optional
Config.UseZAxisForOpenPromptRadiusto enable z axis check for open prompt. Seeconfig.demo.luafor more information.
What must be considered during update?
- Compare your
config.demo.luawith yourconfig.luato consider new options (seeNew since 1.3.2marks).
1.3.1 (2024-03-13)
- Add
Config.ImageServerBlacklistto block specific image servers. Seeconfig.demo.luafor more information. - Add FAQ to
README.md.
What must be considered during update?
- New language keys added (see
New since 1.3.1marks). Please add it to your language file(s). - Compare your
config.demo.luawith yourconfig.luato consider new options (seeNew since 1.3.1marks).
1.3.0 (2024-03-07)
- Extend comments of
config.demo.luafor more clarity. - Add some debug prints to
actions.luabecause in newer versions ofvorp_coresometimes (especially on many players) no char data available if should. - Add torn sheet for broken image (e.g. that can no longer be found).
- Add alternative style of bulletin board. See examples in
config.demo.luawith new poster configuration attributealternative_style. - Add new optional "close bulletin board on damage or combat" feature. See
Config.HideOnCombatOrDamageinconfig.demo.lua.
What must be considered during update?
- New language keys added (see
New since 1.3.0marks). Please add it to your language file(s). - Compare your
config.demo.luawith yourconfig.luato consider new options (seeNew since 1.3.0marks).
1.2.2 (2024-02-07)
- Image urls with search params like
https://example.com/image.jpg?xyz=123are now supported, too.
1.2.1 (2024-01-18)
- Update example
map/bulletin_boards_config.luaand add missinggroupproperty.
1.2.0 (2023-07-13)
- Add option to disable creation of text or image posts (globally or per board).
- Add prev/next buttons to poster details for better navigation.
- Add "pinboard service". Players can pay a fee to post everywhere at once in a pinboard group.
What must be considered during update?
- New language keys added (see
New since 1.2.0marks). Please add it to your language file(s). - Compare your
config.demo.luawith yourconfig.luato consider new options.
1.1.9 (2023-07-05)
- Fix
jpegsupport for images (currentlyjpg,jpeg,pngandwebmare supported).
1.1.8 (2023-03-23)
- Add new required board property
group. Restricts "post to all" feature to specific board groups. - Add new optional board property
restrict_view_by_jobs. Restricts the access to view a board (and blip) to one or more specific jobs.
1.1.7 (2023-03-17)
- Webhooks can now optionally configured each board.
1.1.6
Config.JobRemovePermissionsnow checks correctly if job grade is equal or higher than the required grade.
1.1.5
- Add new
restrict_create_by_jobsinConfig.Postersto restrict the creation of new posters to one or more specific jobs. See config.demo.lua for more information.
1.1.4
- Remove unnecessary print output.
1.1.3
- Add optional new config attribute
Config.DiscordWebhook.webhook_url_newfor only new pinboard notifications. - Add optional new config attribute
Config.DiscordWebhook.anonymous_newwhich hides the character name forwebhook_url_newnotifications. This have no effect towebhook_urlnotifications. - Add optional new config attribute
Config.DiscordWebhook.webhook_url_removedfor only removed pinboard notifications. - Add optional new config attribute
Config.DiscordWebhook.anonymous_removerwhich hides the character name forwebhook_url_removednotifications. This have no effect towebhook_urlnotifications. - Change config attribute
Config.DiscordWebhook.webhook_urlto be optional. It still sends all types of notifications to the same webhook but all authors and removers are not anonymous. - Add new translation
discord_anonymous_userfor anonymous characters forwebhook_url_newandwebhook_url_removednotifications. - Moved changelog from
README.mdtoCHANGELOG.md.
1.1.2
- Add
hide_blipproperty forConfig.Posters. If set totrueno blip is shown on the map for the related pinboard.
1.1.1
- Order of text sections are now correct if inserted between two existing sections.
1.1.0
- Add possibility to pin a new note everywhere at once.
- Permissions of new feature is configurable for groups and character names (full names).
- Add new language keys
discord_location_everywhere,post_everywhere_at_once,post_everywhere_at_once_every_whereandpost_everywhere_at_once_only_here. - Update discord webhook to show as location "everwhere" if someone uses the new feature.
- Admins always have the permission to use the new feature.
1.0.2
- Results of automated processes are shown in discord more clear, e.g. "System" instead of character name.
- Results of console commands are shown in discord more clear, e.g. "Marti McFly (via Console)".
- Add
Config.DiscordWebhook.system_user_aliasto config file, see example inconfig.demo.lua. - Add key
discord_console_commandto languages. - Fix to many linebreaks in poster text.
1.0.1
- Add sorting for notice order on bulletin boards.
1.0.0
Initial release.
