Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 24 additions & 18 deletions AssettoServer.sln
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions TeleportPlugin/README.md
Original file line number Diff line number Diff line change
@@ -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
```
12 changes: 12 additions & 0 deletions TeleportPlugin/TeleportModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using AssettoServer.Server.Plugin;
using Autofac;

namespace TeleportPlugin;

public class TeleportModule : AssettoServerModule
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<TeleportPlugin>().AsSelf().AutoActivate().SingleInstance();
}
}
19 changes: 19 additions & 0 deletions TeleportPlugin/TeleportPlugin.cs
Original file line number Diff line number Diff line change
@@ -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"
);
}
}
36 changes: 36 additions & 0 deletions TeleportPlugin/TeleportPlugin.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<EnableDynamicLoading>true</EnableDynamicLoading>
<SelfContained>false</SelfContained>
<DebugType>embedded</DebugType>
<PublishDir>..\out-$(RuntimeIdentifier)\plugins\$(MSBuildProjectName)\</PublishDir>
<PathMap>$(MSBuildProjectDirectory)=$(MSBuildProjectName)</PathMap>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<OutputPath>..\AssettoServer\bin\$(Configuration)\$(TargetFramework)\plugins\$(MSBuildProjectName)</OutputPath>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\AssettoServer.Shared\AssettoServer.Shared.csproj">
<Private>false</Private>
<ExcludeAssets>runtime</ExcludeAssets>
</ProjectReference>
<ProjectReference Include="..\AssettoServer\AssettoServer.csproj">
<Private>false</Private>
<ExcludeAssets>runtime</ExcludeAssets>
</ProjectReference>
</ItemGroup>

<ItemGroup>
<None Remove="lua\teleport-to-car.lua" />
<EmbeddedResource Include="lua\teleport-to-car.lua" />
<None Remove="lua\teleport-to-location.lua" />
<EmbeddedResource Include="lua\teleport-to-location.lua" />
</ItemGroup>
</Project>
35 changes: 35 additions & 0 deletions TeleportPlugin/lua/teleport-to-car.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
-- Copyright 2024 <github.com/razaqq>

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)
113 changes: 113 additions & 0 deletions TeleportPlugin/lua/teleport-to-location.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
-- Copyright 2024 <github.com/razaqq>

-- 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)