-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathFarmhandFinder.cs
132 lines (107 loc) · 6.07 KB
/
FarmhandFinder.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
125
126
127
128
129
130
131
132
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewValley;
using Vector2 = Microsoft.Xna.Framework.Vector2;
namespace FarmhandFinder
{
public class FarmhandFinder : Mod
{
internal static FarmhandFinder Instance { get; private set; }
internal static ModConfig Config;
internal static Texture2D BackgroundTexture;
internal static Texture2D ForegroundTexture;
internal static Texture2D ArrowTexture;
internal static readonly Dictionary<long, CompassBubble> CompassBubbles = new();
/*********
** Public methods
*********/
/// <summary>The mod entry point, called after the mod is first loaded.</summary>
/// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper)
{
Instance = this; Config = Helper.ReadConfig<ModConfig>();
LoadTextures(helper);
// If not all options are disabled, we have work to do.
if (!Config.HideCompassBubble || !Config.HideCompassArrow)
helper.Events.Display.RenderedHud += OnRenderedHud;
if (!Config.HideCompassBubble)
HandleCompassBubbles(helper);
}
/*********
** Private methods
*********/
/// <summary>Loads the background, foreground, and arrow textures.</summary>
/// <param name="helper">IModHelper instance for loading data.</param>
private static void LoadTextures(IModHelper helper)
{
BackgroundTexture = helper.ModContent.Load<Texture2D>("assets/bubble.png");
ForegroundTexture = helper.ModContent.Load<Texture2D>("assets/bubble_front.png");
ArrowTexture = helper.ModContent.Load<Texture2D>("assets/arrow.png");
}
/// <summary>Handles the generation and deletion of compass bubble instances.</summary>
/// <param name="helper">IModHelper instance to add event predicates.</param>
private void HandleCompassBubbles(IModHelper helper)
{
helper.Events.GameLoop.OneSecondUpdateTicked += (_, _) =>
{
// Generate a corresponding compass bubble and add to dictionary if one has not been created yet.
foreach (var peer in Helper.Multiplayer.GetConnectedPlayers())
{
var farmer = Game1.getFarmer(peer.PlayerID);
if (CompassBubbles.ContainsKey(farmer.UniqueMultiplayerID))
continue;
CompassBubbles.Add(farmer.UniqueMultiplayerID, new CompassBubble(farmer, helper));
}
};
// If a peer disconnects from the world, remove their respective dictionary entry.
// TODO: This doesn't seem to work properly at the moment?
helper.Events.Multiplayer.PeerDisconnected += (_, e) => CompassBubbles.Remove(e.Peer.PlayerID);
// If the game returns to the title screen, clear the compass bubble dictionary.
helper.Events.GameLoop.ReturnedToTitle += (_, _) => CompassBubbles.Clear();
}
/// <summary>
/// Raised after drawing the HUD (item toolbar, clock, etc) to the sprite batch, but before it's rendered to
/// the screen.
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
[SuppressMessage("ReSharper", "PossibleInvalidOperationException")]
private void OnRenderedHud(object sender, RenderedHudEventArgs e)
{
// Render nothing if no remote players are present or if the player is in a cutscene.
if (!Context.HasRemotePlayers || Game1.player.hidden.Value) return;
foreach (var peer in Helper.Multiplayer.GetConnectedPlayers())
{
var farmer = Game1.getFarmer(peer.PlayerID);
var sameLocation = farmer.currentLocation != null &&
farmer.currentLocation.Equals(Game1.player.currentLocation);
// TODO: More split screen checks are needed--specifically having the peer bubble show up in both
// TODO: screens and displayed on the correct location for each screen.
// Render nothing if the peer is not in the same location or is hidden (cutscene).
if (peer.IsSplitScreen || !sameLocation || farmer.hidden.Value) continue;
// Also render nothing if an intersection between the player, peer, and viewport does not exist.
if (!Utility.HandleIntersectionCalculations(farmer, out var compassPos, out var arrowAngle)) continue;
// Only draw the compass bubble if one has already been generated.
if (!Config.HideCompassBubble && CompassBubbles.ContainsKey(farmer.UniqueMultiplayerID))
{
var alpha = Utility.UiElementsIntersect(compassPos) ? 0.5f : 1f;
// Drawing the compass bubble at the normalized position.
CompassBubbles[farmer.UniqueMultiplayerID].Draw(e.SpriteBatch, compassPos, 1, alpha);
}
if (!Config.HideCompassArrow)
{
// Drawing the compass arrow pivoted at an offset in the +X direction about the intersection point
// and rotated in the direction of the intersection point to center of the peer.
var arrowPos = compassPos + new Vector2((float)Math.Cos(arrowAngle), (float)Math.Sin(arrowAngle))
* (36 * Game1.options.uiScale);
Utility.DrawUiSprite(e.SpriteBatch, ArrowTexture, arrowPos, 0.75f, arrowAngle + MathHelper.PiOver2);
}
}
}
}
}