diff --git a/AssettoServer.sln b/AssettoServer.sln index cac89acb..68d30a9a 100644 --- a/AssettoServer.sln +++ b/AssettoServer.sln @@ -1,39 +1,41 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30420.98 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34701.34 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssettoServer", "AssettoServer\AssettoServer.csproj", "{7FDA59D8-BF5B-4B50-8F61-37611D087D24}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssettoServer", "AssettoServer\AssettoServer.csproj", "{7FDA59D8-BF5B-4B50-8F61-37611D087D24}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscordAuditPlugin", "DiscordAuditPlugin\DiscordAuditPlugin.csproj", "{9C7F1530-DF2D-41D4-A6F1-857955106869}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscordAuditPlugin", "DiscordAuditPlugin\DiscordAuditPlugin.csproj", "{9C7F1530-DF2D-41D4-A6F1-857955106869}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamplePlugin", "SamplePlugin\SamplePlugin.csproj", "{DAF372D3-E030-4911-8537-A55325B4F6B5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SamplePlugin", "SamplePlugin\SamplePlugin.csproj", "{DAF372D3-E030-4911-8537-A55325B4F6B5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VotingWeatherPlugin", "VotingWeatherPlugin\VotingWeatherPlugin.csproj", "{1C5C55F2-C818-4277-9DBE-0EAFF35F59AA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VotingWeatherPlugin", "VotingWeatherPlugin\VotingWeatherPlugin.csproj", "{1C5C55F2-C818-4277-9DBE-0EAFF35F59AA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiveWeatherPlugin", "LiveWeatherPlugin\LiveWeatherPlugin.csproj", "{02FEF3DC-BCEC-4888-9B4E-BDE31DD6E58D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiveWeatherPlugin", "LiveWeatherPlugin\LiveWeatherPlugin.csproj", "{02FEF3DC-BCEC-4888-9B4E-BDE31DD6E58D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WordFilterPlugin", "WordFilterPlugin\WordFilterPlugin.csproj", "{C16217E0-D82B-43EF-A5E0-836ED135AA8C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WordFilterPlugin", "WordFilterPlugin\WordFilterPlugin.csproj", "{C16217E0-D82B-43EF-A5E0-836ED135AA8C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RaceChallengePlugin", "RaceChallengePlugin\RaceChallengePlugin.csproj", "{2F522CD8-2890-4E00-97DB-4E2E1B407677}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RaceChallengePlugin", "RaceChallengePlugin\RaceChallengePlugin.csproj", "{2F522CD8-2890-4E00-97DB-4E2E1B407677}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GeoIPPlugin", "GeoIPPlugin\GeoIPPlugin.csproj", "{F0F4ECA0-24FA-4913-92CB-B48A0DD129F3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeoIPPlugin", "GeoIPPlugin\GeoIPPlugin.csproj", "{F0F4ECA0-24FA-4913-92CB-B48A0DD129F3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReportPlugin", "ReportPlugin\ReportPlugin.csproj", "{AF514EA8-5FC5-4A1B-9065-EC0AD34639B1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReportPlugin", "ReportPlugin\ReportPlugin.csproj", "{AF514EA8-5FC5-4A1B-9065-EC0AD34639B1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastLaneUtils", "FastLaneUtils\FastLaneUtils.csproj", "{12A71A2F-CB26-4452-8B24-D3DA2A32466E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastLaneUtils", "FastLaneUtils\FastLaneUtils.csproj", "{12A71A2F-CB26-4452-8B24-D3DA2A32466E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TimeDilationPlugin", "TimeDilationPlugin\TimeDilationPlugin.csproj", "{F479976E-7BB0-49EB-A97E-5389C0601D91}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TimeDilationPlugin", "TimeDilationPlugin\TimeDilationPlugin.csproj", "{F479976E-7BB0-49EB-A97E-5389C0601D91}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoModerationPlugin", "AutoModerationPlugin\AutoModerationPlugin.csproj", "{59C320A4-11D8-4BAE-81F1-226D012F5484}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoModerationPlugin", "AutoModerationPlugin\AutoModerationPlugin.csproj", "{59C320A4-11D8-4BAE-81F1-226D012F5484}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RandomWeatherPlugin", "RandomWeatherPlugin\RandomWeatherPlugin.csproj", "{7289448F-D8EF-4EB7-AFE3-4EDB27EE75E0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RandomWeatherPlugin", "RandomWeatherPlugin\RandomWeatherPlugin.csproj", "{7289448F-D8EF-4EB7-AFE3-4EDB27EE75E0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssettoServer.Shared", "AssettoServer.Shared\AssettoServer.Shared.csproj", "{C7A903BD-6640-460A-BDD1-DFF6FC407E31}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssettoServer.Shared", "AssettoServer.Shared\AssettoServer.Shared.csproj", "{C7A903BD-6640-460A-BDD1-DFF6FC407E31}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssettoServer.Tests", "AssettoServer.Tests\AssettoServer.Tests.csproj", "{DA97DFBB-EA56-468C-BEDE-7CBEB360DD0E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssettoServer.Tests", "AssettoServer.Tests\AssettoServer.Tests.csproj", "{DA97DFBB-EA56-468C-BEDE-7CBEB360DD0E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VotingPresetPlugin", "VotingPresetPlugin\VotingPresetPlugin.csproj", "{458FEEA8-D472-4FA9-8E50-63F04F05180A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VotingPresetPlugin", "VotingPresetPlugin\VotingPresetPlugin.csproj", "{458FEEA8-D472-4FA9-8E50-63F04F05180A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TeleportPlugin", "TeleportPlugin\TeleportPlugin.csproj", "{8436E8CE-3668-480B-87D2-B318BBA3E688}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -105,6 +107,10 @@ Global {458FEEA8-D472-4FA9-8E50-63F04F05180A}.Debug|Any CPU.Build.0 = Debug|Any CPU {458FEEA8-D472-4FA9-8E50-63F04F05180A}.Release|Any CPU.ActiveCfg = Release|Any CPU {458FEEA8-D472-4FA9-8E50-63F04F05180A}.Release|Any CPU.Build.0 = Release|Any CPU + {8436E8CE-3668-480B-87D2-B318BBA3E688}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8436E8CE-3668-480B-87D2-B318BBA3E688}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8436E8CE-3668-480B-87D2-B318BBA3E688}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8436E8CE-3668-480B-87D2-B318BBA3E688}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/TeleportPlugin/README.md b/TeleportPlugin/README.md new file mode 100644 index 00000000..72736fb1 --- /dev/null +++ b/TeleportPlugin/README.md @@ -0,0 +1,9 @@ +# TeleportPlugin +Plugin to let admins teleport to other cars or locations. + +## Configuration +Enable the plugin in `extra_cfg.yml` +```yaml +EnablePlugins: +- TeleportPlugin +``` diff --git a/TeleportPlugin/TeleportModule.cs b/TeleportPlugin/TeleportModule.cs new file mode 100644 index 00000000..dc84d434 --- /dev/null +++ b/TeleportPlugin/TeleportModule.cs @@ -0,0 +1,12 @@ +using AssettoServer.Server.Plugin; +using Autofac; + +namespace TeleportPlugin; + +public class TeleportModule : AssettoServerModule +{ + protected override void Load(ContainerBuilder builder) + { + builder.RegisterType().AsSelf().AutoActivate().SingleInstance(); + } +} diff --git a/TeleportPlugin/TeleportPlugin.cs b/TeleportPlugin/TeleportPlugin.cs new file mode 100644 index 00000000..985a37a6 --- /dev/null +++ b/TeleportPlugin/TeleportPlugin.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using AssettoServer.Server; + +namespace TeleportPlugin; + +public class TeleportPlugin +{ + public TeleportPlugin(CSPServerScriptProvider scriptProvider) + { + scriptProvider.AddScript( + new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("TeleportPlugin.lua.teleport-to-location.lua")!).ReadToEnd(), + "teleport-to-location.lua" + ); + scriptProvider.AddScript( + new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("TeleportPlugin.lua.teleport-to-car.lua")!).ReadToEnd(), + "teleport-to-car.lua" + ); + } +} diff --git a/TeleportPlugin/TeleportPlugin.csproj b/TeleportPlugin/TeleportPlugin.csproj new file mode 100644 index 00000000..27cfc044 --- /dev/null +++ b/TeleportPlugin/TeleportPlugin.csproj @@ -0,0 +1,36 @@ + + + + net8.0 + enable + enable + true + false + embedded + ..\out-$(RuntimeIdentifier)\plugins\$(MSBuildProjectName)\ + $(MSBuildProjectDirectory)=$(MSBuildProjectName) + + + + false + ..\AssettoServer\bin\$(Configuration)\$(TargetFramework)\plugins\$(MSBuildProjectName) + + + + + false + runtime + + + false + runtime + + + + + + + + + + diff --git a/TeleportPlugin/lua/teleport-to-car.lua b/TeleportPlugin/lua/teleport-to-car.lua new file mode 100644 index 00000000..328f9555 --- /dev/null +++ b/TeleportPlugin/lua/teleport-to-car.lua @@ -0,0 +1,35 @@ +-- Copyright 2024 + +local sim = ac.getSim() + +local selectedCar = nil ---@type ac.StateCar + +local function TeleportHUD() + ui.text('Select car to teleport to:') + + ui.childWindow('##drivers', vec2(ui.availableSpaceX(), 120), function () + for i = 1, sim.carsCount - 1 do + local car = ac.getCar(i) + + local driverName = ac.getDriverName(i) + + if car.isConnected and not car.isAIControlled and not string.find(driverName, "Traffic") then + if ui.selectable(driverName, selectedCar == car) then + selectedCar = car + end + + end + end + end) +end + +local function TeleportHUDClosed(okClicked) + if okClicked and selectedCar then + local dir = selectedCar.look; + physics.setCarVelocity(0, vec3(0, 0, 0)) + -- spawn 8 meters behind, add 0.1 meter height to avoid falling through the map + physics.setCarPosition(0, selectedCar.position + vec3(0, 0.1, 0) - dir * 8, -dir) + end +end + +ui.registerOnlineExtra(ui.Icons.FastForward, 'Teleport To Car', nil, TeleportHUD, TeleportHUDClosed, ui.OnlineExtraFlags.Admin) diff --git a/TeleportPlugin/lua/teleport-to-location.lua b/TeleportPlugin/lua/teleport-to-location.lua new file mode 100644 index 00000000..75cf0f54 --- /dev/null +++ b/TeleportPlugin/lua/teleport-to-location.lua @@ -0,0 +1,113 @@ +-- Copyright 2024 + +-- script allowing admins to teleport + +local sim = ac.getSim() + +local currentUiTargetPos = vec2(0, 0) +local targetPos = vec2(0.5, 0.5) + +-- get track map +local mapFilename = ac.getFolder(ac.FolderID.ContentTracks)..'/'..ac.getTrackFullID('/')..'/map.png' + +-- read map parameters +local mapParams = ac.INIConfig.load(ac.getFolder(ac.FolderID.ContentTracks)..'/'..ac.getTrackFullID('/')..'/data/map.ini'):mapSection('PARAMETERS', { + X_OFFSET = 0, + Z_OFFSET = 0, + SCALE_FACTOR = 1, + WIDTH = 600, + HEIGHT = 600 +}) + +-- And last, size of the map. We could calculate it each frame, but it’s nicer if done this way: +local mapSize = vec2(mapParams.WIDTH / mapParams.HEIGHT * 1000, 1000) + +---@param pos vec2 Ui Position +---@param color rgbm +---@param text string +local function DrawCar(pos, color, text) + ui.drawCircleFilled(pos, 3, color) + ui.drawText(text, pos + vec2(0, -3), color) +end + +---@param drawOrigin vec2 2D Origin Pos where the map is drawn from +---@param uiPos vec2 +---@return vec2 +local function UiPosToWorldPos(drawOrigin, uiPos) + local p = (uiPos - drawOrigin) / mapSize + local worldPosX = (p.x * mapParams.WIDTH * mapParams.SCALE_FACTOR) - mapParams.X_OFFSET + local worldPosY = (p.y * mapParams.HEIGHT * mapParams.SCALE_FACTOR) - mapParams.Z_OFFSET + return vec2(worldPosX, worldPosY) +end + +---@param drawOrigin vec2 2D Origin Pos where the map is drawn from +---@param worldPos vec3 +---@return vec2 +local function WorldPosToUiPos(drawOrigin, worldPos) + local relPosX = (worldPos.x + mapParams.X_OFFSET) / mapParams.WIDTH / mapParams.SCALE_FACTOR + local relPosY = (worldPos.z + mapParams.Z_OFFSET) / mapParams.HEIGHT / mapParams.SCALE_FACTOR + return drawOrigin + vec2(relPosX, relPosY) * mapSize +end + +---@param worldPos vec3 +---@return vec3 +local function FixWorldPosHeight(worldPos) + local trackPos = ac.worldCoordinateToTrack(worldPos) + trackPos.y = 10 + return ac.trackCoordinateToWorld(trackPos) +end + +local function TeleportHUD() + ui.text('Select point on a map:') + + local drawOrigin = ui.getCursor() + + ui.drawImage(mapFilename, drawOrigin, drawOrigin + mapSize) + + -- draw all other cars with driver name, filter out traffic + for i = 0, sim.carsCount - 1 do + local car = ac.getCar(i) + local driverName = ac.getDriverName(i) + if car ~= nil and driverName ~= nil and car.isConnected and not car.isAIControlled and not string.find(driverName, "Traffic") then + local color = i == 0 and rgbm.colors.red or rgbm.colors.blue + DrawCar(WorldPosToUiPos(drawOrigin, car.position), color, driverName) + end + end + + -- All `ui.draw…` functions don’t actually move cursor, so we’re still where we were when started drawing stuff. Let’s move with + -- map size, so that window size would extend and include map: + ui.dummy(mapSize) + + if ui.itemClicked() then + local mousePos = ui.mouseLocalPos(); + currentUiTargetPos = mousePos + -- save world pos + targetPos = UiPosToWorldPos(drawOrigin, mousePos) + end + + ui.drawCircleFilled(currentUiTargetPos, 4, rgbm.colors.green) +end + +local function TeleportHUDClosed(okClicked) + if okClicked then + physics.setCarVelocity(0, vec3(0, 0, 0)) + + if ac.hasTrackSpline() then + local finalPos = FixWorldPosHeight(vec3(targetPos.x, 0, targetPos.y)) + -- careful, the direction needs to be able to be normalized, otherwise the game crashes + physics.setCarPosition(0, finalPos, vec3(1, 0, 0)) + else + -- this is a bit hacky... + local finalPos = vec3(targetPos.x, 5000, targetPos.y) + local point = vec3(0, 0, 0) + -- the normal appears to be buggy, maybe the ray bounce is influenced by vegetation? + if physics.raycastTrack(finalPos, vec3(0, -1, 0), 10000, point, nil) > -1 then + physics.setCarPosition(0, point + vec3(0, 1, 0), vec3(1, 0, 0)) + else + ac.setMessage('Error', 'Failed to determine y coordinate of track.') + end + end + end +end + +ui.registerOnlineExtra(ui.Icons.FastForward, 'Teleport to Location', nil, TeleportHUD, TeleportHUDClosed, ui.OnlineExtraFlags.Admin)