Skip to content

Commit 5b56123

Browse files
committed
add TeleportPlugin
1 parent b800fe8 commit 5b56123

File tree

7 files changed

+256
-18
lines changed

7 files changed

+256
-18
lines changed

AssettoServer.sln

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,41 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio Version 16
4-
VisualStudioVersion = 16.0.30420.98
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.9.34701.34
55
MinimumVisualStudioVersion = 10.0.40219.1
6-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssettoServer", "AssettoServer\AssettoServer.csproj", "{7FDA59D8-BF5B-4B50-8F61-37611D087D24}"
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssettoServer", "AssettoServer\AssettoServer.csproj", "{7FDA59D8-BF5B-4B50-8F61-37611D087D24}"
77
EndProject
8-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscordAuditPlugin", "DiscordAuditPlugin\DiscordAuditPlugin.csproj", "{9C7F1530-DF2D-41D4-A6F1-857955106869}"
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscordAuditPlugin", "DiscordAuditPlugin\DiscordAuditPlugin.csproj", "{9C7F1530-DF2D-41D4-A6F1-857955106869}"
99
EndProject
10-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamplePlugin", "SamplePlugin\SamplePlugin.csproj", "{DAF372D3-E030-4911-8537-A55325B4F6B5}"
10+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SamplePlugin", "SamplePlugin\SamplePlugin.csproj", "{DAF372D3-E030-4911-8537-A55325B4F6B5}"
1111
EndProject
12-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VotingWeatherPlugin", "VotingWeatherPlugin\VotingWeatherPlugin.csproj", "{1C5C55F2-C818-4277-9DBE-0EAFF35F59AA}"
12+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VotingWeatherPlugin", "VotingWeatherPlugin\VotingWeatherPlugin.csproj", "{1C5C55F2-C818-4277-9DBE-0EAFF35F59AA}"
1313
EndProject
14-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiveWeatherPlugin", "LiveWeatherPlugin\LiveWeatherPlugin.csproj", "{02FEF3DC-BCEC-4888-9B4E-BDE31DD6E58D}"
14+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiveWeatherPlugin", "LiveWeatherPlugin\LiveWeatherPlugin.csproj", "{02FEF3DC-BCEC-4888-9B4E-BDE31DD6E58D}"
1515
EndProject
16-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WordFilterPlugin", "WordFilterPlugin\WordFilterPlugin.csproj", "{C16217E0-D82B-43EF-A5E0-836ED135AA8C}"
16+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WordFilterPlugin", "WordFilterPlugin\WordFilterPlugin.csproj", "{C16217E0-D82B-43EF-A5E0-836ED135AA8C}"
1717
EndProject
18-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RaceChallengePlugin", "RaceChallengePlugin\RaceChallengePlugin.csproj", "{2F522CD8-2890-4E00-97DB-4E2E1B407677}"
18+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RaceChallengePlugin", "RaceChallengePlugin\RaceChallengePlugin.csproj", "{2F522CD8-2890-4E00-97DB-4E2E1B407677}"
1919
EndProject
20-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GeoIPPlugin", "GeoIPPlugin\GeoIPPlugin.csproj", "{F0F4ECA0-24FA-4913-92CB-B48A0DD129F3}"
20+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeoIPPlugin", "GeoIPPlugin\GeoIPPlugin.csproj", "{F0F4ECA0-24FA-4913-92CB-B48A0DD129F3}"
2121
EndProject
22-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReportPlugin", "ReportPlugin\ReportPlugin.csproj", "{AF514EA8-5FC5-4A1B-9065-EC0AD34639B1}"
22+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReportPlugin", "ReportPlugin\ReportPlugin.csproj", "{AF514EA8-5FC5-4A1B-9065-EC0AD34639B1}"
2323
EndProject
24-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastLaneUtils", "FastLaneUtils\FastLaneUtils.csproj", "{12A71A2F-CB26-4452-8B24-D3DA2A32466E}"
24+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastLaneUtils", "FastLaneUtils\FastLaneUtils.csproj", "{12A71A2F-CB26-4452-8B24-D3DA2A32466E}"
2525
EndProject
26-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TimeDilationPlugin", "TimeDilationPlugin\TimeDilationPlugin.csproj", "{F479976E-7BB0-49EB-A97E-5389C0601D91}"
26+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TimeDilationPlugin", "TimeDilationPlugin\TimeDilationPlugin.csproj", "{F479976E-7BB0-49EB-A97E-5389C0601D91}"
2727
EndProject
28-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoModerationPlugin", "AutoModerationPlugin\AutoModerationPlugin.csproj", "{59C320A4-11D8-4BAE-81F1-226D012F5484}"
28+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoModerationPlugin", "AutoModerationPlugin\AutoModerationPlugin.csproj", "{59C320A4-11D8-4BAE-81F1-226D012F5484}"
2929
EndProject
30-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RandomWeatherPlugin", "RandomWeatherPlugin\RandomWeatherPlugin.csproj", "{7289448F-D8EF-4EB7-AFE3-4EDB27EE75E0}"
30+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RandomWeatherPlugin", "RandomWeatherPlugin\RandomWeatherPlugin.csproj", "{7289448F-D8EF-4EB7-AFE3-4EDB27EE75E0}"
3131
EndProject
32-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssettoServer.Shared", "AssettoServer.Shared\AssettoServer.Shared.csproj", "{C7A903BD-6640-460A-BDD1-DFF6FC407E31}"
32+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssettoServer.Shared", "AssettoServer.Shared\AssettoServer.Shared.csproj", "{C7A903BD-6640-460A-BDD1-DFF6FC407E31}"
3333
EndProject
34-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssettoServer.Tests", "AssettoServer.Tests\AssettoServer.Tests.csproj", "{DA97DFBB-EA56-468C-BEDE-7CBEB360DD0E}"
34+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssettoServer.Tests", "AssettoServer.Tests\AssettoServer.Tests.csproj", "{DA97DFBB-EA56-468C-BEDE-7CBEB360DD0E}"
3535
EndProject
36-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VotingPresetPlugin", "VotingPresetPlugin\VotingPresetPlugin.csproj", "{458FEEA8-D472-4FA9-8E50-63F04F05180A}"
36+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VotingPresetPlugin", "VotingPresetPlugin\VotingPresetPlugin.csproj", "{458FEEA8-D472-4FA9-8E50-63F04F05180A}"
37+
EndProject
38+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TeleportPlugin", "TeleportPlugin\TeleportPlugin.csproj", "{8436E8CE-3668-480B-87D2-B318BBA3E688}"
3739
EndProject
3840
Global
3941
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -105,6 +107,10 @@ Global
105107
{458FEEA8-D472-4FA9-8E50-63F04F05180A}.Debug|Any CPU.Build.0 = Debug|Any CPU
106108
{458FEEA8-D472-4FA9-8E50-63F04F05180A}.Release|Any CPU.ActiveCfg = Release|Any CPU
107109
{458FEEA8-D472-4FA9-8E50-63F04F05180A}.Release|Any CPU.Build.0 = Release|Any CPU
110+
{8436E8CE-3668-480B-87D2-B318BBA3E688}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
111+
{8436E8CE-3668-480B-87D2-B318BBA3E688}.Debug|Any CPU.Build.0 = Debug|Any CPU
112+
{8436E8CE-3668-480B-87D2-B318BBA3E688}.Release|Any CPU.ActiveCfg = Release|Any CPU
113+
{8436E8CE-3668-480B-87D2-B318BBA3E688}.Release|Any CPU.Build.0 = Release|Any CPU
108114
EndGlobalSection
109115
GlobalSection(SolutionProperties) = preSolution
110116
HideSolutionNode = FALSE

TeleportPlugin/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# TeleportPlugin
2+
Plugin to let admins teleport to other cars or locations.
3+
4+
## Configuration
5+
Enable the plugin in `extra_cfg.yml`
6+
```yaml
7+
EnablePlugins:
8+
- TeleportPlugin
9+
```

TeleportPlugin/TeleportModule.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using AssettoServer.Server.Plugin;
2+
using Autofac;
3+
4+
namespace TeleportPlugin;
5+
6+
public class TeleportModule : AssettoServerModule
7+
{
8+
protected override void Load(ContainerBuilder builder)
9+
{
10+
builder.RegisterType<TeleportPlugin>().AsSelf().AutoActivate().SingleInstance();
11+
}
12+
}

TeleportPlugin/TeleportPlugin.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System.Reflection;
2+
using AssettoServer.Server.Plugin;
3+
using AssettoServer.Server;
4+
using AssettoServer.Server.Configuration;
5+
using Serilog;
6+
7+
namespace TeleportPlugin;
8+
9+
public class TeleportPlugin
10+
{
11+
private readonly EntryCarManager _entryCarManager;
12+
13+
public TeleportPlugin(
14+
EntryCarManager entryCarManager, ACServerConfiguration serverConfiguration,
15+
CSPServerScriptProvider scriptProvider)
16+
{
17+
_entryCarManager = entryCarManager;
18+
19+
if (!serverConfiguration.Extra.EnableClientMessages)
20+
{
21+
Log.Error("TeleportModule requires EnableClientMessages");
22+
return;
23+
}
24+
25+
scriptProvider.AddScript(
26+
new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("TeleportPlugin.lua.teleport-to-location.lua")!).ReadToEnd(),
27+
"teleport-to-location.lua"
28+
);
29+
scriptProvider.AddScript(
30+
new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("TeleportPlugin.lua.teleport-to-car.lua")!).ReadToEnd(),
31+
"teleport-to-car.lua"
32+
);
33+
}
34+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
<EnableDynamicLoading>true</EnableDynamicLoading>
8+
<SelfContained>false</SelfContained>
9+
<DebugType>embedded</DebugType>
10+
<PublishDir>..\out-$(RuntimeIdentifier)\plugins\$(MSBuildProjectName)\</PublishDir>
11+
<PathMap>$(MSBuildProjectDirectory)=$(MSBuildProjectName)</PathMap>
12+
</PropertyGroup>
13+
14+
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
15+
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
16+
<OutputPath>..\AssettoServer\bin\$(Configuration)\$(TargetFramework)\plugins\$(MSBuildProjectName)</OutputPath>
17+
</PropertyGroup>
18+
19+
<ItemGroup>
20+
<ProjectReference Include="..\AssettoServer.Shared\AssettoServer.Shared.csproj">
21+
<Private>false</Private>
22+
<ExcludeAssets>runtime</ExcludeAssets>
23+
</ProjectReference>
24+
<ProjectReference Include="..\AssettoServer\AssettoServer.csproj">
25+
<Private>false</Private>
26+
<ExcludeAssets>runtime</ExcludeAssets>
27+
</ProjectReference>
28+
</ItemGroup>
29+
</Project>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
-- Copyright 2024 <github.com/razaqq>
2+
3+
local sim = ac.getSim()
4+
5+
local selectedCar = nil ---@type ac.StateCar
6+
7+
local function TeleportHUD()
8+
ui.text('Select car to teleport to:')
9+
10+
ui.childWindow('##drivers', vec2(ui.availableSpaceX(), 120), function ()
11+
for i = 1, sim.carsCount - 1 do
12+
local car = ac.getCar(i)
13+
14+
local driverName = ac.getDriverName(i)
15+
16+
if car.isConnected and not car.isAIControlled and not string.find(driverName, "Traffic") then
17+
if ui.selectable(driverName, selectedCar == car) then
18+
selectedCar = car
19+
end
20+
21+
end
22+
end
23+
end)
24+
end
25+
26+
local function TeleportHUDClosed(okClicked)
27+
if okClicked and selectedCar then
28+
local dir = selectedCar.look;
29+
physics.setCarVelocity(0, vec3(0, 0, 0))
30+
-- spawn 8 meters behind, add 0.1 meter height to avoid falling through the map
31+
physics.setCarPosition(0, selectedCar.position + vec3(0, 0.1, 0) - dir * 8, -dir)
32+
end
33+
end
34+
35+
ui.registerOnlineExtra(ui.Icons.FastForward, 'Teleport To Car', nil, TeleportHUD, TeleportHUDClosed, ui.OnlineExtraFlags.Admin)
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
-- Copyright 2024 <github.com/razaqq>
2+
3+
-- script allowing admins to teleport
4+
5+
local sim = ac.getSim()
6+
7+
local currentUiTargetPos = vec2(0, 0)
8+
local targetPos = vec2(0.5, 0.5)
9+
10+
-- get track map
11+
local mapFilename = ac.getFolder(ac.FolderID.ContentTracks)..'/'..ac.getTrackFullID('/')..'/map.png'
12+
13+
-- read map parameters
14+
local mapParams = ac.INIConfig.load(ac.getFolder(ac.FolderID.ContentTracks)..'/'..ac.getTrackFullID('/')..'/data/map.ini'):mapSection('PARAMETERS', {
15+
X_OFFSET = 0,
16+
Z_OFFSET = 0,
17+
SCALE_FACTOR = 1,
18+
WIDTH = 600,
19+
HEIGHT = 600
20+
})
21+
22+
-- And last, size of the map. We could calculate it each frame, but it’s nicer if done this way:
23+
local mapSize = vec2(mapParams.WIDTH / mapParams.HEIGHT * 1000, 1000)
24+
25+
---@param pos vec2 Ui Position
26+
---@param color rgbm
27+
---@param text string
28+
local function DrawCar(pos, color, text)
29+
ui.drawCircleFilled(pos, 3, color)
30+
ui.drawText(text, pos + vec2(0, -3), color)
31+
end
32+
33+
---@param drawOrigin vec2 2D Origin Pos where the map is drawn from
34+
---@param uiPos vec2
35+
---@return vec2
36+
local function UiPosToWorldPos(drawOrigin, uiPos)
37+
local p = (uiPos - drawOrigin) / mapSize
38+
local worldPosX = (p.x * mapParams.WIDTH * mapParams.SCALE_FACTOR) - mapParams.X_OFFSET
39+
local worldPosY = (p.y * mapParams.HEIGHT * mapParams.SCALE_FACTOR) - mapParams.Z_OFFSET
40+
return vec2(worldPosX, worldPosY)
41+
end
42+
43+
---@param drawOrigin vec2 2D Origin Pos where the map is drawn from
44+
---@param worldPos vec3
45+
---@return vec2
46+
local function WorldPosToUiPos(drawOrigin, worldPos)
47+
local relPosX = (worldPos.x + mapParams.X_OFFSET) / mapParams.WIDTH / mapParams.SCALE_FACTOR
48+
local relPosY = (worldPos.z + mapParams.Z_OFFSET) / mapParams.HEIGHT / mapParams.SCALE_FACTOR
49+
return drawOrigin + vec2(relPosX, relPosY) * mapSize
50+
end
51+
52+
---@param worldPos vec3
53+
---@return vec3
54+
local function FixWorldPosHeight(worldPos)
55+
local trackPos = ac.worldCoordinateToTrack(worldPos)
56+
trackPos.y = 10
57+
return ac.trackCoordinateToWorld(trackPos)
58+
end
59+
60+
local function TeleportHUD()
61+
ui.text('Select point on a map:')
62+
63+
local drawOrigin = ui.getCursor()
64+
65+
ui.drawImage(mapFilename, drawOrigin, drawOrigin + mapSize)
66+
67+
-- draw all other cars with driver name, filter out traffic
68+
for i = 0, sim.carsCount - 1 do
69+
local car = ac.getCar(i)
70+
local driverName = ac.getDriverName(i)
71+
if car.isConnected and not car.isAIControlled and not string.find(driverName, "Traffic") then
72+
local color = i == 0 and rgbm.colors.red or rgbm.colors.blue
73+
DrawCar(WorldPosToUiPos(drawOrigin, car.position), color, driverName)
74+
end
75+
end
76+
77+
-- All `ui.draw…` functions don’t actually move cursor, so we’re still where we were when started drawing stuff. Let’s move with
78+
-- map size, so that window size would extend and include map:
79+
ui.dummy(mapSize)
80+
81+
if ui.itemClicked() then
82+
local mousePos = ui.mouseLocalPos();
83+
currentUiTargetPos = mousePos
84+
-- save world pos
85+
targetPos = UiPosToWorldPos(drawOrigin, mousePos)
86+
end
87+
88+
ui.drawCircleFilled(currentUiTargetPos, 4, rgbm.colors.green)
89+
end
90+
91+
local function TeleportHUDClosed(okClicked)
92+
if okClicked then
93+
physics.setCarVelocity(0, vec3(0, 0, 0))
94+
95+
if ac.hasTrackSpline() then
96+
local finalPos = FixWorldPosHeight(vec3(targetPos.x, 0, targetPos.y))
97+
-- careful, the direction needs to be able to be normalized, otherwise the game crashes
98+
physics.setCarPosition(0, finalPos, vec3(1, 0, 0))
99+
else
100+
-- this is a bit hacky...
101+
local finalPos = vec3(targetPos.x, 5000, targetPos.y)
102+
local point = vec3(0, 0, 0)
103+
-- the normal appears to be buggy, maybe the ray bounce is influenced by vegetation?
104+
if physics.raycastTrack(finalPos, vec3(0, -1, 0), 10000, point, nil) > -1 then
105+
physics.setCarPosition(0, point + vec3(0, 1, 0), vec3(1, 0, 0))
106+
else
107+
ac.setMessage('Error', 'Failed to determine y coordinate of track.')
108+
end
109+
end
110+
end
111+
end
112+
113+
ui.registerOnlineExtra(ui.Icons.FastForward, 'Teleport to Location', nil, TeleportHUD, TeleportHUDClosed, ui.OnlineExtraFlags.Admin)

0 commit comments

Comments
 (0)