Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Custom Rectangular Nameplate for Assetto Corsa
- -- Shows driver name, country flag, ping, and SERVER-BASED input mode
- local driverData = {}
- local serverInputModes = {} -- Store server input mode data
- local steamAvatarUrls = {} -- Store Steam avatar URLs
- local lastBroadcastReceived = 0
- -- Online event to receive input mode broadcasts from server
- -- CRITICAL: Must specify the exact key that matches C# packet
- local inputModeBroadcastEvent = ac.OnlineEvent({
- ac.StructItem.key("input_modes_broadcast"), -- MUST match C# packet key exactly
- data = ac.StructItem.string(512)
- }, function(sender, message)
- if message and message.data and message.data ~= "" then
- ac.log("Nameplate: Received server input data: " .. message.data)
- lastBroadcastReceived = os.clock()
- -- Clear and parse new data
- serverInputModes = {}
- -- Parse format: "sessionId:inputMode;sessionId:inputMode;..."
- for sessionData in string.gmatch(message.data, "([^;]+)") do
- local sessionId, inputMode = string.match(sessionData, "(%d+):(%w+)")
- if sessionId and inputMode then
- local sessionIdNum = tonumber(sessionId)
- serverInputModes[sessionIdNum] = inputMode
- ac.log("Nameplate: Server data - Session " .. sessionId .. " = " .. inputMode)
- end
- end
- end
- end)
- -- Online event to receive Steam avatar URLs from server
- local steamAvatarBroadcastEvent = ac.OnlineEvent({
- ac.StructItem.key("steam_avatars_broadcast"), -- MUST match C# packet key exactly
- data = ac.StructItem.string(1024) -- Increased size for URLs
- }, function(sender, message)
- if message and message.data and message.data ~= "" then
- ac.log("Nameplate: Received Steam avatar URLs: " .. message.data)
- -- Clear and parse new data
- steamAvatarUrls = {}
- -- Parse format: "sessionId:avatarUrl;sessionId:avatarUrl;..."
- for sessionData in string.gmatch(message.data, "([^;]+)") do
- local sessionId, avatarUrl = string.match(sessionData, "(%d+):(.+)")
- if sessionId and avatarUrl then
- local sessionIdNum = tonumber(sessionId)
- steamAvatarUrls[sessionIdNum] = avatarUrl
- ac.log("Nameplate: Steam avatar - Session " .. sessionId .. " = " .. avatarUrl)
- end
- end
- end
- end)
- -- Get input type from server data (preferred) or fallback to local detection
- function getInputType(car)
- if not car then return "unknown" end
- -- Try to get session ID and use server data
- local sessionId = car.sessionID
- if sessionId and serverInputModes[sessionId] then
- local serverInputMode = serverInputModes[sessionId]
- ac.log("Nameplate: Using server data for session " .. sessionId .. ": " .. serverInputMode)
- return serverInputMode
- end
- -- Fallback to local detection if no server data available
- local index = car.index or car.carIndex or 0
- local steer = car.steer or 0
- local gas = car.gas or 0
- local brake = car.brake or 0
- local currentType = "gamepad"
- local steerAbs = math.abs(steer)
- if (steer == 0 or steerAbs > 0.95) and (gas == 0 or gas > 0.95) and (brake == 0 or brake > 0.95) then
- currentType = "keyboard"
- end
- if steerAbs > 0.05 and steerAbs < 0.9 then
- currentType = "wheel"
- end
- -- Store last 5 readings for each player
- driverData[index] = driverData[index] or {}
- driverData[index].inputTypeHistory = driverData[index].inputTypeHistory or {}
- table.insert(driverData[index].inputTypeHistory, currentType)
- if #driverData[index].inputTypeHistory > 5 then
- table.remove(driverData[index].inputTypeHistory, 1)
- end
- -- Count most frequent
- local count = { keyboard = 0, wheel = 0, gamepad = 0 }
- for _, t in ipairs(driverData[index].inputTypeHistory) do
- count[t] = (count[t] or 0) + 1
- end
- local detected = "gamepad"
- local maxCount = 0
- for k, v in pairs(count) do
- if v > maxCount then
- maxCount = v
- detected = k
- end
- end
- driverData[index].lastInputType = detected
- return detected
- end
- function drawInputIcon(inputType, x, y, alpha)
- if inputType == "wheel" then
- -- Use steering wheel image - bigger size (36x36) and white color
- local success = pcall(function()
- ui.drawImage(
- "https://i.imgur.com/OEENH81.png",
- vec2(x, y),
- vec2(x + 25, y + 25),
- rgbm(1.0, 1.0, 1.0, alpha)
- )
- end)
- if not success then
- ac.log("Nameplate: Failed to draw wheel icon from URL.")
- ui.dwriteDrawText("🏎", 26, vec2(x, y), rgbm(0.2, 1.0, 0.2, alpha), 1, ui.Alignment.Left, ui.Alignment.Top)
- end
- elseif inputType == "keyboard" then
- ui.dwriteDrawText("⌨", 26, vec2(x, y), rgbm(0.2, 0.8, 1.0, alpha), 1, ui.Alignment.Left, ui.Alignment.Top)
- elseif inputType == "gamepad" then
- -- Use controller image - bigger size (36x36) and white color
- local success = pcall(function()
- ui.drawImage(
- "https://i.ibb.co/3m56fyZy/gamepad.png",
- vec2(x, y),
- vec2(x + 36, y + 36),
- rgbm(1.0, 1.0, 1.0, alpha)
- )
- end)
- if not success then
- ac.log("Nameplate: Failed to draw gamepad icon from URL.")
- ui.dwriteDrawText("🎮", 26, vec2(x, y), rgbm(1.0, 0.8, 0.2, alpha), 1, ui.Alignment.Left, ui.Alignment.Top)
- end
- else
- -- Unknown - show question mark
- ui.dwriteDrawText("?", 26, vec2(x, y), rgbm(0.7, 0.7, 0.7, alpha), 1, ui.Alignment.Left, ui.Alignment.Top)
- end
- end
- function drawCountryFlag(nationCode, x, y)
- if nationCode and nationCode ~= "" then
- -- Try to draw flag image
- local success = pcall(function()
- ui.drawImage(
- "/content/gui/flags/" .. nationCode .. ".png",
- vec2(x, y),
- vec2(x + 24, y + 18),
- rgbm(1, 1, 1, 1)
- )
- end)
- -- If flag fails, show country code
- if not success then
- ui.dwriteDrawText(nationCode, 16, vec2(x, y + 2), rgbm(0.8, 0.8, 1.0, 1), 1, ui.Alignment.Left, ui.Alignment.Top)
- end
- end
- end
- function drawPingBars(x, y, ping, pingColor)
- local barWidth = 6
- local barHeight = 16
- local barSpacing = 3
- local maxBars = 4
- local bars = 4
- if ping > 200 then
- bars = 1
- elseif ping > 150 then
- bars = 2
- elseif ping > 100 then
- bars = 3
- end
- for i = 1, maxBars do
- local barX = x + (i - 1) * (barWidth + barSpacing)
- local currentBarHeight = barHeight * (i / maxBars)
- local currentY = y + barHeight - currentBarHeight
- local alpha = (i <= bars) and 1.0 or 0.3
- local color = rgbm(pingColor.r, pingColor.g, pingColor.b, alpha)
- ui.drawRectFilled(vec2(barX, currentY), vec2(barX + barWidth, y + barHeight), color)
- end
- end
- ui.onDriverNameTag(function(car)
- -- Clean the driver name properly
- local rawName = tostring(car.driverName or "unknown")
- local name = rawName:gsub("0x[%x]+", ""):gsub("[^%w%s*%-%.%@]", "")
- name = name:gsub("^%s*(.-)%s*$", "%1")
- -- Skip AI traffic cars - only show input modes for real players
- local isRealPlayer = car.isConnected and not car.isAIControlled
- if not isRealPlayer then
- -- For AI cars, just show name without input mode
- ui.pushDWriteFont("Berlin Sans FB")
- ui.drawRectFilled(vec2(-90, 0), vec2(470, 36), rgbm(0, 0, 0, 0.0), 8)
- ui.dwriteDrawText(name, 21, vec2(-80, 6), rgbm(0.8, 0.8, 0.8, 1), 1, ui.Alignment.Left, ui.Alignment.Top)
- ui.popDWriteFont()
- return
- end
- local ping = car.ping or car.pingMs or 0
- local pingColor = rgbm(0.2, 1.0, 0.2, 1.0)
- if ping > 250 then
- pingColor = rgbm(1.0, 0.2, 0.2, 1.0)
- elseif ping > 120 then
- pingColor = rgbm(1.0, 1.0, 0.2, 1.0)
- end
- -- Get nation code
- local nationCode = ""
- if car.driverNationCode and car.driverNationCode ~= "" then
- nationCode = string.upper(tostring(car.driverNationCode))
- elseif car.nationality and car.nationality ~= "" then
- nationCode = string.upper(tostring(car.nationality))
- else
- nationCode = "ITA"
- end
- local speed = (car.speedKmh or 0)
- local speedText = string.format("%d KM/H", speed)
- ui.pushDWriteFont("Berlin Sans FB")
- -- Main background - MADE TRANSPARENT to avoid overlap
- ui.drawRectFilled(vec2(-90, 0), vec2(470, 36), rgbm(0, 0, 0, 0.0), 8)
- -- Driver name (leftmost)
- ui.dwriteDrawText(name, 21, vec2(-80, 6), rgbm(1,1,1,1), 1, ui.Alignment.Left, ui.Alignment.Top)
- -- Layout: Name | Input | Flag | Ping Bars
- local inputX = 322 -- Input icon position (moved further right to avoid name overlap)
- local flagX = 320 -- Flag position (moved right to make room for input)
- local barsX = 320 -- Ping bars position (moved right)
- local barsY = 18
- -- Input icon (moved further right and better vertical centering) - only for real players
- local inputType = getInputType(car)
- drawInputIcon(inputType, inputX, 35, 1.0) -- Lower vertical position for better centering
- -- Country flag
- drawCountryFlag(nationCode, flagX, 9)
- -- Ping bars (rightmost)
- drawPingBars(barsX, barsY, ping, pingColor)
- -- رقم البنق يمين الشارة (نفس فكرة السكربت الثاني)
- ui.dwriteDrawText(tostring(ping).."ms", 26, vec2(barsX + 40, 8), pingColor, 1, ui.Alignment.Left, ui.Alignment.Top)
- -- Steam Avatar (right of ping)
- local avatarUrl = steamAvatarUrls[car.sessionID]
- if avatarUrl then
- local avatarX = barsX + -321 -- Adjust X position relative to ping bars
- local avatarY = 2 -- Adjust Y position to align with ping text
- local avatarSize = 60 -- Adjust size as needed (e.g., 24x24)
- local success = pcall(function()
- ui.drawImage(
- avatarUrl,
- vec2(avatarX, avatarY),
- vec2(avatarX + avatarSize, avatarY + avatarSize),
- rgbm(1, 1, 1, 1)
- )
- end)
- if not success then
- ac.log("Nameplate: Failed to draw avatar from URL: " .. avatarUrl)
- end
- end
- -- الشريط الأزرق للسرعة
- local minSpeed, maxSpeed = 0, 260
- local speedBoxX = -90
- local speedBoxWMax = 560
- local speedBoxH = 17
- local speedBoxY = 46
- local t = math.max(0, math.min(1, (speed-minSpeed)/(maxSpeed-minSpeed)))
- local minWidth = 15
- local speedBoxW = minWidth + (speedBoxWMax - minWidth) * t
- ui.drawRectFilled(vec2(speedBoxX, speedBoxY), vec2(speedBoxX + speedBoxW, speedBoxY + speedBoxH), rgbm(0.1, 0.45, 0.95, 0.89), 7)
- ui.dwriteDrawText(speedText, 18, vec2(speedBoxX + speedBoxWMax/2, speedBoxY - 1), rgbm(1,1,1,1), 1, ui.Alignment.Center, ui.Alignment.Top)
- ui.popDWriteFont()
- -- Debug info in console every few seconds - only for real players
- if math.fmod(os.clock(), 5) < 0.1 then
- local sessionId = car.sessionID or "unknown"
- ac.log("Nameplate Debug: Player " .. name .. " - Session: " .. sessionId .. " - Input: " .. inputType .. " - Server data available: " .. tostring(serverInputModes[sessionId] ~= nil))
- end
- end)
- -- Debug logging
- ac.log("Nameplate: Enhanced script loaded with server input mode integration!")
- -- Periodic debug info
- local lastDebugTime = 0
- function script.update(dt)
- local currentTime = os.clock()
- if currentTime - lastDebugTime > 10 then -- Every 10 seconds
- lastDebugTime = currentTime
- local serverDataCount = 0
- for _ in pairs(serverInputModes) do
- serverDataCount = serverDataCount + 1
- end
- ac.log("Nameplate: Server input modes tracked: " .. serverDataCount .. " | Last broadcast: " ..
- (lastBroadcastReceived > 0 and string.format("%.1fs ago", currentTime - lastDebugTime) or "never"))
- end
- end
Add Comment
Please, Sign In to add comment