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 source
vRP.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 scalar
vRP.registerDBDriver(name, on_init, on_prepare, on_query)

-- prepare a query--- name: unique name for the query--- query: SQL string with @params notation
vRP.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 scalar
vRP.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 title
vRP.getGroupTitle(group)

-- add a group to a connected user
vRP.addUserGroup(user_id,group)

-- remove a group from a connected user
vRP.removeUserGroup(user_id,group)

-- check if the user has a specific group
vRP.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/nil
vRP.registerPermissionFunction(name, callback)

-- check if the user has a specific permission
vRP.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 string
vRP.getUserGroupByType(user_id,gtype)

-- return list of connected users by group
vRP.getUsersByGroup(group)

-- return list of connected users by permission
vRP.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, weight
vRP.getItemDefinition(idname)

vRP.getItemName(idname)

vRP.getItemDescription(idname)

vRP.getItemChoices(idname)

vRP.getItemWeight(idname)

-- add item to a connected user inventory
vRP.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 removed
vRP.tryGetInventoryItem(user_id,idname,amount,notify)

-- get item amount from a connected user inventory
vRP.getInventoryItemAmount(user_id,idname)

-- get connected user inventory-- return map of full idname => amount or nil
vRP.getInventory(user_id)

-- clear connected user inventory
vRP.clearInventory(user_id)

-- compute weight of a list of items (in inventory/chest format)
vRP.computeItemsWeight(items)

-- return user inventory total weight
vRP.getInventoryWeight(user_id)

-- return user inventory max weight
vRP.getInventoryMaxWeight(user_id)

-- open a chest by name-- cb_close(): called when the chest is closed
vRP.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 definition
vRP.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 user
vRP.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 callback
vRP.setItemTransformer(name,itemtr)

-- remove an item transformer
vRP.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, weight
vRP.getItemDefinition(idname)

vRP.getItemName(idname)

vRP.getItemDescription(idname)

vRP.getItemChoices(idname)

vRP.getItemWeight(idname)

-- add item to a connected user inventory
vRP.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 removed
vRP.tryGetInventoryItem(user_id,idname,amount,notify)

-- get item amount from a connected user inventory
vRP.getInventoryItemAmount(user_id,idname)

-- get connected user inventory-- return map of full idname => amount or nil
vRP.getInventory(user_id)

-- clear connected user inventory
vRP.clearInventory(user_id)

-- compute weight of a list of items (in inventory/chest format)
vRP.computeItemsWeight(items)

-- return user inventory total weight
vRP.getInventoryWeight(user_id)

-- return user inventory max weight
vRP.getInventoryMaxWeight(user_id)

-- open a chest by name-- cb_close(): called when the chest is closed
vRP.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 definition
vRP.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 user
vRP.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 structure
vRP.getWeapons()

-- give weapons-- weapons: same structure as returned by getWeapons()-- (optional) clear_before: if true, will remove all the weapons before adding the new ones
vRP.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 prop
vRP.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 interface
clientdef = {} -- you can add function to clientdef later in other client scripts
Tunnel.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 access
serveraccess = 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
Добавить комментарий