REC_Farm
Stracture
Installation, configuration, and usage for REC_Farm.
- Added
- Updated
The following configuration files and manifest are taken from the current source.
config/sh_config.lua
---@type REC_Farm.Shared.Enum
local shEnums = require "@REC_Farm.shared.sh_enum"
local roles = shEnums.roles
local permissions = shEnums.permissions
local actionTypes = shEnums.actionTypes
local toolKinds = shEnums.toolKinds
---@class REC_Farm.Shared.Config
local config = {}
---[[
--- Debug mode
---]]
---@type boolean
config.debugMode = true
---[[
--- Data files (crops, animals, structures, recipes, land, tools, diseases, skills, obstacles, tutorial)
--- Everything a server owner adds lives in config/data/, the core never needs a change
---]]
---@type REC_Farm.Data.Crops
config.crops = require "@REC_Farm.config.data.sh_crops"
---@type REC_Farm.Data.Animals
config.animals = require "@REC_Farm.config.data.sh_animals"
---@type REC_Farm.Data.Structures
config.structures = require "@REC_Farm.config.data.sh_structures"
---@type REC_Farm.Data.Recipes
config.recipes = require "@REC_Farm.config.data.sh_recipes"
---@type REC_Farm.Data.Sites
config.sites = require "@REC_Farm.config.data.sh_sites"
---@type REC_Farm.Data.Tools
config.tools = require "@REC_Farm.config.data.sh_tools"
---@type REC_Farm.Data.Diseases
config.diseases = require "@REC_Farm.config.data.sh_diseases"
---@type REC_Farm.Data.Skills
config.skills = require "@REC_Farm.config.data.sh_skills"
---@type REC_Farm.Data.Obstacles
config.obstacles = require "@REC_Farm.config.data.sh_obstacles"
---@type REC_Farm.Data.Tutorial
config.tutorial = require "@REC_Farm.config.data.sh_tutorial"
---@type REC_Farm.Data.Difficulty
config.difficulty = require "@REC_Farm.config.data.sh_difficulty"
---[[
--- Generic items (seeds, feed and products are declared in the data files)
---]]
config.items = {
fertilizer = "rec_farm_fertilizer",
compost = "rec_farm_compost",
manure = "rec_farm_manure",
repairKit = "rec_farm_repair_kit",
landDeed = "rec_farm_land_deed",
}
---[[
--- Quality grades
--- Every harvest, animal product and processed good is a separate item per star:
--- itemFormat turns "rec_farm_tomato" + 3 into "rec_farm_tomato_3star"
---]]
config.quality = {
---@type integer
minStars = 1,
---@type integer
maxStars = 5,
---@type string
itemFormat = "%s_%dstar",
---@type string
itemPattern = "^(.-)_(%d)star$",
}
---[[
--- Farmland grid, one cell per crop, aligned to the site origin
---]]
config.grid = {
---@type number
cellSize = 1.5, -- meters
---@type number
plantOffsetZ = 0.0,
}
---[[
--- Distances (meters)
---]]
config.distance = {
interact = 3.0,
target = 2.5,
purchasePoint = 2.0,
tillReach = 2.0,
structureInteract = 3.5,
animalInteract = 3.0,
leadRadius = 30.0,
inspectCamera = 2.2,
}
---[[
--- Client streaming
--- A farm is sent to a client once the player is within farmDistance of the site,
--- entities are only created within renderDistance of the player and never more than maxObjects
---]]
config.streaming = {
---@type number
farmDistance = 250.0,
---@type number
renderDistance = 70.0,
---@type number
animalDistance = 120.0,
---@type integer
maxObjects = 400,
---@type integer
maxWeedObjects = 120,
---@type integer
updateInterval = 1000, -- ms
---@type integer
spawnBudgetPerTick = 12,
}
---[[
--- Activity - when does simulation time advance for a farm
--- A farm only lives while it is "active". Offline time and server downtime are never added.
---
--- members_online : at least one member (owner / manager / worker) is online (default)
--- owner_online : the owner is online
--- anyone_nearby : any player is within streaming distance of the site
--- always : whenever the server is running
---
--- NOTE: the choice of who keeps a farm active is a game design decision, see the delivery notes
---]]
config.activity = {
---@type REC_Farm.Shared.Enum.ActivityModes
mode = "members_online",
}
---[[
--- Simulation tick
---]]
config.sim = {
---@type integer
tickInterval = 10, -- seconds
---@type integer
maxStep = 60, -- seconds, a hitch never advances a farm further than this in one tick
}
---[[
--- Structure placement (edit mode)
--- walk : the ghost floats in front of the player, rotate / raise with keys
--- gizmo : REC_WorldManager's editor (falls back to walk when it is not running)
---]]
config.placement = {
---@type REC_Farm.Shared.Enum.PlacementModes
mode = "walk",
---@type number
distance = 4.0,
---@type number
minDistance = 1.5,
---@type number
maxDistance = 12.0,
---@type number
rotationStep = 5.0,
---@type number
heightStep = 0.05,
---@type number
maxHeightOffset = 1.5,
---@type number
snapRotation = 0.0, -- 0 = free, 15 = snap to 15 degree steps
---@type integer
ghostAlpha = 160,
---@type { r: integer, g: integer, b: integer, }
validColor = { r = 60, g = 220, b = 100, },
---@type { r: integer, g: integer, b: integer, }
invalidColor = { r = 220, g = 60, b = 60, },
keys = {
confirm = 191, -- ENTER
cancel = 202, -- BACKSPACE
rotateLeft = 174, -- LEFT
rotateRight = 175, -- RIGHT
raise = 172, -- UP
lower = 173, -- DOWN
closer = 15, -- SCROLL UP
further = 14, -- SCROLL DOWN
placeOnGround = 47, -- G
},
}
---[[
--- Construction
--- instant : the building is done as soon as it is placed
--- timed : the building needs its buildTime of active farm time (players are free meanwhile)
---]]
config.construction = {
---@type REC_Farm.Shared.Enum.ConstructionModes
mode = "timed",
---@type string
scaffoldModel = "prop_ld_farm_table01",
}
---[[
--- Weather
--- GTA weather names to the modifiers applied while that weather is active
---]]
config.weather = {
---@type boolean
enabled = true,
---@type table<string, REC_Farm.Shared.Config.WeatherModifier>
modifiers = {
["RAIN"] = { moisturePerHour = 25.0, growthMultiplier = 1.0, },
["THUNDER"] = { moisturePerHour = 35.0, growthMultiplier = 0.9, },
["CLEARING"] = { moisturePerHour = 5.0, growthMultiplier = 1.0, },
["OVERCAST"] = { moisturePerHour = 0.0, growthMultiplier = 1.0, },
["CLOUDS"] = { moisturePerHour = 0.0, growthMultiplier = 1.0, },
["EXTRASUNNY"] = { moisturePerHour = -6.0, growthMultiplier = 1.05, },
["SMOG"] = { moisturePerHour = -2.0, growthMultiplier = 0.95, },
["FOGGY"] = { moisturePerHour = 2.0, growthMultiplier = 1.0, },
["SNOW"] = { moisturePerHour = 0.0, growthMultiplier = 0.4, },
["BLIZZARD"] = { moisturePerHour = 0.0, growthMultiplier = 0.2, },
["XMAS"] = { moisturePerHour = 0.0, growthMultiplier = 0.4, },
["HALLOWEEN"] = { moisturePerHour = 0.0, growthMultiplier = 1.0, },
},
---@type REC_Farm.Shared.Config.WeatherModifier
default = { moisturePerHour = 0.0, growthMultiplier = 1.0, },
}
---[[
--- Progress bars per action (duration in ms, anims and props)
---]]
---@type table<REC_Farm.Shared.Enum.ActionTypes, REC_Farm.Shared.Config.Action>
config.actions = {
[actionTypes.clear_obstacle] = { duration = 6000, anim = { dict = "amb@world_human_hammering@male@base", clip = "base", }, },
[actionTypes.till] = { duration = 4000, anim = { dict = "amb@world_human_gardener_plant@male@base", clip = "base", }, },
[actionTypes.plant] = { duration = 3500, anim = { dict = "amb@world_human_gardener_plant@male@base", clip = "base", }, },
[actionTypes.water] = { duration = 3000, anim = { dict = "weapon@w_sp_jerrycan", clip = "fire", }, prop = { model = "prop_wateringcan", bone = 28422, pos = vector3(0.0, 0.0, 0.0), rot = vector3(0.0, 0.0, 0.0), }, },
[actionTypes.fertilize] = { duration = 3500, anim = { dict = "amb@world_human_gardener_plant@male@base", clip = "base", }, },
[actionTypes.weed] = { duration = 4500, anim = { dict = "amb@world_human_gardener_plant@male@base", clip = "base", }, },
[actionTypes.treat_crop] = { duration = 4000, anim = { dict = "amb@world_human_gardener_plant@male@base", clip = "base", }, },
[actionTypes.harvest] = { duration = 4500, anim = { dict = "amb@world_human_gardener_plant@male@base", clip = "base", }, },
[actionTypes.clear_dead] = { duration = 4000, anim = { dict = "amb@world_human_gardener_plant@male@base", clip = "base", }, },
[actionTypes.fill_can] = { duration = 3000, anim = { dict = "amb@world_human_gardener_plant@male@base", clip = "base", }, },
[actionTypes.fill_feed] = { duration = 3500, anim = { dict = "amb@world_human_gardener_plant@male@base", clip = "base", }, },
[actionTypes.fill_water] = { duration = 3500, anim = { dict = "weapon@w_sp_jerrycan", clip = "fire", }, },
[actionTypes.clean_manure] = { duration = 4000, anim = { dict = "amb@world_human_gardener_plant@male@base", clip = "base", }, },
[actionTypes.pet] = { duration = 2500, anim = { dict = "creatures@rottweiler@tricks@", clip = "petting_franklin", }, },
[actionTypes.brush] = { duration = 4000, anim = { dict = "mini@repair", clip = "fixing_a_player", }, },
[actionTypes.treat_animal] = { duration = 5000, anim = { dict = "mp_medic", clip = "cpr_pumpchest", }, },
[actionTypes.collect] = { duration = 5000, anim = { dict = "amb@world_human_gardener_plant@male@base", clip = "base", }, },
[actionTypes.ship] = { duration = 2000, },
[actionTypes.process_start] = { duration = 3000, anim = { dict = "mini@repair", clip = "fixing_a_player", }, },
[actionTypes.process_collect] = { duration = 2500, anim = { dict = "mini@repair", clip = "fixing_a_player", }, },
[actionTypes.build] = { duration = 4000, anim = { dict = "amb@world_human_hammering@male@base", clip = "base", }, },
[actionTypes.upgrade] = { duration = 4000, anim = { dict = "amb@world_human_hammering@male@base", clip = "base", }, },
[actionTypes.repair_tool] = { duration = 4000, anim = { dict = "mini@repair", clip = "fixing_a_player", }, },
}
---[[
--- Minimum role for every permission (a higher role always includes a lower one)
---]]
---@type table<REC_Farm.Shared.Enum.Permissions, REC_Farm.Shared.Enum.Roles>
config.permissions = {
[permissions.land_purchase] = roles.owner,
[permissions.land_expand] = roles.owner,
[permissions.farm_edit] = roles.manager,
[permissions.building_purchase] = roles.manager,
[permissions.building_upgrade] = roles.manager,
[permissions.building_remove] = roles.owner,
[permissions.clear_obstacle] = roles.worker,
[permissions.till] = roles.worker,
[permissions.plant] = roles.worker,
[permissions.crop_care] = roles.worker,
[permissions.harvest] = roles.worker,
[permissions.clear_dead] = roles.worker,
[permissions.processing] = roles.worker,
[permissions.animal_purchase] = roles.manager,
[permissions.animal_care] = roles.worker,
[permissions.animal_collect] = roles.worker,
[permissions.animal_ship] = roles.manager,
[permissions.animal_rename] = roles.manager,
[permissions.animal_pasture] = roles.worker,
[permissions.manage_members] = roles.manager,
[permissions.farm_settings] = roles.owner,
[permissions.storage] = roles.worker,
}
---[[
--- Farmland cell visuals (the crop object is the crop model, the soil is a marker)
---]]
config.cellVisual = {
---@type boolean
drawSoilMarker = true,
---@type integer
soilMarkerType = 1,
---@type { r: integer, g: integer, b: integer, a: integer, }
soilMarkerColor = { r = 120, g = 80, b = 40, a = 70, },
---@type number
soilMarkerDrawDistance = 25.0,
---@type integer
refreshInterval = 4000, -- ms
---[[
--- Small props drawn on a cell as its weed level climbs (1 - 3 of them)
---]]
---@type string[]
weedModels = { "prop_fernba", "prop_fernbb", "prop_plant_fern_01a", },
---@type number
weedSpread = 0.55,
---[[
--- Marker on the tilled cell the player can plant on
---]]
---@type number
plantReach = 1.6,
}
---[[
--- Inspection camera ("look closer")
---]]
config.inspection = {
---@type integer
transitionTime = 700, -- ms
---@type number
cropFov = 35.0,
---@type number
animalFov = 40.0,
---@type number
cropHeight = 1.1,
---@type number
animalHeight = 1.3,
---@type integer
refreshInterval = 1500, -- ms
keys = {
exit = 202, -- BACKSPACE
actions = 51, -- E
},
}
---[[
--- Watering can (ox_inventory durability is the water level)
---]]
config.wateringCan = {
---@type integer
capacity = 100,
---@type integer
costPerUse = 10,
---@type number
moisturePerUse = 40.0,
---@type integer
troughUnitsPerCan = 20,
}
---[[
--- Tool durability (ox_inventory durability, 100 is new)
--- usePerAction is subtracted per action, at 0 the tool is broken until repaired
---]]
config.toolDurability = {
---@type boolean
enabled = true,
---@type number
repairKitRestore = 100.0,
}
---[[
--- Management panel command (the panel itself is gated by farm membership on the server)
---]]
config.management = {
---@type string
command = "farm",
---@type string
editCommand = "farmedit",
}
---[[
--- Blips
---]]
config.blips = {
---@type boolean
showPurchasePoints = true,
purchasePoint = { sprite = 469, color = 2, scale = 0.7, },
ownFarm = { sprite = 469, color = 25, scale = 0.8, },
}
---[[
--- Farm boundary drawing while editing / placing
---]]
config.boundary = {
---@type { r: integer, g: integer, b: integer, a: integer, }
ownedColor = { r = 60, g = 220, b = 100, a = 120, },
---@type { r: integer, g: integer, b: integer, a: integer, }
availableColor = { r = 220, g = 200, b = 60, a = 120, },
---@type number
height = 1.0,
}
---[[
--- Animal visuals (client)
--- manureModel placeholder prop for a manure spot, swap for an addon prop
--- nameTagDistance draw the animal's name above its head within this distance (0 = off)
--- ai controller tick, stuck detection and follow distances
---]]
config.animalVisual = {
---@type string
manureModel = "prop_rock_4_c",
---@type number
nameTagDistance = 8.0,
---@type integer
resolveInterval = 2000, -- ms, how often peds of streamed animals are looked up by net id
ai = {
---@type integer
tickInterval = 500, -- ms
---@type integer
reportInterval = 5000, -- ms, position / state reports of a controlled ped (server: sv_config animals.reportInterval)
---@type number
arriveDistance = 1.6,
---@type number
followDistance = 2.5,
---@type number
followRetaskDistance = 5.0,
---@type number
wanderSpeed = 1.0,
---@type number
followSpeed = 1.8,
---@type integer
idleTime = { 4000, 12000, }, -- ms, min / max before the next decision
---@type integer
restTime = { 10000, 25000, }, -- ms
---@type integer
stuckTime = 10000, -- ms without moving before the ped is re-tasked
---@type number
stuckDistance = 0.4,
---@type integer
stuckRetries = 2, -- re-tasks before the server is asked to reset the ped
---@type number
escapeRadius = 25.0,
---@type number
homeRadius = 6.0, -- an escaped animal led inside housing radius + this is home
},
}
---[[
--- Tool item required per action (nil = no tool)
---]]
---@type table<REC_Farm.Shared.Enum.ActionTypes, REC_Farm.Shared.Enum.ToolKinds>
config.actionTools = {
[actionTypes.till] = toolKinds.hoe,
[actionTypes.water] = toolKinds.wateringCan,
[actionTypes.weed] = toolKinds.scythe,
[actionTypes.harvest] = toolKinds.basket,
[actionTypes.clear_dead] = toolKinds.scythe,
[actionTypes.clean_manure] = toolKinds.shovel,
[actionTypes.brush] = toolKinds.brush,
}
return config
---@class REC_Farm.Shared.Config.Action
---@field duration integer
---@field anim? { dict: string, clip: string, }
---@field prop? { model: string, bone: integer, pos: vector3, rot: vector3, }
---@class REC_Farm.Shared.Config.WeatherModifier
---@field moisturePerHour number
---@field growthMultiplier number
