ns-vineyard â
Grape growing + wine production system. Cross-framework via ns-lib.
Flow â
[Vineyard plot] [Press machine] [Cellar â fixed slots]
3Ã3 cell, 2Ã2 vine public, open to all per-player, client-only
â unlock ($100/cell) â 10 grapes = 1 bucket â place a barrel
â grow vines (5 min) â animation + cooldown â 2 buckets = full barrel
â harvest (1-10 grapes) â wait (quality 1â5)
â collect (4 bottles wine_q[N])Requirements â
- ns-lib (mandatory) â one of the supported frameworks must be running (VORP, RSG-Core, RedEM:RP, ESX, QBCore)
- oxmysql or mysql-async
- (Recommended) ox_lib â nicer notifications
Installation â
- Copy this folder to
resources/ns-vineyard/ - Apply the
sql/install.sqlfile to your database - Add the items below to your framework's item DB (see Items)
- Add
ensure ns-liband thenensure ns-vineyardtoserver.cfg - Restart the server
Items (add to your inventory) â
| Item name | Description | Stackable |
|---|---|---|
grape | Grape | yes |
grape_juice | Grape Juice (bucket) | yes |
wine_q1 | Young Wine | yes |
wine_q2 | Mature Wine | yes |
wine_q3 | Quality Wine | yes |
wine_q4 | Premium Wine | yes |
wine_q5 | Vintage Wine | yes |
ox_inventory (data/items.lua) â
['grape'] = { label = 'Grape', weight = 50, stack = true },
['grape_juice'] = { label = 'Grape Juice', weight = 500, stack = true },
['wine_q1'] = { label = 'Young Wine', weight = 600, stack = true },
['wine_q2'] = { label = 'Mature Wine', weight = 600, stack = true },
['wine_q3'] = { label = 'Quality Wine', weight = 600, stack = true },
['wine_q4'] = { label = 'Premium Wine', weight = 600, stack = true },
['wine_q5'] = { label = 'Vintage Wine', weight = 600, stack = true },vorp_inventory (SQL) â
INSERT INTO items (item, label, type, usable, can_remove) VALUES
('grape', 'Grape', 'item_standard', 0, 1),
('grape_juice', 'Grape Juice', 'item_standard', 0, 1),
('wine_q1', 'Young Wine', 'item_standard', 0, 1),
('wine_q2', 'Mature Wine', 'item_standard', 0, 1),
('wine_q3', 'Quality Wine', 'item_standard', 0, 1),
('wine_q4', 'Premium Wine', 'item_standard', 0, 1),
('wine_q5', 'Vintage Wine', 'item_standard', 0, 1);qb-core / rsg-core (shared/items.lua) â
grape = { name = 'grape', label = 'Grape', weight = 50, type = 'item', image = 'grape.png', unique = false, useable = false, shouldClose = false, combinable = nil, description = 'A grape.' },
grape_juice = { name = 'grape_juice', label = 'Grape Juice', weight = 500, type = 'item', image = 'grape_juice.png', unique = false, useable = false, shouldClose = false, combinable = nil, description = 'A bucket of grape juice.' },
wine_q1 = { name = 'wine_q1', label = 'Young Wine', weight = 600, type = 'item', image = 'wine.png', unique = false, useable = true, shouldClose = true, combinable = nil },
wine_q2 = { name = 'wine_q2', label = 'Mature Wine', weight = 600, type = 'item', image = 'wine.png', unique = false, useable = true, shouldClose = true, combinable = nil },
wine_q3 = { name = 'wine_q3', label = 'Quality Wine', weight = 600, type = 'item', image = 'wine.png', unique = false, useable = true, shouldClose = true, combinable = nil },
wine_q4 = { name = 'wine_q4', label = 'Premium Wine', weight = 600, type = 'item', image = 'wine.png', unique = false, useable = true, shouldClose = true, combinable = nil },
wine_q5 = { name = 'wine_q5', label = 'Vintage Wine', weight = 600, type = 'item', image = 'wine.png', unique = false, useable = true, shouldClose = true, combinable = nil },Configuration â
All settings live in config.lua. The most important ones:
| Setting | Default | Description |
|---|---|---|
Config.PlotOrigin | vector3(2604, -1041, 47) | Center coordinate of the vineyard plot â change for your server |
Config.PressLocation | vector3(2640, -1042, 46) | Press machine location |
Config.CellarLocation | vector3(2630, -1050, 47) | Cellar center (slots are arranged nearby) |
Config.BarrelSlots | 5 slots, 1.5m apart on the x axis | Position + heading per slot |
Config.GrowDuration | 300 | Seconds, from vine to harvestable grapes (5 min â test/dev) |
Config.QualityThresholds | {0,300,900,1800,3600} | Quality tier thresholds (1â5) |
Config.CellCost | 100 | Cost to unlock a cell |
Config.WinePerBarrel | 4 | Number of bottles produced per barrel |
Set the time scale to medium or slow for a live server â see the comment lines in the config.lua file referenced at the top of the README.
Architecture â
client (each player sees their own props)
â propmgr.lua â local-only prop registry, cleanup
â main.lua â state + DrawText3DLocal helper
â vineyard.lua â vine props, unlock cell + harvest prompt
â press.lua â press animation + prompt
â barrel.lua â slot props, add bucket + collect prompt + DrawText3D quality
server (DB + validation)
â db.lua â SQL queries (NSLib.Query)
â main.lua â lifecycle, OnPlayerLoaded, sync push
â vineyard.lua â UnlockCell, HarvestVine (mutex + dist + time check)
â press.lua â PressGrapes (cooldown + dist check)
â barrel.lua â PlaceBarrel, AddBucket, CollectWine (slot-based)Sync strategy â
- Player join â
OnPlayerLoadedâ DB load â cache âsyncStateevent push - The client keeps the cache + server clock offset and does time calculations locally
- On an action â server validate â DB update â cache update â new
syncState - All time-based UI (ripening countdown, quality progress) is rendered on the client only
Anti-cheat â
- Cell ID, vine idx and slot ID are validated on the server
- Distance is checked server-side on every action (
GetEntityCoords) - Inventory operations are atomic (mutex per-source)
- A cell can't be unlocked without the cost being deducted
- Quality is computed from
filled_at, based on server time
FAQ â
Q: The vine prop doesn't show up A: Verify the Config.VineModelEmpty / Config.VineModelRipe hashes against your own RedM build (CodeWalker / OpenIV).
Q: DrawText3D renders special characters incorrectly A: RedM supports UTF-8 via LITERAL_STRING, but some fonts are incompatible. Try SetTextFontForCurrentCommand(2) or (9) instead of (0).
Q: I want to charge for the press A: Add an NSLib.RemoveMoney call in server/press.lua and a PressCost in the config.
Q: I want a single wine item with ox_inventory metadata A: Change Config.Items.wineQ in config.lua to a single name and, in CollectWine in server/barrel.lua, call NSLib.AddItem(source, 'wine', amount, { quality = quality }). Collapse the 5 items in the README into a single wine.
License â
MIT
