forked from mspielberg/dv-hud
-
Notifications
You must be signed in to change notification settings - Fork 0
/
TrackIndexer.cs
executable file
·124 lines (112 loc) · 5.02 KB
/
TrackIndexer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
using DV.PointSet;
using DV.Signs;
using HarmonyLib;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace DvMod.HeadsUpDisplay
{
public static class TrackIndexer
{
internal const int SIGN_COLLIDER_LAYER = 30;
private const float SIMPLIFIED_RESOLUTION = 10f;
private static readonly Dictionary<RailTrack, List<TrackEvent>> indexedTracks =
new Dictionary<RailTrack, List<TrackEvent>>();
public static IEnumerable<TrackEvent> GetTrackEvents(RailTrack track)
{
if (!indexedTracks.TryGetValue(track, out var data))
{
float start = Time.realtimeSinceStartup;
data = indexedTracks[track] = GenerateTrackEvents(track).ToList();
float end = Time.realtimeSinceStartup;
Main.DebugLog($"Indexed track {track.logicTrack.ID}."
+ $" Found {data.Count} events ({data.OfType<SpeedLimitEvent>().Count()} speed signs) in {end-start} s.");
}
return data;
}
public static IEnumerable<TrackEvent> GetTrackEvents(RailTrack track, bool first, double start)
{
var allTrackEvents = GetTrackEvents(track);
var filtered = allTrackEvents.RelativeFromSpan(start, first);
// Debug.Log($"allTrackEvents:\n{string.Join("\n",allTrackEvents)}\nfiltered:\n{string.Join("\n",filtered)}");
return filtered;
}
private static SpeedLimitEvent? ParseSign(string colliderName, bool direction, double span)
{
string[] parts = colliderName.Split('\n');
return parts.Length switch
{
1 => new SpeedLimitEvent(span, direction, int.Parse(parts[0]) * 10),
2 => new DualSpeedLimitEvent(span, direction, int.Parse(parts[0]) * 10, int.Parse(parts[1]) * 10),
_ => null,
};
}
public static float Grade(EquiPointSet.Point point)
{
return (float)Mathf.RoundToInt(point.forward.y * 200) / 2f;
}
private static IEnumerable<SpeedLimitEvent> FindSigns(EquiPointSet.Point point)
{
// Debug.Log($"Raycasting from {(Vector3)point.position + WorldMover.currentMove} / {point.forward}");
var hits = Physics.RaycastAll(
new Ray((Vector3)point.position + WorldMover.currentMove, point.forward),
(float)point.spanToNextPoint,
1 << SIGN_COLLIDER_LAYER);
foreach (var hit in hits)
{
var dp = Vector3.Dot(hit.collider.transform.forward, point.forward);
// Debug.Log($"Found sign {hit.collider.name} at {hit.point}, dp = {dp}");
bool direction = dp < 0f;
var signEvent = ParseSign(hit.collider.name, direction, point.span + hit.distance);
if (signEvent == null)
Debug.Log($"Could not parse sign text {hit.collider.name}");
else
yield return signEvent;
}
}
private static IEnumerable<TrackEvent> GenerateTrackEvents(RailTrack track)
{
var pointSet = track.GetPointSet();
EquiPointSet simplified = EquiPointSet.ResampleEquidistant(
pointSet,
Mathf.Min(SIMPLIFIED_RESOLUTION, (float)pointSet.span / 3));
var lastGrade = float.NaN;
foreach (var point in simplified.points)
{
foreach (var sign in FindSigns(point))
yield return sign;
var grade = Grade(point);
if (grade != lastGrade)
{
yield return new GradeEvent(point.span, grade);
lastGrade = grade;
}
}
}
[HarmonyPatch(typeof(Streamer), nameof(Streamer.AddSceneGO))]
public static class AddSceneGOPatch
{
public static void Postfix(GameObject sceneGO)
{
var signDebugs = sceneGO.GetComponentsInChildren<SignDebug>();
bool foundSigns = false;
foreach (var signDebug in signDebugs)
{
signDebug.gameObject.layer = SIGN_COLLIDER_LAYER;
// var collider = signDebug.gameObject.AddComponent<CapsuleCollider>();
var collider = signDebug.gameObject.AddComponent<SphereCollider>();
collider.name = signDebug.text;
collider.center = new Vector3(2f, 0f, 0f);
collider.radius = 1f;
// collider.height = 100f;
// collider.direction = 1; // along Y-axis
collider.isTrigger = true;
foundSigns = true;
}
// Main.DebugLog($"Loaded tile {sceneGO} on frame {Time.frameCount}. Fixed update {Time.fixedTime / Time.fixedDeltaTime}");
if (foundSigns)
indexedTracks.Clear();
}
}
}
}