[PAID]dev5_drivingschool

:vertical_traffic_light: DEV5 Driving School – Realistic License System for RP Servers

Bring realism to your FiveM roleplay server with DEV5 Driving School, a fully automated and immersive system for acquiring driving licenses – including theory and practical exams.

:receipt: Features

:mortar_board: Complete Driving License Workflow

  • Theory Tests with randomized questions per license
  • Practical Exams with live route monitoring, speed checks, and parking assessment

:oncoming_automobile: Supported License Types

  • Car License (B)
  • Motorbike License (A)
  • Truck License (C)

:bulb: Learning & Exam Tools

  • In-game PDF viewer to study traffic rules
  • Unique 10-question quiz per license category
  • Realistic driving routes with:
    • Speed enforcement
    • Collision detection
    • Final parking test

:identification_card: Licensing System

  • Auto-generated license cards
  • Optional fail cooldown system
  • Fully automated – no admin input required

:jigsaw: Compatibility

:white_check_mark: Frameworks

  • QBCore
  • QBOX
  • Standalone (logic-only support)

:white_check_mark: Dependencies

  • ox_lib
  • ox_target
  • MugShotBase64

:hammer_and_wrench: Planned Content

:school: Custom Driving School MLO (coming soon)

An exclusive, high-quality MLO interior for theory, practice, and license handling – fully integrated with the DEV5 system.

Config = {}

Config.Debugs    = true
Config.Framework = "auto-detect"
Config.Locale    = "en"      -- auf "de" umstellen für Deutsch
Config.TotalEPoints = 40
-- Config.TheoreticalPrice = 500
Config.PracticalPrice = 500
Config.ItemName = 'driver_license'

Config.Exam = {
  timeLimitMs    = 10*60000,   -- 10 Min
  maxErrorPoints = {
    car   = 3,
    motor = 3,
    truck = 3,
  },
  errorPauseMs = 3000, -- 1000 = 1 sec
  speedUnit    = "mph",
}


Config.TheoryFailLockHours = 0
Config.PracticalFailLockHours = 0

Config.StartPosition = vector3(86.9, -219, 54)
Config.PedHeading    = 347.97
Config.BlipName = "Driving School"

Config.PedModel      = "csb_imran"

Config.Locations = {
  car = {
    model         = "sentinel",
    spawn         = vector3(90.23, -215.74, 54.08),
    heading       = 339.61,
    parkingMarker = vector3(77.51, -201.72, 53.5),
    size          = vector3(5.2, 2.8, 2.0),
    parkHead      = 248.96,
  },
  motor = {
    model         = "faggio",
    spawn         = vector3(90.23, -215.74, 54.08),
    heading       = 339.61,
    parkingMarker = vector3(77.36, -201.69, 53.5),
    size          = vector3(2.5, 1.5, 2.0),
    parkHead      = 248.96,
  },
  truck = {
    model          = "packer",
    trailer        = "trailers",
    spawn          = vector3(95.67, -204.8, 54.58),
    heading        = 340.38,
    trailerSpawn   = vector3(93.18, -211.97, 54.49),
    trailerHeading = 340.38,
    parkingMarker  = vector3(96.93, -201.29, 53.5),
    size           = vector3(20.0, 5.0, 2.0),
    parkHead       = 340.45,
  },
}

Config.Route = {
  car = {
{ pos = vec3(98.47, -197.55, 52.67), maxSpeed = 50.0 },
{ pos = vec3(209.11, -212.99, 52.08), maxSpeed = 50.0 },
{ pos = vec3(273.32, -117.95, 67.3), maxSpeed = 50.0 },
{ pos = vec3(375.56, -128.72, 62.99), maxSpeed = 50.0 },
{ pos = vec3(363.78, -246.94, 51.98), maxSpeed = 50.0 },
{ pos = vec3(445.83, -310.71, 46.66), maxSpeed = 50.0 },
{ pos = vec3(579.79, -361.47, 41.6), maxSpeed = 50.0 },
{ pos = vec3(755.16, -70.22, 55.28), maxSpeed = 50.0 },
{ pos = vec3(1016.62, 276.1, 80.41), maxSpeed = 50.0 },
{ pos = vec3(1125.35, 371.28, 89.48), maxSpeed = 50.0 },
{ pos = vec3(1039.74, 479.41, 93.08), maxSpeed = 50.0 },
{ pos = vec3(1147.33, 571.71, 96.14), maxSpeed = 50.0 },
{ pos = vec3(1308.67, 1036.01, 103.83), maxSpeed = 50.0 },
{ pos = vec3(1295.75, 1499.99, 96.17), maxSpeed = 50.0 },
{ pos = vec3(1137.74, 1861.1, 67.16), maxSpeed = 50.0 },
{ pos = vec3(1011.76, 2121.74, 47.23), maxSpeed = 50.0 },
{ pos = vec3(830.94, 2229.71, 46.83), maxSpeed = 50.0 },
{ pos = vec3(451.55, 2148.49, 85.32), maxSpeed = 50.0 },
{ pos = vec3(11.28, 2047.14, 162.32), maxSpeed = 50.0 },
{ pos = vec3(-151.61, 1868.59, 196.21), maxSpeed = 50.0 },
{ pos = vec3(65.89, 1701.09, 223.99), maxSpeed = 50.0 },
{ pos = vec3(141.87, 1627.9, 227.08), maxSpeed = 50.0 },
{ pos = vec3(242.25, 1308.93, 234.52), maxSpeed = 50.0 },
{ pos = vec3(307.96, 1018.47, 208.42), maxSpeed = 50.0 },
{ pos = vec3(114.06, 989.84, 211.02), maxSpeed = 50.0 },
{ pos = vec3(-187.99, 1048.44, 231.04), maxSpeed = 50.0 },
{ pos = vec3(-355.37, 964.67, 231.39), maxSpeed = 50.0 },
{ pos = vec3(-592.84, 985.96, 239.35), maxSpeed = 50.0 },
{ pos = vec3(-687.97, 927.31, 231.44), maxSpeed = 50.0 },
{ pos = vec3(-561.05, 496.14, 101.92), maxSpeed = 50.0 },
{ pos = vec3(-536.97, 414.43, 91.77), maxSpeed = 50.0 },
{ pos = vec3(-517.41, 248.78, 81.07), maxSpeed = 50.0 },
{ pos = vec3(10.77, 252.05, 107.49), maxSpeed = 50.0 },
{ pos = vec3(-45.61, 54.03, 70.25), maxSpeed = 50.0 },
{ pos = vec3(-97.86, -145.63, 53.86), maxSpeed = 50.0 },
{ pos = vec3(-99.0, -205.05, 43.57), maxSpeed = 50.0 },
{ pos = vec3(40.67, -255.79, 45.81), maxSpeed = 50.0 },
{ pos = vec3(98.29, -198.54, 52.62), maxSpeed = 50.0 }

},

  motor = {
    { pos = vec3(98.47, -197.55, 52.67), maxSpeed = 50.0 },
{ pos = vec3(209.11, -212.99, 52.08), maxSpeed = 50.0 },
{ pos = vec3(273.32, -117.95, 67.3), maxSpeed = 50.0 },
{ pos = vec3(375.56, -128.72, 62.99), maxSpeed = 50.0 },
{ pos = vec3(363.78, -246.94, 51.98), maxSpeed = 50.0 },
{ pos = vec3(445.83, -310.71, 46.66), maxSpeed = 50.0 },
{ pos = vec3(579.79, -361.47, 41.6), maxSpeed = 50.0 },
{ pos = vec3(755.16, -70.22, 55.28), maxSpeed = 50.0 },
{ pos = vec3(1016.62, 276.1, 80.41), maxSpeed = 50.0 },
{ pos = vec3(1125.35, 371.28, 89.48), maxSpeed = 50.0 },
{ pos = vec3(1039.74, 479.41, 93.08), maxSpeed = 50.0 },
{ pos = vec3(1147.33, 571.71, 96.14), maxSpeed = 50.0 },
{ pos = vec3(1308.67, 1036.01, 103.83), maxSpeed = 50.0 },
{ pos = vec3(1295.75, 1499.99, 96.17), maxSpeed = 50.0 },
{ pos = vec3(1137.74, 1861.1, 67.16), maxSpeed = 50.0 },
{ pos = vec3(1011.76, 2121.74, 47.23), maxSpeed = 50.0 },
{ pos = vec3(830.94, 2229.71, 46.83), maxSpeed = 50.0 },
{ pos = vec3(451.55, 2148.49, 85.32), maxSpeed = 50.0 },
{ pos = vec3(11.28, 2047.14, 162.32), maxSpeed = 50.0 },
{ pos = vec3(-151.61, 1868.59, 196.21), maxSpeed = 50.0 },
{ pos = vec3(65.89, 1701.09, 223.99), maxSpeed = 50.0 },
{ pos = vec3(141.87, 1627.9, 227.08), maxSpeed = 50.0 },
{ pos = vec3(242.25, 1308.93, 234.52), maxSpeed = 50.0 },
{ pos = vec3(307.96, 1018.47, 208.42), maxSpeed = 50.0 },
{ pos = vec3(114.06, 989.84, 211.02), maxSpeed = 50.0 },
{ pos = vec3(-187.99, 1048.44, 231.04), maxSpeed = 50.0 },
{ pos = vec3(-355.37, 964.67, 231.39), maxSpeed = 50.0 },
{ pos = vec3(-592.84, 985.96, 239.35), maxSpeed = 50.0 },
{ pos = vec3(-687.97, 927.31, 231.44), maxSpeed = 50.0 },
{ pos = vec3(-561.05, 496.14, 101.92), maxSpeed = 50.0 },
{ pos = vec3(-536.97, 414.43, 91.77), maxSpeed = 50.0 },
{ pos = vec3(-517.41, 248.78, 81.07), maxSpeed = 50.0 },
{ pos = vec3(10.77, 252.05, 107.49), maxSpeed = 50.0 },
{ pos = vec3(-45.61, 54.03, 70.25), maxSpeed = 50.0 },
{ pos = vec3(-97.86, -145.63, 53.86), maxSpeed = 50.0 },
{ pos = vec3(-99.0, -205.05, 43.57), maxSpeed = 50.0 },
{ pos = vec3(40.67, -255.79, 45.81), maxSpeed = 50.0 },
{ pos = vec3(98.29, -198.54, 52.62), maxSpeed = 50.0 }
  },
  truck = {
     { pos = vec3(98.47, -197.55, 52.67), maxSpeed = 50.0 },
{ pos = vec3(209.11, -212.99, 52.08), maxSpeed = 50.0 },
{ pos = vec3(273.32, -117.95, 67.3), maxSpeed = 50.0 },
{ pos = vec3(375.56, -128.72, 62.99), maxSpeed = 50.0 },
{ pos = vec3(363.78, -246.94, 51.98), maxSpeed = 50.0 },
{ pos = vec3(445.83, -310.71, 46.66), maxSpeed = 50.0 },
{ pos = vec3(579.79, -361.47, 41.6), maxSpeed = 50.0 },
{ pos = vec3(755.16, -70.22, 55.28), maxSpeed = 50.0 },
{ pos = vec3(1016.62, 276.1, 80.41), maxSpeed = 50.0 },
{ pos = vec3(1125.35, 371.28, 89.48), maxSpeed = 50.0 },
{ pos = vec3(1039.74, 479.41, 93.08), maxSpeed = 50.0 },
{ pos = vec3(1147.33, 571.71, 96.14), maxSpeed = 50.0 },
{ pos = vec3(1308.67, 1036.01, 103.83), maxSpeed = 50.0 },
{ pos = vec3(1295.75, 1499.99, 96.17), maxSpeed = 50.0 },
{ pos = vec3(1137.74, 1861.1, 67.16), maxSpeed = 50.0 },
{ pos = vec3(1011.76, 2121.74, 47.23), maxSpeed = 50.0 },
{ pos = vec3(830.94, 2229.71, 46.83), maxSpeed = 50.0 },
{ pos = vec3(451.55, 2148.49, 85.32), maxSpeed = 50.0 },
{ pos = vec3(11.28, 2047.14, 162.32), maxSpeed = 50.0 },
{ pos = vec3(-151.61, 1868.59, 196.21), maxSpeed = 50.0 },
{ pos = vec3(65.89, 1701.09, 223.99), maxSpeed = 50.0 },
{ pos = vec3(141.87, 1627.9, 227.08), maxSpeed = 50.0 },
{ pos = vec3(242.25, 1308.93, 234.52), maxSpeed = 50.0 },
{ pos = vec3(307.96, 1018.47, 208.42), maxSpeed = 50.0 },
{ pos = vec3(114.06, 989.84, 211.02), maxSpeed = 50.0 },
{ pos = vec3(-187.99, 1048.44, 231.04), maxSpeed = 50.0 },
{ pos = vec3(-355.37, 964.67, 231.39), maxSpeed = 50.0 },
{ pos = vec3(-592.84, 985.96, 239.35), maxSpeed = 50.0 },
{ pos = vec3(-687.97, 927.31, 231.44), maxSpeed = 50.0 },
{ pos = vec3(-561.05, 496.14, 101.92), maxSpeed = 50.0 },
{ pos = vec3(-536.97, 414.43, 91.77), maxSpeed = 50.0 },
{ pos = vec3(-517.41, 248.78, 81.07), maxSpeed = 50.0 },
{ pos = vec3(10.77, 252.05, 107.49), maxSpeed = 50.0 },
{ pos = vec3(-45.61, 54.03, 70.25), maxSpeed = 50.0 },
{ pos = vec3(-97.86, -145.63, 53.86), maxSpeed = 50.0 },
{ pos = vec3(-99.0, -205.05, 43.57), maxSpeed = 50.0 },
{ pos = vec3(40.67, -255.79, 45.81), maxSpeed = 50.0 },
{ pos = vec3(98.29, -198.54, 52.62), maxSpeed = 50.0 }
  },
}

Config.Languages = {
  de = {
    title = "development 5",
    sub_title = "Fahrschule",
    mode_learning  = "Lernen",
    mode_theory    = "Theorie",
    mode_practice  = "Praxis",
    car            = "Auto",
    motor          = "Motorrad",
    truck          = "LKW",
    theory_title   = "Prüfung",
    practice_title = "Prüfung",
    question_prefix= "Frage ",
    next_question  = "Nächste Frage",
    result_quote   = "Sie haben den Test erfolgreich abgeschlossen! Ihre Ergebnisse findest du unten.",
    result_success = "Bestanden",
    result_failed  = "Durchgefallen",
    confirm_close  = "Schließen bestätigen?",
    confirm_content= "Bist du sicher, dass du alles schließen willst?",
    mode_examination = "Prüfung",
    examresult = 'Prüfungsergebnis',
    speed       = "Geschwindigkeit",
    speed_limit = "Limit",
    errors      = "Fehler",
    time        = "Zeit",
    reenter_description = "Du hast 10 Sekunden, um wieder einzusteigen!",
    exam_resumed = "Prüfung fortgesetzt!",
    exam_failed_timeout = "Prüfung abgebrochen: Nicht rechtzeitig zurückgekehrt."
  },
  en = {
    title = "development 5",
    sub_title = "DRIVINGSCHOOL",
    mode_learning  = "Learning",
    mode_theory    = "Theory",
    mode_practice  = "Practical",
    car            = "Car",
    motor          = "Motorcycle",
    truck          = "Truck",
    theory_title   = "Theoretical Exam",
    practice_title = "Practical Exam",
    question_prefix= "Question ",
    next_question  = "Next Question",
    result_quote   = "You have successfully completed the test! Your results are below.",
    result_success = "Passed",
    result_failed  = "Failed",
    confirm_close  = "Confirm Close?",
    confirm_content= "Are you sure you want to close everything?",
    mode_examination = "Examination",
    examresult = 'Your Result',
    speed       = "Speed",
    speed_limit = "Limit",
    errors      = "Errors",
    time        = "Time",
    reenter_description = "You have 10 seconds to get back in!",
    exam_resumed = "Exam resumed!",
    exam_failed_timeout = "Exam failed: Did not return in time."
  },
}

image5






YOU CAN BUY IT HERE: TEBEX
SUPPORT : DISCORD

Code is accessible No
Subscription-based No
Lines (approximately) 3000
Requirements ox_lib + ox_target
Support Yes
1 Like

We’re excited to announce a new update for DEV5 Driving School, bringing more flexibility and compatibility to your RP server!


:new: New Feature: Configurable License Item

Until now, the license item was hardcoded – but not anymore!
You can now define the item name used for licenses directly in the config.lua.

:bulb: What does this mean?

This update allows you to:

  • Adjust the license item to match your inventory system
  • Ensure better compatibility with custom inventories (e.g. ox_inventory, qb-inventory)
  • Maintain a cleaner and more modular setup

:hammer_and_wrench: Example:

Config.ItemName = 'driver_license'

When a player passes their driving test, the system will automatically give them the item you’ve defined here.

1 Like

I bought the driving school and am very happy that everything works.
I can really recommend the driving school.

1 Like

I hope you like it and that it works as intended. There will be a few more updates in the future. We are always open to suggestions on Discord or here in the comments.

  • :jigsaw: New: Customizable target support in target.lua
    → You can now configure the target system to your needs – no longer limited to ox_target.

  • :bug: Fix: Quiz position corrected
    → The quiz UI now appears in the correct screen location.

  • :closed_lock_with_key: Change: License check implemented
    → Request is only possible if the player owns at least one of the following licenses:
    - carlicense :red_car:
    - motorlicense :motorcycle:
    - trucklicense :truck:

  • :earth_africa: Add: General translations added in config.lua
    → Multilingual support structure prepared for easier localization.

:red_car:Driving School – Metadata Rework (v2.0)

Released: October 19, 2025
A complete rework of the driving school system — now fully metadata-based, faster, and smarter!


:wrench:Major Changes

:small_blue_diamond: Replaced all database logic with a pure metadata system
:small_blue_diamond: Each class (:blue_car: Car / :motorcycle: Motor / :truck: Truck) now works independently
:small_blue_diamond: Optimized performance and instant UI updates

Lock Behavior Overview

:new: New Player: Theory :white_check_mark: Open | Practical :lock: Locked
:blue_book: Theory Passed: Theory :lock: Locked | Practical :white_check_mark: Open
:identification_card: Practical Passed: Both :lock: Locked
:x: Theory Failed: Theory :white_check_mark: Open | Practical :lock: Locked
:warning: Practical Failed: Theory :lock: Locked | Practical :white_check_mark: Open


:brain:Technical Updates

:gear: Fully removed SQL dependencies and old column checks
:zap: Added new server events:
test:giveTheoryCertificate → sets metadata on theory pass
nosk:server:completePracticalExam → locks both after practical pass
markFailedToday → only affects selected class
checkDrivingTheory → returns lock data from metadata
:speech_balloon: Client now sends class info (car, motor, truck) on fails


:compass:Initialization

:small_orange_diamond: Metadata automatically created on player join
:small_orange_diamond: Default state → Theory :white_check_mark: Open | Practical :lock: Locked
:small_orange_diamond: UI instantly refreshes after every exam


:bulb:Notes

:card_file_box: Old database columns are no longer used — can be safely deleted
:repeat: Restart the resource once to initialize metadata for all players


:sparkles: Development 5 | Driving School System v2.0

“Simple logic. Smarter learning.”

next updates coming soon…