Skip to content

Commit 4548998

Browse files
committed
zoom, death checks, improvements
1 parent 31f1072 commit 4548998

File tree

8 files changed

+88
-59
lines changed

8 files changed

+88
-59
lines changed

Inputs.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,11 @@ internal class Inputs : LcInputActions
1313

1414
[InputAction("<Mouse>/rightButton", Name = "Toggle Flashlight")]
1515
public InputAction FlashlightKey { get; set; }
16+
17+
[InputAction("<Mouse>/scroll/down", Name = "Zoom Out")]
18+
public InputAction ZoomOutKey { get; set; }
19+
20+
[InputAction("<Mouse>/scroll/up", Name = "Zoom In")]
21+
public InputAction ZoomInKey { get; set; }
1622
}
1723
}

Patches/EnemyAI_Patches.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ private static void Postfix(EnemyAI __instance)
99
{
1010
Spectatable s = __instance.gameObject.AddComponent<Spectatable>();
1111
s.enemyName = __instance.enemyType.enemyName;
12+
s.enemyInstance = __instance;
1213
}
1314
}
1415
}

Patches/HUDManager_Patches.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,14 @@ private static void Postfix(HUDManager __instance)
2828
string swapKey = InputControlPath.ToHumanReadableString(Plugin.Inputs.SwapKey.bindings[0].effectivePath, InputControlPath.HumanReadableStringOptions.OmitDevice);
2929
string menuKey = InputControlPath.ToHumanReadableString(Plugin.Inputs.MenuKey.bindings[0].effectivePath, InputControlPath.HumanReadableStringOptions.OmitDevice);
3030
string flashlightKey = InputControlPath.ToHumanReadableString(Plugin.Inputs.FlashlightKey.bindings[0].effectivePath, InputControlPath.HumanReadableStringOptions.OmitDevice);
31+
string zoomOutKey = InputControlPath.ToHumanReadableString(Plugin.Inputs.ZoomOutKey.bindings[0].effectivePath, InputControlPath.HumanReadableStringOptions.OmitDevice);
32+
string zoomInKey = InputControlPath.ToHumanReadableString(Plugin.Inputs.ZoomInKey.bindings[0].effectivePath, InputControlPath.HumanReadableStringOptions.OmitDevice);
3133
// who needs to change the y position when u can just \n: sunglasses:
32-
__instance.holdButtonToEndGameEarlyText.text += $"\n\n\n\n\nSwitch to {(SpectateEnemies.Instance.SpectatingEnemies ? "Players" : "Enemies")}: [{swapKey}]\nToggle Flashlight : [{flashlightKey}] (Click)\nConfig Menu : [{menuKey}]";
34+
if (SpectateEnemies.Instance.SpectatingEnemies)
35+
__instance.holdButtonToEndGameEarlyText.text += $"\n\n\n\n\nSpectate Players: [{swapKey}]\nFlashlight : [{flashlightKey}]\nZoom Out [{zoomOutKey}]\nZoom In [{zoomInKey}]\nConfig Menu : [{menuKey}]";
36+
else
37+
__instance.holdButtonToEndGameEarlyText.text += $"\n\n\n\n\nSpectate Enemies: [{swapKey}]\nFlashlight : [{flashlightKey}]\nConfig Menu : [{menuKey}]";
38+
3339
}
3440
}
3541
}

Patches/MaskedPlayerEnemy_Patches.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ private static void Postfix(MaskedPlayerEnemy __instance)
1515
{
1616
s.maskedName = __instance.mimickingPlayer.playerUsername;
1717
}
18+
s.enemyInstance = __instance;
1819
}
1920
}
2021
}

Patches/QuickMenuManager_Patches.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ private static void Postfix(QuickMenuManager __instance)
1212
{
1313
GameObject obj = new("SpectateEnemiesObject");
1414
SpectateEnemies spec = obj.AddComponent<SpectateEnemies>();
15-
spec.PopulateSettings(__instance.testAllEnemiesLevel);
15+
spec.PopulateSettings();
1616
}
1717
}
1818
}

Spectatable.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using UnityEngine;
1+
using System;
2+
using UnityEngine;
23

34
namespace SpectateEnemy
45
{
@@ -7,6 +8,7 @@ internal class Spectatable : MonoBehaviour
78
public SpectatableType type = SpectatableType.Enemy;
89
public string enemyName = "Enemy";
910
public string maskedName = string.Empty;
11+
public EnemyAI enemyInstance = null;
1012
}
1113

1214
internal enum SpectatableType

SpectateEnemies.cs

Lines changed: 65 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ internal class SpectateEnemies : MonoBehaviour
1717
private static readonly Dictionary<string, bool> settings = [];
1818

1919
private bool WindowOpen = false;
20-
private Rect window = new(10, 10, 500, 300);
20+
private Rect window = new(10, 10, 500, 400);
2121

2222
public int SpectatedEnemyIndex = -1;
2323
public bool SpectatingEnemies = false;
2424
public Spectatable[] SpectatorList;
25+
public float zoomLevel = 1f;
2526

2627
private void Awake()
2728
{
@@ -39,6 +40,8 @@ private void SetupKeybinds()
3940
Plugin.Inputs.SwapKey.performed += OnSwapKeyPressed;
4041
Plugin.Inputs.MenuKey.performed += OnMenuKeyPressed;
4142
Plugin.Inputs.FlashlightKey.performed += OnFlashlightKeyPressed;
43+
Plugin.Inputs.ZoomOutKey.performed += OnZoomOutPressed;
44+
Plugin.Inputs.ZoomInKey.performed += OnZoomInPressed;
4245
}
4346

4447
private void OnSwapKeyPressed(InputAction.CallbackContext context)
@@ -85,6 +88,24 @@ private void OnFlashlightKeyPressed(InputAction.CallbackContext context)
8588
}
8689
}
8790

91+
private void OnZoomOutPressed(InputAction.CallbackContext context)
92+
{
93+
if (!context.performed) return;
94+
if (!SpectatingEnemies) return;
95+
zoomLevel += 0.1f;
96+
if (zoomLevel > 10f)
97+
zoomLevel = 10f;
98+
}
99+
100+
private void OnZoomInPressed(InputAction.CallbackContext context)
101+
{
102+
if (!context.performed) return;
103+
if (!SpectatingEnemies) return;
104+
zoomLevel -= 0.1f;
105+
if (zoomLevel < 1f)
106+
zoomLevel = 1f;
107+
}
108+
88109
private void LateUpdate()
89110
{
90111
if (SpectatingEnemies)
@@ -94,17 +115,20 @@ private void LateUpdate()
94115
SpectatingEnemies = false;
95116
return;
96117
}
97-
if (SpectatedEnemyIndex >= SpectatorList.Length)
98-
{
99-
GetNextValidSpectatable();
100-
return;
101-
}
102118
Spectatable currentEnemy = SpectatorList.ElementAtOrDefault(SpectatedEnemyIndex);
103119
if (currentEnemy == null)
104120
{
105121
GetNextValidSpectatable();
106122
return;
107123
}
124+
if (currentEnemy.type == SpectatableType.Enemy || currentEnemy.type == SpectatableType.Masked)
125+
{
126+
if (currentEnemy.enemyInstance != null && currentEnemy.enemyInstance.isEnemyDead)
127+
{
128+
GetNextValidSpectatable();
129+
return;
130+
}
131+
}
108132
Vector3? position = GetSpectatePosition(currentEnemy);
109133
if (!position.HasValue)
110134
{
@@ -115,20 +139,20 @@ private void LateUpdate()
115139
{
116140
TryFixName(ref currentEnemy);
117141
}
118-
HUDManager.Instance.localPlayer.spectateCameraPivot.position = position.Value + GetZoomDistance(currentEnemy);
142+
GameNetworkManager.Instance.localPlayerController.spectateCameraPivot.position = position.Value + Vector3.up * zoomLevel;
119143
if (currentEnemy.type == SpectatableType.Masked && currentEnemy.maskedName != string.Empty)
120-
HUDManager.Instance.spectatingPlayerText.text = "(Spectating: " + currentEnemy.maskedName + ")";
144+
HUDManager.Instance.spectatingPlayerText.text = string.Format("(Spectating: {0}) [{1:F1}x]", currentEnemy.maskedName, zoomLevel);
121145
else
122-
HUDManager.Instance.spectatingPlayerText.text = "(Spectating: " + currentEnemy.enemyName + ")";
123-
Plugin.raycastSpectate.Invoke(HUDManager.Instance.localPlayer, []);
146+
HUDManager.Instance.spectatingPlayerText.text = string.Format("(Spectating: {0}) [{1:F1}x]", currentEnemy.enemyName, zoomLevel);
147+
Plugin.raycastSpectate.Invoke(GameNetworkManager.Instance.localPlayerController, []);
124148
}
125149
}
126150

127151
private Vector3? GetSpectatePosition(Spectatable obj)
128152
{
129153
if (obj.type == SpectatableType.Enemy || obj.type == SpectatableType.Masked)
130154
{
131-
EnemyAI enemy = obj.GetComponent<EnemyAI>();
155+
EnemyAI enemy = obj.enemyInstance;
132156
if (enemy != null)
133157
{
134158
return enemy.eye == null ? enemy.transform.position : enemy.eye.position;
@@ -153,16 +177,6 @@ private void LateUpdate()
153177
return null;
154178
}
155179

156-
private Vector3 GetZoomDistance(Spectatable obj)
157-
{
158-
if (obj.enemyName == "ForestGiant")
159-
return Vector3.up * 3;
160-
if (obj.enemyName == "MouthDog" || obj.enemyName == "Jester")
161-
return Vector3.up * 2;
162-
else
163-
return Vector3.up;
164-
}
165-
166180
private void TryFixName(ref Spectatable obj)
167181
{
168182
if (obj.gameObject.TryGetComponent(out MaskedPlayerEnemy masked))
@@ -195,7 +209,7 @@ public void ToggleSpectatingMode(PlayerControllerB __instance)
195209
SpectatingEnemies = !SpectatingEnemies;
196210
if (SpectatingEnemies)
197211
{
198-
SpectatorList = FindObjectsByType<Spectatable>(FindObjectsSortMode.None);
212+
SpectatorList = FindObjectsByType<Spectatable>(FindObjectsSortMode.None).Where(x => settings[x.enemyName]).ToArray();
199213
if (SpectatorList.Length == 0)
200214
{
201215
SpectatingEnemies = false;
@@ -210,17 +224,11 @@ public void ToggleSpectatingMode(PlayerControllerB __instance)
210224
}
211225
else
212226
{
213-
List<Spectatable> matches = SpectatorList.Where(x => settings[x.enemyName]).ToList();
214-
if (matches.Count == 0)
215-
{
216-
Plugin.displaySpectatorTip.Invoke(HUDManager.Instance, ["No enemies to spectate"]);
217-
return;
218-
}
219227
float closest = 999999f;
220228
int index = 0;
221-
for (int i = 0; i < matches.Count; i++)
229+
for (int i = 0; i < SpectatorList.Length; i++)
222230
{
223-
float dist = (matches[i].transform.position - __instance.spectatedPlayerScript.transform.position).sqrMagnitude;
231+
float dist = (SpectatorList[i].transform.position - __instance.spectatedPlayerScript.transform.position).sqrMagnitude;
224232
if (dist < closest * closest)
225233
{
226234
closest = dist;
@@ -230,36 +238,25 @@ public void ToggleSpectatingMode(PlayerControllerB __instance)
230238
SpectatedEnemyIndex = index;
231239
}
232240
}
233-
else
234-
{
235-
if (!settings[SpectatorList[SpectatedEnemyIndex].enemyName])
236-
{
237-
GetNextValidSpectatable();
238-
}
239-
}
240241
__instance.spectatedPlayerScript = null;
241242
}
242243
else
243244
{
244245
__instance.spectatedPlayerScript = __instance.playersManager.allPlayerScripts.FirstOrDefault(x => !x.isPlayerDead && x.isPlayerControlled);
245-
HUDManager.Instance.spectatingPlayerText.text = "(Spectating: " + __instance.spectatedPlayerScript.playerUsername + ")";
246+
HUDManager.Instance.spectatingPlayerText.text = $"(Spectating: {__instance.spectatedPlayerScript.playerUsername})";
246247
}
247248
}
248249

249-
public void PopulateSettings(SelectableLevel level)
250+
public void PopulateSettings()
250251
{
251-
foreach (SpawnableEnemyWithRarity t in level.Enemies)
252-
{
253-
settings.TryAdd(t.enemyType.enemyName, true);
254-
}
255-
foreach (SpawnableEnemyWithRarity t in level.OutsideEnemies)
252+
EnemyType[] allEnemies = Resources.FindObjectsOfTypeAll<EnemyType>();
253+
foreach (EnemyType type in allEnemies)
256254
{
257-
settings.TryAdd(t.enemyType.enemyName, true);
258-
}
259-
foreach (SpawnableEnemyWithRarity t in level.DaytimeEnemies)
260-
{
261-
settings.TryAdd(t.enemyType.enemyName, false);
255+
if (type.enemyName == "Red pill" || type.enemyName == "Lasso")
256+
continue;
257+
settings.TryAdd(type.enemyName, !type.isDaytimeEnemy);
262258
}
259+
263260
settings.TryAdd("Landmine", false);
264261
settings.TryAdd("Turret", false);
265262

@@ -278,9 +275,10 @@ public void PopulateSettings(SelectableLevel level)
278275
{
279276
string[] c = s.Split(':');
280277
if (c.Length != 2) continue;
281-
if (settings.ContainsKey(c[0]))
278+
if (settings.ContainsKey(c[0])) {
282279
if (bool.TryParse(c[1], out bool value))
283280
settings[c[0]] = value;
281+
}
284282
}
285283
Debug.LogWarning("[SpectateEnemies]: Config loaded");
286284
}
@@ -292,9 +290,9 @@ public void PopulateSettings(SelectableLevel level)
292290
catch (Exception)
293291
{
294292
Debug.LogWarning("[SpectateEnemies]: Config failed to load, using default values!");
295-
}
293+
}
296294

297-
// AssertSettings();
295+
AssertSettings();
298296
}
299297

300298
private void OnApplicationQuit()
@@ -324,6 +322,7 @@ public bool SpectateNextEnemy()
324322

325323
private void GetNextValidSpectatable()
326324
{
325+
SpectatorList = FindObjectsByType<Spectatable>(FindObjectsSortMode.None).Where(x => settings[x.enemyName]).ToArray();
327326
int enemiesChecked = 0;
328327
int current = SpectatedEnemyIndex;
329328
while (enemiesChecked < SpectatorList.Length)
@@ -333,10 +332,21 @@ private void GetNextValidSpectatable()
333332
{
334333
current = 0;
335334
}
336-
if (settings[SpectatorList[current].enemyName])
335+
Spectatable enemy = SpectatorList.ElementAtOrDefault(current);
336+
if (enemy != null)
337337
{
338-
SpectatedEnemyIndex = current;
339-
return;
338+
if (enemy.type == SpectatableType.Enemy || enemy.type == SpectatableType.Masked)
339+
{
340+
if (enemy.enemyInstance != null && enemy.enemyInstance.isEnemyDead)
341+
{
342+
continue;
343+
}
344+
}
345+
if (settings.ContainsKey(enemy.enemyName))
346+
{
347+
SpectatedEnemyIndex = current;
348+
return;
349+
}
340350
}
341351
enemiesChecked++;
342352
}

SpectateEnemy.csproj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<TargetFramework>netstandard2.1</TargetFramework>
55
<AssemblyName>SpectateEnemy</AssemblyName>
66
<Description>My first plugin</Description>
7-
<Version>2.0.0</Version>
7+
<Version>2.2.0</Version>
88
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
99
<LangVersion>latest</LangVersion>
1010
<RestoreAdditionalProjectSources>
@@ -30,6 +30,9 @@
3030
<Reference Include="Assembly-CSharp">
3131
<HintPath>F:\SteamLibrary\steamapps\common\Lethal Company\Lethal Company_Data\Managed\Assembly-CSharp.dll</HintPath>
3232
</Reference>
33+
<Reference Include="LethalCompanyInputUtils">
34+
<HintPath>F:\SteamLibrary\steamapps\common\Lethal Company\BepInEx\plugins\LethalCompanyInputUtils.dll</HintPath>
35+
</Reference>
3336
<Reference Include="Unity.InputSystem">
3437
<HintPath>F:\SteamLibrary\steamapps\common\Lethal Company\Lethal Company_Data\Managed\Unity.InputSystem.dll</HintPath>
3538
</Reference>

0 commit comments

Comments
 (0)