SHARE
    TWEET
    supinus

    Untitled

    Nov 12th, 2025
    25
    0
    Never
    Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
    Lua 12.27 KB | Gaming | 0 0
    1. -- Custom Rectangular Nameplate for Assetto Corsa
    2. -- Shows driver name, country flag, ping, and SERVER-BASED input mode
    3. local driverData = {}
    4. local serverInputModes = {} -- Store server input mode data
    5. local steamAvatarUrls = {} -- Store Steam avatar URLs
    6. local lastBroadcastReceived = 0
    7. -- Online event to receive input mode broadcasts from server
    8. -- CRITICAL: Must specify the exact key that matches C# packet
    9. local inputModeBroadcastEvent = ac.OnlineEvent({
    10. ac.StructItem.key("input_modes_broadcast"), -- MUST match C# packet key exactly
    11. data = ac.StructItem.string(512)
    12. }, function(sender, message)
    13. if message and message.data and message.data ~= "" then
    14. ac.log("Nameplate: Received server input data: " .. message.data)
    15. lastBroadcastReceived = os.clock()
    16. -- Clear and parse new data
    17. serverInputModes = {}
    18. -- Parse format: "sessionId:inputMode;sessionId:inputMode;..."
    19. for sessionData in string.gmatch(message.data, "([^;]+)") do
    20. local sessionId, inputMode = string.match(sessionData, "(%d+):(%w+)")
    21. if sessionId and inputMode then
    22. local sessionIdNum = tonumber(sessionId)
    23. serverInputModes[sessionIdNum] = inputMode
    24. ac.log("Nameplate: Server data - Session " .. sessionId .. " = " .. inputMode)
    25. end
    26. end
    27. end
    28. end)
    29. -- Online event to receive Steam avatar URLs from server
    30. local steamAvatarBroadcastEvent = ac.OnlineEvent({
    31. ac.StructItem.key("steam_avatars_broadcast"), -- MUST match C# packet key exactly
    32. data = ac.StructItem.string(1024) -- Increased size for URLs
    33. }, function(sender, message)
    34. if message and message.data and message.data ~= "" then
    35. ac.log("Nameplate: Received Steam avatar URLs: " .. message.data)
    36. -- Clear and parse new data
    37. steamAvatarUrls = {}
    38. -- Parse format: "sessionId:avatarUrl;sessionId:avatarUrl;..."
    39. for sessionData in string.gmatch(message.data, "([^;]+)") do
    40. local sessionId, avatarUrl = string.match(sessionData, "(%d+):(.+)")
    41. if sessionId and avatarUrl then
    42. local sessionIdNum = tonumber(sessionId)
    43. steamAvatarUrls[sessionIdNum] = avatarUrl
    44. ac.log("Nameplate: Steam avatar - Session " .. sessionId .. " = " .. avatarUrl)
    45. end
    46. end
    47. end
    48. end)
    49. -- Get input type from server data (preferred) or fallback to local detection
    50. function getInputType(car)
    51. if not car then return "unknown" end
    52. -- Try to get session ID and use server data
    53. local sessionId = car.sessionID
    54. if sessionId and serverInputModes[sessionId] then
    55. local serverInputMode = serverInputModes[sessionId]
    56. ac.log("Nameplate: Using server data for session " .. sessionId .. ": " .. serverInputMode)
    57. return serverInputMode
    58. end
    59. -- Fallback to local detection if no server data available
    60. local index = car.index or car.carIndex or 0
    61. local steer = car.steer or 0
    62. local gas = car.gas or 0
    63. local brake = car.brake or 0
    64. local currentType = "gamepad"
    65. local steerAbs = math.abs(steer)
    66. if (steer == 0 or steerAbs > 0.95) and (gas == 0 or gas > 0.95) and (brake == 0 or brake > 0.95) then
    67. currentType = "keyboard"
    68. end
    69. if steerAbs > 0.05 and steerAbs < 0.9 then
    70. currentType = "wheel"
    71. end
    72. -- Store last 5 readings for each player
    73. driverData[index] = driverData[index] or {}
    74. driverData[index].inputTypeHistory = driverData[index].inputTypeHistory or {}
    75. table.insert(driverData[index].inputTypeHistory, currentType)
    76. if #driverData[index].inputTypeHistory > 5 then
    77. table.remove(driverData[index].inputTypeHistory, 1)
    78. end
    79. -- Count most frequent
    80. local count = { keyboard = 0, wheel = 0, gamepad = 0 }
    81. for _, t in ipairs(driverData[index].inputTypeHistory) do
    82. count[t] = (count[t] or 0) + 1
    83. end
    84. local detected = "gamepad"
    85. local maxCount = 0
    86. for k, v in pairs(count) do
    87. if v > maxCount then
    88. maxCount = v
    89. detected = k
    90. end
    91. end
    92. driverData[index].lastInputType = detected
    93. return detected
    94. end
    95. function drawInputIcon(inputType, x, y, alpha)
    96. if inputType == "wheel" then
    97. -- Use steering wheel image - bigger size (36x36) and white color
    98. local success = pcall(function()
    99. ui.drawImage(
    100. "https://i.imgur.com/OEENH81.png",
    101. vec2(x, y),
    102. vec2(x + 25, y + 25),
    103. rgbm(1.0, 1.0, 1.0, alpha)
    104. )
    105. end)
    106. if not success then
    107. ac.log("Nameplate: Failed to draw wheel icon from URL.")
    108. ui.dwriteDrawText("🏎", 26, vec2(x, y), rgbm(0.2, 1.0, 0.2, alpha), 1, ui.Alignment.Left, ui.Alignment.Top)
    109. end
    110. elseif inputType == "keyboard" then
    111. ui.dwriteDrawText("⌨", 26, vec2(x, y), rgbm(0.2, 0.8, 1.0, alpha), 1, ui.Alignment.Left, ui.Alignment.Top)
    112. elseif inputType == "gamepad" then
    113. -- Use controller image - bigger size (36x36) and white color
    114. local success = pcall(function()
    115. ui.drawImage(
    116. "https://i.ibb.co/3m56fyZy/gamepad.png",
    117. vec2(x, y),
    118. vec2(x + 36, y + 36),
    119. rgbm(1.0, 1.0, 1.0, alpha)
    120. )
    121. end)
    122. if not success then
    123. ac.log("Nameplate: Failed to draw gamepad icon from URL.")
    124. ui.dwriteDrawText("🎮", 26, vec2(x, y), rgbm(1.0, 0.8, 0.2, alpha), 1, ui.Alignment.Left, ui.Alignment.Top)
    125. end
    126. else
    127. -- Unknown - show question mark
    128. ui.dwriteDrawText("?", 26, vec2(x, y), rgbm(0.7, 0.7, 0.7, alpha), 1, ui.Alignment.Left, ui.Alignment.Top)
    129. end
    130. end
    131. function drawCountryFlag(nationCode, x, y)
    132. if nationCode and nationCode ~= "" then
    133. -- Try to draw flag image
    134. local success = pcall(function()
    135. ui.drawImage(
    136. "/content/gui/flags/" .. nationCode .. ".png",
    137. vec2(x, y),
    138. vec2(x + 24, y + 18),
    139. rgbm(1, 1, 1, 1)
    140. )
    141. end)
    142. -- If flag fails, show country code
    143. if not success then
    144. ui.dwriteDrawText(nationCode, 16, vec2(x, y + 2), rgbm(0.8, 0.8, 1.0, 1), 1, ui.Alignment.Left, ui.Alignment.Top)
    145. end
    146. end
    147. end
    148. function drawPingBars(x, y, ping, pingColor)
    149. local barWidth = 6
    150. local barHeight = 16
    151. local barSpacing = 3
    152. local maxBars = 4
    153. local bars = 4
    154. if ping > 200 then
    155. bars = 1
    156. elseif ping > 150 then
    157. bars = 2
    158. elseif ping > 100 then
    159. bars = 3
    160. end
    161. for i = 1, maxBars do
    162. local barX = x + (i - 1) * (barWidth + barSpacing)
    163. local currentBarHeight = barHeight * (i / maxBars)
    164. local currentY = y + barHeight - currentBarHeight
    165. local alpha = (i <= bars) and 1.0 or 0.3
    166. local color = rgbm(pingColor.r, pingColor.g, pingColor.b, alpha)
    167. ui.drawRectFilled(vec2(barX, currentY), vec2(barX + barWidth, y + barHeight), color)
    168. end
    169. end
    170. ui.onDriverNameTag(function(car)
    171. -- Clean the driver name properly
    172. local rawName = tostring(car.driverName or "unknown")
    173. local name = rawName:gsub("0x[%x]+", ""):gsub("[^%w%s*%-%.%@]", "")
    174. name = name:gsub("^%s*(.-)%s*$", "%1")
    175. -- Skip AI traffic cars - only show input modes for real players
    176. local isRealPlayer = car.isConnected and not car.isAIControlled
    177. if not isRealPlayer then
    178. -- For AI cars, just show name without input mode
    179. ui.pushDWriteFont("Berlin Sans FB")
    180. ui.drawRectFilled(vec2(-90, 0), vec2(470, 36), rgbm(0, 0, 0, 0.0), 8)
    181. ui.dwriteDrawText(name, 21, vec2(-80, 6), rgbm(0.8, 0.8, 0.8, 1), 1, ui.Alignment.Left, ui.Alignment.Top)
    182. ui.popDWriteFont()
    183. return
    184. end
    185. local ping = car.ping or car.pingMs or 0
    186. local pingColor = rgbm(0.2, 1.0, 0.2, 1.0)
    187. if ping > 250 then
    188. pingColor = rgbm(1.0, 0.2, 0.2, 1.0)
    189. elseif ping > 120 then
    190. pingColor = rgbm(1.0, 1.0, 0.2, 1.0)
    191. end
    192. -- Get nation code
    193. local nationCode = ""
    194. if car.driverNationCode and car.driverNationCode ~= "" then
    195. nationCode = string.upper(tostring(car.driverNationCode))
    196. elseif car.nationality and car.nationality ~= "" then
    197. nationCode = string.upper(tostring(car.nationality))
    198. else
    199. nationCode = "ITA"
    200. end
    201. local speed = (car.speedKmh or 0)
    202. local speedText = string.format("%d KM/H", speed)
    203. ui.pushDWriteFont("Berlin Sans FB")
    204. -- Main background - MADE TRANSPARENT to avoid overlap
    205. ui.drawRectFilled(vec2(-90, 0), vec2(470, 36), rgbm(0, 0, 0, 0.0), 8)
    206. -- Driver name (leftmost)
    207. ui.dwriteDrawText(name, 21, vec2(-80, 6), rgbm(1,1,1,1), 1, ui.Alignment.Left, ui.Alignment.Top)
    208. -- Layout: Name | Input | Flag | Ping Bars
    209. local inputX = 322 -- Input icon position (moved further right to avoid name overlap)
    210. local flagX = 320 -- Flag position (moved right to make room for input)
    211. local barsX = 320 -- Ping bars position (moved right)
    212. local barsY = 18
    213. -- Input icon (moved further right and better vertical centering) - only for real players
    214. local inputType = getInputType(car)
    215. drawInputIcon(inputType, inputX, 35, 1.0) -- Lower vertical position for better centering
    216. -- Country flag
    217. drawCountryFlag(nationCode, flagX, 9)
    218. -- Ping bars (rightmost)
    219. drawPingBars(barsX, barsY, ping, pingColor)
    220. -- رقم البنق يمين الشارة (نفس فكرة السكربت الثاني)
    221. ui.dwriteDrawText(tostring(ping).."ms", 26, vec2(barsX + 40, 8), pingColor, 1, ui.Alignment.Left, ui.Alignment.Top)
    222. -- Steam Avatar (right of ping)
    223. local avatarUrl = steamAvatarUrls[car.sessionID]
    224. if avatarUrl then
    225. local avatarX = barsX + -321 -- Adjust X position relative to ping bars
    226. local avatarY = 2 -- Adjust Y position to align with ping text
    227. local avatarSize = 60 -- Adjust size as needed (e.g., 24x24)
    228. local success = pcall(function()
    229. ui.drawImage(
    230. avatarUrl,
    231. vec2(avatarX, avatarY),
    232. vec2(avatarX + avatarSize, avatarY + avatarSize),
    233. rgbm(1, 1, 1, 1)
    234. )
    235. end)
    236. if not success then
    237. ac.log("Nameplate: Failed to draw avatar from URL: " .. avatarUrl)
    238. end
    239. end
    240. -- الشريط الأزرق للسرعة
    241. local minSpeed, maxSpeed = 0, 260
    242. local speedBoxX = -90
    243. local speedBoxWMax = 560
    244. local speedBoxH = 17
    245. local speedBoxY = 46
    246. local t = math.max(0, math.min(1, (speed-minSpeed)/(maxSpeed-minSpeed)))
    247. local minWidth = 15
    248. local speedBoxW = minWidth + (speedBoxWMax - minWidth) * t
    249. ui.drawRectFilled(vec2(speedBoxX, speedBoxY), vec2(speedBoxX + speedBoxW, speedBoxY + speedBoxH), rgbm(0.1, 0.45, 0.95, 0.89), 7)
    250. ui.dwriteDrawText(speedText, 18, vec2(speedBoxX + speedBoxWMax/2, speedBoxY - 1), rgbm(1,1,1,1), 1, ui.Alignment.Center, ui.Alignment.Top)
    251. ui.popDWriteFont()
    252. -- Debug info in console every few seconds - only for real players
    253. if math.fmod(os.clock(), 5) < 0.1 then
    254. local sessionId = car.sessionID or "unknown"
    255. ac.log("Nameplate Debug: Player " .. name .. " - Session: " .. sessionId .. " - Input: " .. inputType .. " - Server data available: " .. tostring(serverInputModes[sessionId] ~= nil))
    256. end
    257. end)
    258. -- Debug logging
    259. ac.log("Nameplate: Enhanced script loaded with server input mode integration!")
    260. -- Periodic debug info
    261. local lastDebugTime = 0
    262. function script.update(dt)
    263. local currentTime = os.clock()
    264. if currentTime - lastDebugTime > 10 then -- Every 10 seconds
    265. lastDebugTime = currentTime
    266. local serverDataCount = 0
    267. for _ in pairs(serverInputModes) do
    268. serverDataCount = serverDataCount + 1
    269. end
    270. ac.log("Nameplate: Server input modes tracked: " .. serverDataCount .. " | Last broadcast: " ..
    271. (lastBroadcastReceived > 0 and string.format("%.1fs ago", currentTime - lastDebugTime) or "never"))
    272. end
    273. end
    Add Comment
    Please, Sign In to add comment
    Public Pastes
    We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
    Not a member of Pastebin yet?
    Sign Up, it unlocks many cool features!

    AltStyle によって変換されたページ (->オリジナル) /