Philosophie de conception du système agricole
Un système agricole et agricole apporte un rythme complètement différent aux serveurs de jeu de rôle FiveM, offrant aux joueurs une alternative relaxante aux activités criminelles à haute adrénaline et aux forces de l'ordre. Les meilleurs systèmes agricoles créent une boucle économique autonome dans laquelle les joueurs achètent des semences, plantent des cultures sur des terres agricoles désignées, s'en occupent au cours de cycles de croissance en temps réel, récoltent les produits et les vendent au marché dans un but lucratif. Le défi de conception consiste à rendre le système suffisamment attrayant pour que les joueurs reviennent régulièrement sans que cela prenne tellement de temps que cela ressemble à une corvée. Utilisez des cycles de croissance en temps réel qui se poursuivent même lorsque le joueur est hors ligne, afin que les agriculteurs se connectent pour trouver leurs cultures à différents stades de croissance. Le modèle de données de base doit suivre chaque parcelle de culture individuelle avec sa position, son type de culture, son stade de croissance actuel, son horodatage de plantation, son niveau d'eau et son évaluation de la qualité. Stockez tout cela côté serveur dans une base de données afin que l'état de la batterie persiste lors des redémarrages du serveur et soit protégé contre les manipulations côté client.
Schéma de plantation de cultures et de base de données
Le système de plantation commence avec un joueur sélectionnant des graines dans son inventaire et les plaçant sur des zones de terres agricoles valides. Définissez les terres agricoles comme des zones polygonales configurables sur la carte où la plantation est autorisée, empêchant les joueurs de cultiver sur les trottoirs ou à l'intérieur des bâtiments. Chaque parcelle agricole doit avoir un nombre limité d'emplacements en fonction de la taille du terrain, et les joueurs peuvent louer ou acheter des terres agricoles via un PNJ ou un système immobilier. Lorsqu'un joueur plante une graine, créez un enregistrement de base de données qui suit la culture tout au long de son cycle de vie. Voici un schéma de base de données pratique et le gestionnaire de plantation côté serveur :
CREATE TABLE IF NOT EXISTS farm_crops (
id INT AUTO_INCREMENT PRIMARY KEY,
owner VARCHAR(50) NOT NULL,
farm_id VARCHAR(50) NOT NULL,
crop_type VARCHAR(50) NOT NULL,
position_x FLOAT NOT NULL,
position_y FLOAT NOT NULL,
position_z FLOAT NOT NULL,
planted_at BIGINT NOT NULL,
growth_stage INT DEFAULT 0,
water_level FLOAT DEFAULT 100.0,
quality FLOAT DEFAULT 1.0,
is_harvestable TINYINT DEFAULT 0,
is_dead TINYINT DEFAULT 0,
last_watered BIGINT DEFAULT 0,
INDEX idx_owner (owner),
INDEX idx_farm (farm_id)
);
CREATE TABLE IF NOT EXISTS farm_plots (
id INT AUTO_INCREMENT PRIMARY KEY,
farm_id VARCHAR(50) NOT NULL UNIQUE,
owner VARCHAR(50) DEFAULT NULL,
max_slots INT DEFAULT 20,
rent_price INT DEFAULT 500,
coords_center_x FLOAT NOT NULL,
coords_center_y FLOAT NOT NULL,
coords_center_z FLOAT NOT NULL,
radius FLOAT DEFAULT 30.0
);
RegisterNetEvent('farming:server:plantCrop', function(cropType, position)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local citizenid = Player.PlayerData.citizenid
local seedItem = 'seed_' .. cropType
if not Player.Functions.GetItemByName(seedItem) then
return TriggerClientEvent('QBCore:Notify', src, 'You need seeds to plant', 'error')
end
local farmId = GetFarmAtPosition(position)
if not farmId then
return TriggerClientEvent('QBCore:Notify', src, 'You can only plant on farmland', 'error')
end
local currentCrops = MySQL.scalar.await(
'SELECT COUNT(*) FROM farm_crops WHERE farm_id = ? AND is_dead = 0',
{farmId}
)
local maxSlots = MySQL.scalar.await(
'SELECT max_slots FROM farm_plots WHERE farm_id = ?', {farmId}
)
if currentCrops >= maxSlots then
return TriggerClientEvent('QBCore:Notify', src, 'Farm is full', 'error')
end
Player.Functions.RemoveItem(seedItem, 1)
MySQL.insert(
'INSERT INTO farm_crops (owner, farm_id, crop_type, position_x, position_y, position_z, planted_at, last_watered) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
{citizenid, farmId, cropType, position.x, position.y, position.z, os.time(), os.time()}
)
TriggerClientEvent('QBCore:Notify', src, 'Planted ' .. cropType, 'success')
TriggerClientEvent('farming:client:spawnCropProp', -1, position, cropType, 0)
end)
Chaque type de culture doit avoir différents paramètres de croissance définis dans un tableau de configuration. Le blé pourrait pousser en 30 minutes réelles en 4 étapes, tandis que le cannabis ou le raisin pourraient prendre plusieurs heures en 6 étapes, récompensant les agriculteurs patients avec des produits de plus grande valeur. Le stade de croissance détermine quel modèle d'accessoire est affiché dans le monde, passant d'une petite pousse à une plante adulte au fil du temps.
Moteur de cycle de croissance et arrosage
Le moteur de cycle de croissance est une boucle côté serveur qui vérifie périodiquement toutes les cultures plantées et avance leurs étapes de croissance en fonction du temps écoulé et des conditions telles que le niveau d'eau. Exécutez-le comme un thread de serveur chronométré qui s'exécute toutes les quelques minutes, calculant si chaque culture doit passer à l'étape suivante en fonction de la durée de croissance de son type de culture et du temps écoulé depuis la plantation. Le niveau d'eau est le principal mécanisme qui maintient les joueurs engagés : les cultures consomment de l'eau au fil du temps, et si le niveau d'eau descend à zéro, la croissance s'arrête et la qualité de la culture se dégrade. Les joueurs doivent retourner à leur ferme et utiliser un arrosoir ou un système d'irrigation pour reconstituer les niveaux d'eau. Voici le moteur de croissance côté serveur :
local CropConfig = {
wheat = {
stages = 4,
growthTime = 1800, -- 30 min total, ~7.5 min per stage
waterConsumption = 5, -- per cycle
baseYield = 5,
sellPrice = 50
},
corn = {
stages = 5,
growthTime = 3600,
waterConsumption = 7,
baseYield = 4,
sellPrice = 80
},
tomato = {
stages = 4,
growthTime = 2400,
waterConsumption = 8,
baseYield = 6,
sellPrice = 65
},
grape = {
stages = 6,
growthTime = 7200,
waterConsumption = 4,
baseYield = 8,
sellPrice = 120
}
}
CreateThread(function()
while true do
Wait(60000 * 5) -- Run every 5 minutes
local crops = MySQL.query.await(
'SELECT * FROM farm_crops WHERE is_dead = 0 AND is_harvestable = 0'
)
for _, crop in ipairs(crops or {}) do
local config = CropConfig[crop.crop_type]
if not config then goto continue end
local elapsed = os.time() - crop.planted_at
local stageTime = config.growthTime / config.stages
local expectedStage = math.min(math.floor(elapsed / stageTime), config.stages)
-- Degrade water
local newWater = math.max(0, crop.water_level - config.waterConsumption)
local newQuality = crop.quality
-- Quality degrades without water
if newWater <= 0 then
newQuality = math.max(0.3, crop.quality - 0.05)
expectedStage = crop.growth_stage -- Pause growth
end
local isHarvestable = expectedStage >= config.stages and newWater > 0
if expectedStage ~= crop.growth_stage or newWater ~= crop.water_level then
MySQL.update(
'UPDATE farm_crops SET growth_stage = ?, water_level = ?, quality = ?, is_harvestable = ? WHERE id = ?',
{expectedStage, newWater, newQuality, isHarvestable and 1 or 0, crop.id}
)
if expectedStage ~= crop.growth_stage then
TriggerClientEvent('farming:client:updateCropStage', -1,
crop.id, expectedStage, crop.crop_type,
vector3(crop.position_x, crop.position_y, crop.position_z))
end
end
::continue::
end
end
end)
Le mécanicien d’arrosage doit être interactif plutôt que fastidieux. Donnez au joueur un arrosoir qui déclenche une animation lorsqu'il est utilisé à proximité de cultures et arrosez plusieurs cultures à proximité en une seule action plutôt que de nécessiter un arrosage un par un. Pour les grandes exploitations, introduisez une mise à niveau du système d’irrigation qui arrose automatiquement toutes les cultures de la parcelle à intervalles réguliers, réduisant ainsi le travail manuel mais nécessitant un investissement initial en matériaux. Affichez le niveau d'eau et la progression de la croissance de chaque culture via un petit indicateur au-dessus de l'accessoire lorsque le joueur le regarde, en utilisant un texte 3D ou une superposition du système cible.
Récolte et qualité des produits
La récolte est le moment de récompense qui rend l’ensemble de la boucle agricole satisfaisante. Lorsqu’une culture atteint son stade final de croissance et a été adéquatement arrosée, elle devient récoltable. Le joueur interagit avec la récolte, joue une animation de récolte et reçoit des produits dans son inventaire. La quantité et la qualité des produits dépendent de la façon dont le joueur a entretenu la culture pendant son cycle de croissance : un arrosage constant produit des articles de meilleure qualité qui se vendent plus cher, tandis que les cultures négligées produisent moins d'articles de moindre qualité. Mettez en œuvre un multiplicateur de qualité qui affecte à la fois le rendement et le prix de vente, créant ainsi une forte incitation à une agriculture attentive. Après la récolte, supprimez la culture de la base de données et supprimez l'accessoire du monde, libérant ainsi l'emplacement de la parcelle pour la replantation. Envisagez d'ajouter un mécanisme de compostage où les récoltes de mauvaise qualité peuvent être converties en engrais qui améliorent la qualité des cultures futures, créant ainsi une boucle zéro déchet qui récompense l'activité agricole continue.
Système d'élevage
Les animaux ajoutent une deuxième dimension à l'expérience agricole et créent des sources de revenus supplémentaires. Mettez en œuvre des animaux achetables comme des poulets, des vaches et des moutons qui sont placés dans des enclos pour animaux désignés sur les terres agricoles. Chaque type d'animal a son propre cycle de production : les poules produisent des œufs toutes les quelques heures, les vaches produisent du lait quotidiennement et les moutons peuvent être tondus périodiquement pour leur laine. Les animaux doivent être nourris à partir de l'inventaire de produits du joueur, connectant le système de culture directement au système animal et créant une boucle économique fermée. Voici une configuration et un système d'alimentation pour animaux de ferme :
Config.Animals = {
chicken = {
model = 'a_c_hen',
purchasePrice = 500,
feedItem = 'wheat',
feedInterval = 3600, -- needs feeding every hour
productionItem = 'eggs',
productionAmount = 3,
productionInterval = 7200, -- produces every 2 hours
maxPerFarm = 10
},
cow = {
model = 'a_c_cow',
purchasePrice = 3000,
feedItem = 'corn',
feedInterval = 5400,
productionItem = 'milk',
productionAmount = 2,
productionInterval = 14400,
maxPerFarm = 5
},
sheep = {
model = 'a_c_sheep',
purchasePrice = 1500,
feedItem = 'wheat',
feedInterval = 4800,
productionItem = 'wool',
productionAmount = 1,
productionInterval = 21600,
maxPerFarm = 8
}
}
RegisterNetEvent('farming:server:feedAnimal', function(animalId)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local animal = MySQL.query.await(
'SELECT * FROM farm_animals WHERE id = ? AND owner = ?',
{animalId, Player.PlayerData.citizenid}
)
if not animal or not animal[1] then return end
animal = animal[1]
local config = Config.Animals[animal.animal_type]
if not Player.Functions.GetItemByName(config.feedItem) then
return TriggerClientEvent('QBCore:Notify', src, 'Need ' .. config.feedItem .. ' to feed', 'error')
end
Player.Functions.RemoveItem(config.feedItem, 1)
MySQL.update(
'UPDATE farm_animals SET last_fed = ?, hunger = 100 WHERE id = ?',
{os.time(), animalId}
)
TriggerClientEvent('QBCore:Notify', src, 'Animal fed successfully', 'success')
end)
Les animaux qui ne sont pas nourris à temps deviennent malheureux, ce qui réduit leur production. S’ils restent trop longtemps sans nourriture, ils cessent complètement de produire. Affichez le statut de l'animal grâce à une interaction cible qui montre le niveau de faim, le bonheur et le temps jusqu'à la prochaine production. Cela crée une routine d'enregistrement quotidienne pour les agriculteurs qui les maintient en contact avec le serveur entre les cycles de croissance des cultures.
Système de marché et vente de produits
Le système de marché connecte les agriculteurs à l’économie des serveurs au sens large. Créez des emplacements de vendeurs PNJ dans les marchés de producteurs, les épiceries et les restaurants autour de la carte où les joueurs peuvent vendre leurs produits. Mettre en œuvre un système de tarification dynamique dans lequel les prix fluctuent en fonction de l'offre et de la demande : si de nombreux agriculteurs cultivent du blé, les prix du blé baissent, ce qui encourage la diversité des cultures. Suivez le volume total des ventes par type de culture sur des fenêtres temporelles glissantes et ajustez les prix en conséquence. Les produits de première qualité issus de cultures de haute qualité se vendent à un multiplicateur supérieur au prix de base, récompensant une agriculture prudente. Envisagez d'ajouter une option d'échange de joueur à joueur où les agriculteurs peuvent installer des étals de marché dans des zones désignées, vendant directement à d'autres joueurs à des prix personnalisés. Cela crée des interactions de jeu de rôle organiques entre les agriculteurs et les acheteurs, et permet aux joueurs entrepreneurs de profiter en achetant des produits en gros bon marché et en les vendant au prix de détail dans les zones à fort trafic.
Effets météorologiques sur l’agriculture
L’intégration météorologique ajoute de l’imprévisibilité et de la stratégie à l’agriculture. Connectez-tu au système météo de ton serveur pour appliquer des modificateurs à la croissance des cultures et à la consommation d'eau. La pluie arrose naturellement toutes les cultures extérieures, réduisant ainsi le besoin d’arrosage manuel pendant les périodes humides. La chaleur extrême augmente la consommation d’eau, obligeant les agriculteurs à arroser plus fréquemment par temps chaud. Les tempêtes peuvent endommager les récoltes, en réduire la qualité ou même détruire les produits non récoltés et restés trop longtemps. Les épisodes de gel pendant les saisons hivernales peuvent tuer complètement certains types de cultures, obligeant les agriculteurs à choisir des variétés résistantes au froid ou à investir dans des serres qui protègent les cultures des effets météorologiques. Mettez en œuvre un système de prévisions météorologiques accessible via une application téléphonique dans le jeu ou une diffusion télévisée afin que les agriculteurs puissent planifier leur calendrier de plantation en fonction des conditions à venir, en ajoutant une couche de planification stratégique qui élève l'expérience agricole au-delà des simples mécanismes de clic et d'attente.
Améliorations et progression de la ferme
Un système de progression donne aux agriculteurs des objectifs à long terme et récompense le jeu constant. Commencez les joueurs avec une petite parcelle pouvant contenir une poignée de cultures, puis laissez-les gagner des extensions grâce à l'XP agricole ou à l'achat direct. Chaque niveau de mise à niveau débloque de nouvelles capacités : des systèmes d'arrosage automatisés qui gèrent l'abreuvement, des enclos pour animaux plus grands pour plus de bétail, une grange pour stocker les surplus de produits, des stations de traitement qui convertissent les matières premières en biens de plus grande valeur comme le blé en farine ou les raisins en vin, et un véhicule tracteur qui accélère la plantation et la récolte sur de grandes parcelles. Suivez l'XP agricole séparément de la progression des autres serveurs pour créer une compétence agricole dédiée qui améliore la qualité du rendement et réduit les temps de croissance aux niveaux supérieurs. Le système de transformation est particulièrement important pour l'économie car il ajoute des étapes à valeur ajoutée entre les produits bruts et les produits finis, créant des opportunités de jeu de rôle dans la chaîne d'approvisionnement dans lequel les agriculteurs vendent des matières premières aux boulangeries, caves ou restaurants appartenant aux joueurs qui les transforment en produits finaux pour les consommateurs.
