GitHub — MM1212/vRP-1: FiveM ( RP addon/framework

becfbdafffeecfdd Новости

.1.1. The Problem

Given a graph G=(V,E)

This “definition” remains vague enough to encompass the most known variants of the VRP. Indeed, not only does the VRP
exist in different flavors (capacitated, multi-depots, with time-windows, with pick-up and delivery, …) but several
slightly different definitions exist in the literature.

In this manual, we will use the definition given by Gilbert Laporte in [Laporte1992]. In this article, a VRP
is designed in such a way that

The last point is important. Indeed, without side constraints and if the graph obeys the triangle inequality
(i.e. d(x,z) leqslant d(x,y) d(y,z)../../_images/mtsp_metric_graph.pngd(x,z) leqslant d(x,y) d(y,z)xzy

The most common side constraints include:

And the list goes on.

For our basic version of the VRP, all vehicles must be used. This version of the VRP
is better known as the mTSP[2]. Some problems can be coined as mTSP and we refer again the reader to [Bektas2006]
to find some examples.

Below you’ll find a picture of a solution of a VRP with 32 cities and 5 vehicles (A-n32-k5) in the
sub-section Visualization with ePix.

.1.5. To hold and check a (C)VRP solution: the CVRPSolution class

To represent a (C)VRP solution, we have defined the CVRPSolution class. Two constructors are available:

Two methods verify the feasibility of the solution:

The CVRPSolution class provides iterators to run through the solution. For instance, the
ComputeObjectiveValue() method — that computes the objective value of the solution — is written as follows:

Because this method is constant and doesn’t change the solution, it uses constant iterators. The CVRPSolution
class also provides the following non constant iterators:

Audio

-- TUNNEL CLIENT API-- play audio source (once)--- url: valid audio HTML url (ex: .ogg/.wav/direct ogg-stream url)--- volume: 0-1--- x,y,z: position (omit for unspatialized)--- max_dist (omit for unspatialized)vRP.playAudioSource(url, volume, x, y, z, max_dist)-- set named audio source (looping)--- name: source name--- url: valid audio HTML url (ex: .ogg/.wav/direct ogg-stream url)--- volume: 0-1--- x,y,z: position (omit for unspatialized)--- max_dist (omit for unspatialized)vRP.setAudioSource(name, url, volume, x, y, z, max_dist)-- remove named audio sourcevRP.removeAudioSource(name)

Database

SQL queries are managed by DB drivers, you can use the default vRP driver vrp_mysql or use a custom one (vrp_mysql has crappy code, see alternatives).

DB drivers will register themselves (as resources) with a specific name to use in cfg/base.lua. Since there is no guarantee about when the driver will be registered, all queries will be cached until that moment.

-- API (PROXY)-- register a DB driver--- name: unique name for the driver--- on_init(cfg): called when the driver is initialized (connection), should return true on success---- cfg: db config--- on_prepare(name, query): should prepare the query (@param notation)--- on_query(name, params, mode): should execute the prepared query---- params: map of parameters---- mode:----- "query": should return rows (list of map of parameter => value), affected----- "execute": should return affected----- "scalar": should return a scalarvRP.registerDBDriver(name, on_init, on_prepare, on_query)-- prepare a query--- name: unique name for the query--- query: SQL string with @params notationvRP.prepare(name, query)-- execute a query--- name: unique name of the query--- params: map of parameters--- mode: default is "query"---- "query": should return rows (list of map of field => value), affected---- "execute": should return affected---- "scalar": should return a scalarvRP.query(name, params, mode)-- shortcut for vRP.query with "execute"vRP.execute(name, params)-- shortcut for vRP.query with "scalar"vRP.scalar(name, params)

Group/permission

Group and permissions are a way to limit features to specific players.
Each group have a set of permissions defined in cfg/groups.lua.
Permissions can be used with most of the vRP modules, giving the ability to create specific garages, item transformers, etc.

Api
-- PROXY API-- return group titlevRP.getGroupTitle(group)-- add a group to a connected uservRP.addUserGroup(user_id,group)-- remove a group from a connected uservRP.removeUserGroup(user_id,group)-- check if the user has a specific groupvRP.hasGroup(user_id,group)-- register a special permission function-- name: name of the permission -> "!name.[...]"-- callback(user_id, parts)--- parts: parts (strings) of the permissions, ex "!name.param1.param2" -> ["name", "param1", "param2"]--- should return true or false/nilvRP.registerPermissionFunction(name, callback)-- check if the user has a specific permissionvRP.hasPermission(user_id, perm)-- check if the user has a specific list of permissions (all of them)vRP.hasPermissions(user_id, perms)-- get user group by group type-- return group name or an empty stringvRP.getUserGroupByType(user_id,gtype)-- return list of connected users by groupvRP.getUsersByGroup(group)-- return list of connected users by permissionvRP.getUsersByPermission(perm)

Inventory

The inventory is autosaved and, as the wallet, gets empty upon death.

Items

Items are simple identifiers associated with a quantity in an inventory. But they can also be parametrics.

Parametrics items are identified like other items in the inventory but also have arguments as: weapon|pistol instead of just an ID. Parametric items don’t contain any data, they are generic item definitions that will be specialized by the arguments.

-- PROXY API-- define an inventory item (call this at server start) (parametric or plain text data)-- idname: unique item name-- name: display name or genfunction-- description: item description (html) or genfunction-- choices: menudata choices (see gui api) only as genfunction or nil-- weight: weight or genfunction---- genfunction are functions returning a correct value as: function(args) return value end-- where args is a list of {base_idname,arg,arg,arg,...}vRP.defInventoryItem(idname,name,description,choices,weight)-- return name, description, weightvRP.getItemDefinition(idname)
vRP.getItemName(idname)
vRP.getItemDescription(idname)
vRP.getItemChoices(idname)
vRP.getItemWeight(idname)-- add item to a connected user inventoryvRP.giveInventoryItem(user_id,idname,amount,notify)-- try to get item from a connected user inventory-- return true if the item has been found and the quantity removedvRP.tryGetInventoryItem(user_id,idname,amount,notify)-- get item amount from a connected user inventoryvRP.getInventoryItemAmount(user_id,idname)-- get connected user inventory-- return map of full idname => amount or nilvRP.getInventory(user_id)-- clear connected user inventoryvRP.clearInventory(user_id)-- compute weight of a list of items (in inventory/chest format)vRP.computeItemsWeight(items)-- return user inventory total weightvRP.getInventoryWeight(user_id)-- return user inventory max weightvRP.getInventoryMaxWeight(user_id)-- open a chest by name-- cb_close(): called when the chest is closedvRP.openChest(source, name, max_weight, cb_close)-- TUNNEL SERVER API-- TUNNEL CLIENT API

Once defined, items can be used by any resources (ex: they can be added to shops).

local Proxy =module("vrp", "lib/Proxy")local Tunnel =require("vrp", "lib/Tunnel")
vRP = Proxy.getInterface("vRP")
vRPclient = Tunnel.getInterface("vRP","vrp_waterbottle")-- create Water bottle itemlocal wb_choices = {} -- (see gui API for menudata choices structure)wb_choices["Drink"] = {function(player,choice) -- add drink actionlocal user_id = vRP.getUserId(player) -- get user_idif user_id thenif vRP.tryGetInventoryItem(user_id,"water_bottle",1) then-- try to remove one bottle vRP.varyThirst(user_id,-35) -- decrease thirst vRPclient.notify(player,"~b~ Drinking.") -- notify vRP.closeMenu(player) -- the water bottle is consumed by the action, close the menuendendend,"Do it."}-- add item definitionvRP.defInventoryItem("water_bottle","Water bottle","Drink this my friend.",function() return wb_choices end,0.5)-- (at any time later) give 2 water bottles to a connected uservRP.giveInventoryItem(user_id,"water_bottle",2)

Item transformer

The item transformer is a very generic way to create harvest and processing areas.

  • you can use the action of the item transformer when entering the area

  • the item transformer has a number of work units, regenerated at a specific rate

  • the item transformer takes reagents (money, items or none) to produce products (money or items) and it consumes a work unit

This way, processing and harvesting are limited by the work units.

-- add an item transformer-- name: transformer id name-- itemtr: item transformer definition table--- name--- permissions (optional)--- max_units--- units_per_minute--- x,y,z,radius,height (area properties)--- r,g,b (color)--- recipes, map of action =>---- description---- in_money---- out_money---- reagents: items as idname => amount---- products: items as idname => amount---- aptitudes: list as "group.aptitude" => exp amount generated--- onstart(player,recipe): optional callback--- onstep(player,recipe): optional callback--- onstop(player,recipe): optional callbackvRP.setItemTransformer(name,itemtr)-- remove an item transformervRP.removeItemTransformer(name)
Example 2. Example from another resource using proxy
local itemtr = { name="Water bottles tree", -- menu name r=0,g=125,b=255, -- color max_units=10, units_per_minute=5, x=1858,y=3687.5,z=34.26, -- pos radius=5, height=1.5, -- area recipes = { ["Harvest"] = { -- action name description="Harvest some water bottles.", -- action description in_money=0, -- money taken per unit out_money=0, -- money earned per unit reagents={}, -- items taken per unit products={ -- items given per unit ["water_bottle"] =1 } } }
}
vRP.setItemTransformer("my_unique_transformer",itemtr)

Items

Items are simple identifiers associated with a quantity in an inventory. But they can also be parametrics.

Parametrics items are identified like other items in the inventory but also have arguments as: weapon|pistol instead of just an ID. Parametric items don’t contain any data, they are generic item definitions that will be specialized by the arguments.

-- PROXY API-- define an inventory item (call this at server start) (parametric or plain text data)-- idname: unique item name-- name: display name or genfunction-- description: item description (html) or genfunction-- choices: menudata choices (see gui api) only as genfunction or nil-- weight: weight or genfunction---- genfunction are functions returning a correct value as: function(args) return value end-- where args is a list of {base_idname,arg,arg,arg,...}vRP.defInventoryItem(idname,name,description,choices,weight)-- return name, description, weightvRP.getItemDefinition(idname)
vRP.getItemName(idname)
vRP.getItemDescription(idname)
vRP.getItemChoices(idname)
vRP.getItemWeight(idname)-- add item to a connected user inventoryvRP.giveInventoryItem(user_id,idname,amount,notify)-- try to get item from a connected user inventory-- return true if the item has been found and the quantity removedvRP.tryGetInventoryItem(user_id,idname,amount,notify)-- get item amount from a connected user inventoryvRP.getInventoryItemAmount(user_id,idname)-- get connected user inventory-- return map of full idname => amount or nilvRP.getInventory(user_id)-- clear connected user inventoryvRP.clearInventory(user_id)-- compute weight of a list of items (in inventory/chest format)vRP.computeItemsWeight(items)-- return user inventory total weightvRP.getInventoryWeight(user_id)-- return user inventory max weightvRP.getInventoryMaxWeight(user_id)-- open a chest by name-- cb_close(): called when the chest is closedvRP.openChest(source, name, max_weight, cb_close)-- TUNNEL SERVER API-- TUNNEL CLIENT API

Once defined, items can be used by any resources (ex: they can be added to shops).

local Proxy =module("vrp", "lib/Proxy")local Tunnel =require("vrp", "lib/Tunnel")
vRP = Proxy.getInterface("vRP")
vRPclient = Tunnel.getInterface("vRP","vrp_waterbottle")-- create Water bottle itemlocal wb_choices = {} -- (see gui API for menudata choices structure)wb_choices["Drink"] = {function(player,choice) -- add drink actionlocal user_id = vRP.getUserId(player) -- get user_idif user_id thenif vRP.tryGetInventoryItem(user_id,"water_bottle",1) then-- try to remove one bottle vRP.varyThirst(user_id,-35) -- decrease thirst vRPclient.notify(player,"~b~ Drinking.") -- notify vRP.closeMenu(player) -- the water bottle is consumed by the action, close the menuendendend,"Do it."}-- add item definitionvRP.defInventoryItem("water_bottle","Water bottle","Drink this my friend.",function() return wb_choices end,0.5)-- (at any time later) give 2 water bottles to a connected uservRP.giveInventoryItem(user_id,"water_bottle",2)

Player state

-- PROXY API-- TUNNEL SERVER API-- TUNNEL CLIENT API-- get player weapons data-- return table with weapons data, use print(json.encode(result)) to understand the structurevRP.getWeapons()-- give weapons-- weapons: same structure as returned by getWeapons()-- (optional) clear_before: if true, will remove all the weapons before adding the new onesvRP.giveWeapons(weapons,clear_before)-- get player apparence customization data-- return table with customization data, use print(json.encode(result)) to understand the structure-- .model or .modelhash define the player model, the indexes define each component as [drawable_id,texture_id,palette_id] array-- props are referenced using the prefix "p" for the key (p0,p1,p2,p...), -1 = no propvRP.getCustomization()-- set player apparence-- customization_data: same structure as returned by getCustomization()vRP.setCustomization(customization_data)-- set player armour (0-100)vRP.setArmour(amount)

Proxy

The proxy lib is used to call other resources functions through a proxy event.

The notation is Interface.function(…​).

Survival

Running, walking, being hurt/injured, and just living add hunger and thirst. When the hunger and the thirst are at their maximum level (100%), next hunger/thirst overflow will damage the character by the same amount (ex: when thirsty, don’t run, take a car).

The survival module implement also a coma system. If the health of the player is below the coma threshold, the player is in coma for a specific duration before dying. The health (thus coma) is recorded in the player state.
If a player disconnect and reconnect while in coma, he will fall in coma again and die in a few seconds.

Tunnel

The idea behind tunnels is to easily access any declared server function from any client resource, and to access any declared client function from any server resource.

Example 4. Example of two-way resource communication
-- build the client-side interfaceclientdef = {} -- you can add function to clientdef later in other client scriptsTunnel.bindInterface("myrsc",clientdef)functionclientdef.teleport(x,y,z) SetEntityCoords(GetPlayerPed(-1), x, y, z, 1,0,0,0)end-- sometimes, you would want to return the tunnel call with asynchronous data-- ex:functionclientdef.setModel(hash) local r =async() Citizen.CreateThread(function() -- do the asynchronous model loading Citizen.Wait(1000) r(true) -- return trueend) return r:wait() -- wait for the async returned valueend-- get the server-side accessserveraccess = Tunnel.getInterface("myrsc")-- call test on server and print the returned value (in an async context)local r = serveraccess.test("my client message")print(r) -- true

Now if we want to use the same teleport function in another resource:

This way resources can easily use other resources client/server API.

The notation is Interface.function(dest, …​).

Оцените статью
Huawei Devices