Code here
Delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
// Configuration
const screen_pos_x = 0.165;
const screen_pos_y = 0.882;
const always_show = false; // Show the HUD when on foot?
const seatbelt_plays_sound = true; // Play a sound when toggling the seatbelt?
const seatbelt_eject_min_speed = 5; // In meters per second.
const force_to_eject = 400; // Deceleration in meters per second.
const seatbelt_keyboard = "K";
const seatbelt_controller = "LDOWN_INDEX";
const cruise_keyboard = "CAPITAL";
const cruise_controller = "RDOWN_INDEX";
const speed_limit = 100.0;
const low_fuel = 25.0;
const text_color_good = [96, 255, 96, 255];
const text_color_neutral = [255, 255, 255, 255];
const text_color_bad = [255, 96, 96, 255];
const classes = {
speed: [13], // Hide speed display for these classes
fuel: [13, 21], // Hide fuel display for these classes
cruise: [13, 14, 15, 16, 21, 22], // Hide cruise display for these classes
seatbelt: [8, 13] // Hide seatbelt display for these classes
};
const headings = ["N", "NW", "W", "SW", "S", "SE", "E", "NE", "N"];
const zones = {
AIRP: "Los Santos International Airport",
ALAMO: "Alamo Sea",
ALTA: "Alta",
ARMYB: "Fort Zancudo",
BANHAMC: "Banham Canyon Dr",
BANNING: "Banning",
BEACH: "Vespucci Beach",
BHAMCA: "Banham Canyon",
BRADP: "Braddock Pass",
BRADT: "Braddock Tunnel",
BURTON: "Burton",
CALAFB: "Calafia Bridge",
CANNY: "Raton Canyon",
CCREAK: "Cassidy Creek",
CHAMH: "Chamberlain Hills",
CHIL: "Vinewood Hills",
CHU: "Chumash",
CMSW: "Chiliad Mountain State Wilderness",
CYPRE: "Cypress Flats",
DAVIS: "Davis",
DELBE: "Del Perro Beach",
DELPE: "Del Perro",
DELSOL: "La Puerta",
DESRT: "Grand Senora Desert",
DOWNT: "Downtown",
DTVINE: "Downtown Vinewood",
EAST_V: "East Vinewood",
EBURO: "El Burro Heights",
ELGORL: "El Gordo Lighthouse",
ELYSIAN: "Elysian Island",
GALFISH: "Galilee",
GOLF: "GWC and Golfing Society",
GRAPES: "Grapeseed",
GREATC: "Great Chaparral",
HARMO: "Harmony",
HAWICK: "Hawick",
HORS: "Vinewood Racetrack",
HUMLAB: "Humane Labs and Research",
JAIL: "Bolingbroke Penitentiary",
KOREAT: "Little Seoul",
LACT: "Land Act Reservoir",
LAGO: "Lago Zancudo",
LDAM: "Land Act Dam",
LEGSQU: "Legion Square",
LMESA: "La Mesa",
LOSPUER: "La Puerta",
MIRR: "Mirror Park",
MORN: "Morningwood",
MOVIE: "Richards Majestic",
MTCHIL: "Mount Chiliad",
MTGORDO: "Mount Gordo",
MTJOSE: "Mount Josiah",
MURRI: "Murrieta Heights",
NCHU: "North Chumash",
NOOSE: "N.O.O.S.E",
OCEANA: "Pacific Ocean",
PALCOV: "Paleto Cove",
PALETO: "Paleto Bay",
PALFOR: "Paleto Forest",
PALHIGH: "Palomino Highlands",
PALMPOW: "Palmer-Taylor Power Station",
PBLUFF: "Pacific Bluffs",
PBOX: "Pillbox Hill",
PROCOB: "Procopio Beach",
RANCHO: "Rancho",
RGLEN: "Richman Glen",
RICHM: "Richman",
ROCKF: "Rockford Hills",
RTRAK: "Redwood Lights Track",
SANAND: "San Andreas",
SANCHIA: "San Chianski Mountain Range",
SANDY: "Sandy Shores",
SKID: "Mission Row",
SLAB: "Stab City",
STAD: "Maze Bank Arena",
STRAW: "Strawberry",
TATAMO: "Tataviam Mountains",
TERMINA: "Terminal",
TEXTI: "Textile City",
TONGVAH: "Tongva Hills",
TONGVAV: "Tongva Valley",
VCANA: "Vespucci Canals",
VESP: "Vespucci",
VINE: "Vinewood",
WINDF: "Ron Alternates Wind Farm",
WVINE: "West Vinewood",
ZANCUDO: "Zancudo River",
ZP_ORT: "Port of South Los Santos",
ZQ_UAR: "Davis Quartz",
PROL: "Prologue / North Yankton",
ISHeist: "Cayo Perico Island"
};
// Variables
var player_ped = 0;
var player_pos_x = 0;
var player_pos_y = 0;
var player_pos_z = 0;
var player_prev_velocity_x = 0;
var player_prev_velocity_y = 0;
var player_prev_velocity_z = 0;
var player_pos_h = 0;
var player_vehicle = 0;
var player_vehicle_class = -1;
var player_vehicle_speed = 0;
var player_vehicle_fuel = "000";
var player_vehicle_speed_old = 0;
var use_metric = false;
var speed_multiplier = 0;
var fuel_multiplier = 0;
var speed_color = text_color_neutral;
var fuel_color = text_color_neutral;
var cruise_color = text_color_neutral;
var seatbelt_color = text_color_bad;
var vehicle_has_speed = false;
var vehicle_has_fuel = false;
var vehicle_has_cruise = false;
var vehicle_has_seatbelt = false;
var cruise_status = false;
var seatbelt_status = false;
var speed_fuel_string = "";
var time_string = "";
var location_string = "";
var seatbelt_handler;
var can_be_ejected = false;
// Low priority updates | 1s
setTick(async () => {
// Basic info
player_ped = PlayerPedId();
player_vehicle = GetVehiclePedIsIn(player_ped, false);
// Update only if the HUD is visible
if (always_show || player_vehicle !== 0) {
[player_pos_x, player_pos_y, player_pos_z] = GetEntityCoords(player_ped, false);
player_pos_h = GetEntityHeading(player_ped);
use_metric = ShouldUseMetricMeasurements();
// Only update if in vehicle
if (player_vehicle !== 0) {
player_vehicle_class = GetVehicleClass(player_vehicle);
can_be_ejected = GetEntitySpeedVector(player_vehicle, true)[1] > seatbelt_eject_min_speed;
// Update cruise control and seatbelt availability
vehicle_has_fuel = !classes.fuel.includes(player_vehicle_class);
vehicle_has_speed = !classes.speed.includes(player_vehicle_class);
vehicle_has_cruise = !classes.cruise.includes(player_vehicle_class);
vehicle_has_seatbelt = !classes.seatbelt.includes(player_vehicle_class);
// Has speedo and/or fuel
if (vehicle_has_speed && vehicle_has_fuel) {
speed_fuel_string = ((use_metric) ? "KPH " : "MPH ") + ((use_metric) ? "L" : "GAL");
speed_multiplier = (use_metric) ? 3.6 : 2.23694;
fuel_multiplier = (use_metric) ? 1 : 0.264172;
player_vehicle_fuel = String(Math.floor(GetVehicleFuelLevel(player_vehicle) * fuel_multiplier)).padStart(3, "0");
} else if (vehicle_has_speed && !vehicle_has_fuel) {
speed_fuel_string = (use_metric) ? "KPH" : "MPH";
speed_multiplier = (use_metric) ? 3.6 : 2.23694;
} else if (!vehicle_has_speed && vehicle_has_fuel) {
speed_fuel_string = (use_metric) ? " L" : " GAL";
fuel_multiplier = (use_metric) ? 1 : 0.264172;
player_vehicle_fuel = String(Math.floor(GetVehicleFuelLevel(player_vehicle) * fuel_multiplier)).padStart(3, "0");
}
}
// Update strings to display
location_string = headings[Math.floor((player_pos_h + 22.5) / 45)] + " | " + GetStreetNameFromHashKey(GetStreetNameAtCoord(player_pos_x, player_pos_y, player_pos_z)[0]) + " | " + zones[GetNameOfZone(player_pos_x, player_pos_y, player_pos_z)];
var hour = GetClockHours();
if (use_metric === true) {
time_string = String(hour).padStart(2, "0") + ":" + String(GetClockMinutes()).padStart(2, "0");
} else {
time_string = String(hour % 12).padStart(2, "0") + ":" + String(GetClockMinutes()).padStart(2, "0") + ((hour < 13) ? " AM" : " PM");
}
}
await Delay(1000);
});
// High priority updates | Every tick
setTick(async () => {
// If in a vehicle
if (player_vehicle !== 0) {
// Update speed
player_vehicle_speed_old = player_vehicle_speed;
player_vehicle_speed = GetEntitySpeed(player_vehicle);
// Seatbelt logic
if (vehicle_has_seatbelt) {
if (!seatbelt_status) {
if ((player_vehicle_speed_old - player_vehicle_speed) / GetFrameTime() >= force_to_eject && can_be_ejected) {
// Force update coords right now
[player_pos_x, player_pos_y, player_pos_z] = GetEntityCoords(player_ped, false);
// Set player coords outside of vehicle
SetEntityCoords(player_ped, player_pos_x, player_pos_y, player_pos_z + 0.4, true, true, true, false);
SetEntityVelocity(player_ped, player_prev_velocity_x, player_prev_velocity_y, player_prev_velocity_z);
await Delay(0);
SetPedToRagdoll(player_ped, 2000, 2000, 0, false, false, false);
// Clear variables
player_vehicle = 0;
player_vehicle_class = -1;
can_be_ejected = false;
}
[player_prev_velocity_x, player_prev_velocity_y, player_prev_velocity_z] = GetEntityVelocity(player_ped);
}
}
}
});
// Displaying generated strings | Every tick
setTick(async () => {
// Draw location and time
if (player_vehicle !== 0 || always_show) {
drawTxt(time_string, 4, text_color_neutral, 0.4, screen_pos_x, screen_pos_y + 0.048);
drawTxt(location_string, 4, text_color_neutral, 0.5, screen_pos_x, screen_pos_y + 0.075);
}
// Draw remainder of HUD if in vehicle
if (player_vehicle !== 0) {
if (vehicle_has_speed) {
drawTxt(String(Math.ceil(player_vehicle_speed * speed_multiplier)).padStart(3, "0"), 4, speed_color, 0.8, screen_pos_x, screen_pos_y);
}
if (vehicle_has_fuel) {
drawTxt(player_vehicle_fuel, 4, fuel_color, 0.8, screen_pos_x + 0.055, screen_pos_y);
}
if (vehicle_has_speed || vehicle_has_fuel) {
drawTxt(speed_fuel_string, 4, text_color_neutral, 0.4, screen_pos_x + 0.03, screen_pos_y + 0.018);
}
if (vehicle_has_cruise) {
drawTxt("CRUISE", 2, cruise_color, 0.4, screen_pos_x + 0.04, screen_pos_y + 0.048);
}
if (vehicle_has_seatbelt) {
drawTxt("SEATBELT", 2, seatbelt_color, 0.4, screen_pos_x + 0.08, screen_pos_y + 0.048);
}
}
});
// Drawing text on screen
const drawTxt = async function(content, font, [color_r, color_g, color_b], scale, pos_x, pos_y) {
BeginTextCommandDisplayText("STRING");
SetTextFont(font);
SetTextColour(color_r, color_g, color_b, 255);
SetTextScale(scale, scale);
SetTextOutline();
AddTextComponentSubstringPlayerName(content);
EndTextCommandDisplayText(pos_x, pos_y);
}
// Toggle cruise and seatbelt status
const toggleCruise = function() {
if (vehicle_has_cruise) {
cruise_status = !cruise_status;
if (cruise_status) {
// Cruise was turned on, set to current speed
SetVehicleMaxSpeed(player_vehicle, GetEntitySpeed(player_vehicle));
cruise_color = text_color_good;
} else {
// Cruise was turned off, reset
SetVehicleMaxSpeed(player_vehicle, -1.0);
cruise_color = text_color_neutral;
}
}
}
const toggleSeatbelt = function() {
if (vehicle_has_seatbelt) {
seatbelt_status = !seatbelt_status;
if (seatbelt_plays_sound) PlaySoundFrontend(-1, "Faster_Click", "RESPAWN_ONLINE_SOUNDSET", true);
if (seatbelt_status) {
seatbelt_color = text_color_good;
} else {
seatbelt_color = text_color_bad;
}
}
}
// Keybinds
RegisterCommand("cruise", toggleCruise);
RegisterCommand("seatbelt", toggleSeatbelt);
RegisterKeyMapping("cruise", "Toggle Cruise Control", "KEYBOARD", cruise_keyboard);
RegisterKeyMapping("~!cruise", "Toggle Cruise Control", "PAD_DIGITALBUTTON", cruise_controller);
RegisterKeyMapping("seatbelt", "Toggle Seatbelt", "KEYBOARD", seatbelt_keyboard);
RegisterKeyMapping("~!seatbelt", "Toggle Seatbelt", "PAD_DIGITALBUTTON", seatbelt_controller);
It’s running at 0.14 - 0.16ms compared to the LUA version which runs at 0.12ms according to the resource monitor.
What I’ve noticed is that when you are running a resource with an empty JavaScript file loaded on the client, the resource monitor already reports 0.02ms CPU time, whereas LUA is at 0.00ms. Same thing for the server side, but there it’s at 0.03ms.
Since I only focused on execution time and not resmon usage at first, I completely missed this.
Anyways, if this scales to larger resources too (0.02ms base usage, 15-30% higher overall usage), then I’d choose LUA over JavaScript. The only thing left now is to test C#, so if anyone here happens to know C# and has some free time on their hands…