diff --git a/README.md b/README.md
index 33688a4..f04f525 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,4 @@
# Titanfall 2 Discord Rich Presence
-# Titanfall 2 Discord Rich Presence
This project aims to allow for Discord's Rich Presence feature to work with Titanfall 2. This is accomplished in a very hacky way. Specifically, known memory addresses are directly read from by this program. Yes, you read that right. I had to mess around in Cheat Engine to find the right memory addresses to read various values from. It's incredibly hacky but at least the code is relatively elegant if I say so myself.
@@ -52,7 +51,7 @@ Currently this is officially supported only on Windows. However, I've been infor
4. Have fun!
## Supported Game Modes
-While this project _is_ stable, it isn't **_nearly_** complete yet. Multiplayer game data isn't easy to track down in memory. For this reason, this project has a limited set of game modes that it supports. You can still play the unsupported game modes. It won't cause any problems. However, only the supported game modes will show your score and other info on Discord. For the list of supported games, see [#45](https://github.com/IncPlusPlus/titanfall2-rp/issues/45).
+While this project _is_ stable, it isn't quite complete yet. Multiplayer game data isn't easy to track down in memory. For this reason, this project has a limited amount of data it can retrieve about a given game mode. This is really more of a side note and doesn't affect everyday use. For the list of supported game modes, see [#45](https://github.com/IncPlusPlus/titanfall2-rp/issues/45).
## Known Issues
See [the bugs area](https://github.com/IncPlusPlus/titanfall2-rp/issues?q=is%3Aopen+is%3Aissue+label%3Abug) for all the known issues at this time.
@@ -71,9 +70,13 @@ This section is just for developers. If you only want to _use_ this program, see
To build this project, run `dotnet publish`.
-To run this project, run the exe file from `[PROJECT_ROOT_DIR]\titanfall2-rp\bin\Debug\net5.0\win10-x64\publish` (where PROJECT_ROOT_DIR is the directory where you cloned this project) which was created when you ran `dotnet publish`.
+To only run this project, run the exe file from `[PROJECT_ROOT_DIR]\Windows\bin\Debug\net5.0-windows\win10-x64\publish` (where PROJECT_ROOT_DIR is the directory where you cloned this project) which was created when you ran `dotnet publish`.
-If you change anything in the ZipExtractor project, the changes will only be reflected after running `dotnet publish ZipExtractor` because of where the main `titanfall2-rip` project expects it to be (for use as an embedded resource).
+If you change anything in the ZipExtractor project, the changes will only be reflected after running `dotnet publish ZipExtractor` because of where the main `titanfall2-rp` project expects it to be (for use as an embedded resource).
## Building on Linux
-Building on Linux works the same way as on Windows. However, the exe you create will have the auto-updating feature disabled on Windows.
+Building on Linux allows you to build only the Wine project. This is because you can't build WPF and WinForms projects on .NET 5.0 on Linux (as far as I'm aware).
+
+To create a fully-fledged executable for running in Wine, run `dotnet publish ZipExtractor && dotnet publish Wine`. Your exe will be located at `[PROJECT_ROOT_DIR]\Wine\bin\Debug\net5.0\win10-x64\publish\titanfall2-rp-Wine.exe`.
+
+If you are only trying to _run_ the Wine project (i.e. inside of your IDE), you need to run `dotnet publish ZipExtractor; dotnet build Wine`.
diff --git a/Windows/App.xaml.cs b/Windows/App.xaml.cs
index 363d33f..ad6e3a7 100644
--- a/Windows/App.xaml.cs
+++ b/Windows/App.xaml.cs
@@ -1,8 +1,10 @@
using System;
using System.ComponentModel;
+using System.Reflection;
using System.Windows;
using System.Windows.Forms;
using Common;
+using log4net;
using titanfall2_rp.updater;
using Xamarin.Forms;
using Xamarin.Forms.Platform.WPF;
@@ -16,15 +18,35 @@ namespace titanfall2_rp.Windows
///
public partial class App
{
+ private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod()!.DeclaringType);
private NotifyIcon? _notifyIcon;
private RichPresenceManager? _program;
private bool _isExit;
protected override void OnStartup(StartupEventArgs e)
{
- Forms.Init();
+ _program = new RichPresenceManager();
+ _program.Begin();
- base.OnStartup(e);
+ try
+ {
+ Forms.Init();
+ }
+ catch (Exception exception)
+ {
+ Log.Fatal("Failed at Forms.Init()", exception);
+ throw;
+ }
+
+ try
+ {
+ base.OnStartup(e);
+ }
+ catch (Exception exception)
+ {
+ Log.Fatal("Failed at base.OnStartup(e)", exception);
+ throw;
+ }
_notifyIcon = new NotifyIcon();
_notifyIcon.MouseDoubleClick += NotifyIconOnDoubleClick;
@@ -33,10 +55,15 @@ protected override void OnStartup(StartupEventArgs e)
_notifyIcon.Visible = true;
_notifyIcon.Text = "Titanfall 2 Discord Rich Presence";
- CreateContextMenu();
-
- _program = new RichPresenceManager();
- _program.Begin();
+ try
+ {
+ CreateContextMenu();
+ }
+ catch (Exception exception)
+ {
+ Log.Fatal("Failed at CreateContextMenu()", exception);
+ throw;
+ }
}
private void NotifyIconOnDoubleClick(object? sender, MouseEventArgs e)
diff --git a/Windows/Windows.csproj b/Windows/Windows.csproj
index b17fd86..da361ab 100644
--- a/Windows/Windows.csproj
+++ b/Windows/Windows.csproj
@@ -15,6 +15,7 @@
true
enable
+ true
@@ -61,6 +62,12 @@
+
+
+
+
+
+
True
diff --git a/titanfall2-rp/GameDetailsProvider.cs b/titanfall2-rp/GameDetailsProvider.cs
index 8ac72a9..46a5b79 100644
--- a/titanfall2-rp/GameDetailsProvider.cs
+++ b/titanfall2-rp/GameDetailsProvider.cs
@@ -20,9 +20,9 @@ public static class GameDetailsProvider
public static (string, string, Timestamps?, Assets? assets) GetMultiplayerDetails(Titanfall2Api tf2Api, DateTime gameOpenTimestamp)
{
- var currentGameMode = tf2Api.GetGameMode();
+ var mpStats = tf2Api.GetMultiPlayerGameStats();
string gameDetails = tf2Api.GetGameMode().ToFriendlyString();
- string gameState = "";
+ string gameState = $"{mpStats.GetTeam1Score()}:{mpStats.GetTeam2Score()}";
var timestamps = new Timestamps(gameOpenTimestamp);
var playerInTitan = tf2Api.IsPlayerInTitan();
var assets = new Assets
@@ -32,54 +32,6 @@ public static (string, string, Timestamps?, Assets? assets) GetMultiplayerDetail
SmallImageKey = playerInTitan ? tf2Api.GetTitan().GetAssetName() : tf2Api.GetMultiPlayerGameStats().GetCurrentFaction().GetAssetName(),
SmallImageText = playerInTitan ? tf2Api.GetTitan().ToFriendlyString() : tf2Api.GetMultiPlayerGameStats().GetCurrentFaction().ToFriendlyString(),
};
- switch (currentGameMode)
- {
- case GameMode.coliseum:
- break;
- case GameMode.aitdm:
- var attritionStats = tf2Api.GetMultiPlayerGameStats().GetAttrition();
- gameState = attritionStats.GetTeam1Score() + ":" + attritionStats.GetTeam2Score();
- break;
- case GameMode.tdm:
- break;
- case GameMode.cp:
- var ampedHardpointStats = tf2Api.GetMultiPlayerGameStats().GetAmpedHardpoint();
- gameState = ampedHardpointStats.GetTeam1Score() + ":" + ampedHardpointStats.GetTeam2Score();
- break;
- case GameMode.at:
- var bountyHuntStats = tf2Api.GetMultiPlayerGameStats().GetBountyHunt();
- gameState = bountyHuntStats.GetTeam1Score() + ":" + bountyHuntStats.GetTeam2Score();
- break;
- case GameMode.ctf:
- var ctfStats = tf2Api.GetMultiPlayerGameStats().GetCaptureTheFlag();
- gameState = ctfStats.GetTeam1Score() + ":" + ctfStats.GetTeam2Score();
- break;
- case GameMode.lts:
- break;
- case GameMode.ps:
- break;
- case GameMode.speedball:
- break;
- case GameMode.mfd:
- break;
- case GameMode.ttdm:
- var titanBrawlStats = tf2Api.GetMultiPlayerGameStats().GetTitanBrawl();
- gameState = titanBrawlStats.GetTeam1Score() + ":" + titanBrawlStats.GetTeam2Score();
- break;
- case GameMode.fd_easy:
- break;
- case GameMode.fd_normal:
- break;
- case GameMode.fd_hard:
- break;
- case GameMode.fd_insane:
- break;
- case GameMode.solo:
- break;
- default:
- throw new ArgumentException("Unknown game mode '" + currentGameMode + "'.");
- }
-
return (gameDetails, gameState, timestamps, assets);
}
diff --git a/titanfall2-rp/MpGameStats/AmpedHardpoint.cs b/titanfall2-rp/MpGameStats/AmpedHardpoint.cs
new file mode 100644
index 0000000..79df380
--- /dev/null
+++ b/titanfall2-rp/MpGameStats/AmpedHardpoint.cs
@@ -0,0 +1,38 @@
+using System;
+using Process.NET;
+
+namespace titanfall2_rp.MpGameStats
+{
+ public class AmpedHardpoint : MpStats
+ {
+ public AmpedHardpoint(Titanfall2Api tf2Api, ProcessSharp processSharp) : base(tf2Api, processSharp)
+ { }
+
+ ///
+ /// Get the assault score of the current user.
+ ///
+ /// the user's assault score
+ public int GetMyAssaultScore()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the defense score of the current user.
+ ///
+ /// the user's defense score
+ public int GetMyDefenseScore()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the kill count of the current user.
+ ///
+ /// the user's kill count
+ public int GetMyKills()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+ }
+}
\ No newline at end of file
diff --git a/titanfall2-rp/MpGameStats/Attrition.cs b/titanfall2-rp/MpGameStats/Attrition.cs
new file mode 100644
index 0000000..15015f1
--- /dev/null
+++ b/titanfall2-rp/MpGameStats/Attrition.cs
@@ -0,0 +1,47 @@
+using System;
+using Process.NET;
+
+namespace titanfall2_rp.MpGameStats
+{
+ public class Attrition : MpStats
+ {
+ public Attrition(Titanfall2Api tf2Api, ProcessSharp processSharp) : base(tf2Api, processSharp)
+ { }
+
+ ///
+ /// Get the score of the current user.
+ ///
+ /// the user's score
+ public int GetMyScore()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the pilot kills of the current user.
+ ///
+ /// the number of pilots the user has killed
+ public int GetMyPilotKills()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the titan kills of the current user.
+ ///
+ /// the number of titans the user has killed
+ public int GetMyTitanKills()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the minion kills of the current user.
+ ///
+ /// the number of minions the user has killed
+ public int GetMyMinionKills()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+ }
+}
\ No newline at end of file
diff --git a/titanfall2-rp/MpGameStats/BountyHunt.cs b/titanfall2-rp/MpGameStats/BountyHunt.cs
new file mode 100644
index 0000000..3534b9e
--- /dev/null
+++ b/titanfall2-rp/MpGameStats/BountyHunt.cs
@@ -0,0 +1,38 @@
+using System;
+using Process.NET;
+
+namespace titanfall2_rp.MpGameStats
+{
+ public class BountyHunt : MpStats
+ {
+ public BountyHunt(Titanfall2Api tf2Api, ProcessSharp processSharp) : base(tf2Api, processSharp)
+ { }
+
+ ///
+ /// Get the score of the current user.
+ ///
+ /// the user's score
+ public int GetMyScore()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the bonus of the current user.
+ ///
+ /// the user's bonus
+ public int GetMyBonus()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the kills of the current user.
+ ///
+ /// the user's kills
+ public int GetMyKills()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+ }
+}
\ No newline at end of file
diff --git a/titanfall2-rp/MpGameStats/CaptureTheFlag.cs b/titanfall2-rp/MpGameStats/CaptureTheFlag.cs
new file mode 100644
index 0000000..ad8e1dd
--- /dev/null
+++ b/titanfall2-rp/MpGameStats/CaptureTheFlag.cs
@@ -0,0 +1,56 @@
+using System;
+using Process.NET;
+
+namespace titanfall2_rp.MpGameStats
+{
+ public class CaptureTheFlag : MpStats
+ {
+ public CaptureTheFlag(Titanfall2Api tf2Api, ProcessSharp processSharp) : base(tf2Api, processSharp)
+ { }
+
+ ///
+ /// Get whether the game has passed halftime
+ ///
+ /// true if in the 2nd half, false if halftime hasn't happened yet
+ public bool IsInSecondHalf()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the amount of time in seconds remaining in the current half
+ ///
+ /// the time in seconds remaining in the current half
+ public int GetTimeRemainingInHalf()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the number of captures the user has achieved
+ ///
+ /// the number of captures the user has achieved
+ public int GetMyCaptures()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the number of times the user returned their team's flag
+ ///
+ /// the number of times the user returned their team's flag
+ public int GetMyReturns()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the number of kills the user has made
+ ///
+ /// the number of players the user has killed
+ public int GetMyKills()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+ }
+}
\ No newline at end of file
diff --git a/titanfall2-rp/MpGameStats/Coliseum.cs b/titanfall2-rp/MpGameStats/Coliseum.cs
new file mode 100644
index 0000000..aff88ab
--- /dev/null
+++ b/titanfall2-rp/MpGameStats/Coliseum.cs
@@ -0,0 +1,10 @@
+using Process.NET;
+
+namespace titanfall2_rp.MpGameStats
+{
+ public class Coliseum : MpStats
+ {
+ public Coliseum(Titanfall2Api tf2Api, ProcessSharp processSharp) : base(tf2Api, processSharp)
+ { }
+ }
+}
\ No newline at end of file
diff --git a/titanfall2-rp/MpGameStats/FrontierDefense.cs b/titanfall2-rp/MpGameStats/FrontierDefense.cs
new file mode 100644
index 0000000..17f6e0f
--- /dev/null
+++ b/titanfall2-rp/MpGameStats/FrontierDefense.cs
@@ -0,0 +1,10 @@
+using Process.NET;
+
+namespace titanfall2_rp.MpGameStats
+{
+ public class FrontierDefense : MpStats
+ {
+ public FrontierDefense(Titanfall2Api tf2Api, ProcessSharp processSharp) : base(tf2Api, processSharp)
+ { }
+ }
+}
\ No newline at end of file
diff --git a/titanfall2-rp/MpGameStats/LastTitanStanding.cs b/titanfall2-rp/MpGameStats/LastTitanStanding.cs
new file mode 100644
index 0000000..e21c0e4
--- /dev/null
+++ b/titanfall2-rp/MpGameStats/LastTitanStanding.cs
@@ -0,0 +1,42 @@
+using System;
+using Process.NET;
+
+namespace titanfall2_rp.MpGameStats
+{
+ public class LastTitanStanding : MpStats
+ {
+ public LastTitanStanding(Titanfall2Api tf2Api, ProcessSharp processSharp) : base(tf2Api, processSharp)
+ {
+ }
+
+ /// the current round number
+ public int GetRoundNumber()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ /// the total number of rounds (to give the current round number some context)
+ public int GetTotalRounds()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ /// the time remaining in the current round (measured in seconds)
+ public int GetTimeRemainingInRoundInSeconds()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ /// the number of titans the user has killed
+ public int GetMyTitanKills()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ /// the amount of damage the user has done to other titans
+ public int GetMyTitanDamage()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+ }
+}
\ No newline at end of file
diff --git a/titanfall2-rp/MpGameStats/LiveFire.cs b/titanfall2-rp/MpGameStats/LiveFire.cs
new file mode 100644
index 0000000..9ba7d2d
--- /dev/null
+++ b/titanfall2-rp/MpGameStats/LiveFire.cs
@@ -0,0 +1,39 @@
+using System;
+using Process.NET;
+
+namespace titanfall2_rp.MpGameStats
+{
+ public class LiveFire : MpStats
+ {
+ public LiveFire(Titanfall2Api tf2Api, ProcessSharp processSharp) : base(tf2Api, processSharp)
+ {
+ }
+
+ ///
+ /// Get the number of players the user has killed
+ ///
+ /// the number of players the user has killed
+ public int GetMyKills()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the number of flags the user has secured
+ ///
+ /// the number of flags the user has secured
+ public int GetMyFlags()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the number of times the user has died
+ ///
+ /// the number of times the user has died
+ public int GetMyDeaths()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+ }
+}
\ No newline at end of file
diff --git a/titanfall2-rp/MpGameStats/MarkedForDeath.cs b/titanfall2-rp/MpGameStats/MarkedForDeath.cs
new file mode 100644
index 0000000..b28013b
--- /dev/null
+++ b/titanfall2-rp/MpGameStats/MarkedForDeath.cs
@@ -0,0 +1,10 @@
+using Process.NET;
+
+namespace titanfall2_rp.MpGameStats
+{
+ public class MarkedForDeath : MpStats
+ {
+ public MarkedForDeath(Titanfall2Api tf2Api, ProcessSharp processSharp) : base(tf2Api, processSharp)
+ { }
+ }
+}
\ No newline at end of file
diff --git a/titanfall2-rp/MpGameStats/PilotsVersusPilots.cs b/titanfall2-rp/MpGameStats/PilotsVersusPilots.cs
new file mode 100644
index 0000000..c8420da
--- /dev/null
+++ b/titanfall2-rp/MpGameStats/PilotsVersusPilots.cs
@@ -0,0 +1,39 @@
+using System;
+using Process.NET;
+
+namespace titanfall2_rp.MpGameStats
+{
+ public class PilotsVersusPilots : MpStats
+ {
+ public PilotsVersusPilots(Titanfall2Api tf2Api, ProcessSharp processSharp) : base(tf2Api, processSharp)
+ {
+ }
+
+ ///
+ /// Get the number of players the user has killed
+ ///
+ /// the number of players the user has killed
+ public int GetMyKills()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the number of assists the user has made
+ ///
+ /// the number of assists the user has made
+ public int GetMyAssists()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the number of times the user has died
+ ///
+ /// the number of times the user has died
+ public int GetMyDeaths()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+ }
+}
\ No newline at end of file
diff --git a/titanfall2-rp/MpGameStats/Skirmish.cs b/titanfall2-rp/MpGameStats/Skirmish.cs
new file mode 100644
index 0000000..58897f2
--- /dev/null
+++ b/titanfall2-rp/MpGameStats/Skirmish.cs
@@ -0,0 +1,10 @@
+using Process.NET;
+
+namespace titanfall2_rp.MpGameStats
+{
+ public class Skirmish : MpStats
+ {
+ public Skirmish(Titanfall2Api tf2Api, ProcessSharp processSharp) : base(tf2Api, processSharp)
+ { }
+ }
+}
\ No newline at end of file
diff --git a/titanfall2-rp/MpGameStats/TitanBrawl.cs b/titanfall2-rp/MpGameStats/TitanBrawl.cs
new file mode 100644
index 0000000..2bdd541
--- /dev/null
+++ b/titanfall2-rp/MpGameStats/TitanBrawl.cs
@@ -0,0 +1,55 @@
+using System;
+using Process.NET;
+
+namespace titanfall2_rp.MpGameStats
+{
+ public class TitanBrawl : MpStats
+ {
+ public TitanBrawl(Titanfall2Api tf2Api, ProcessSharp processSharp) : base(tf2Api, processSharp)
+ { }
+
+ ///
+ /// Gets the round number (out of 5) of the current match.
+ ///
+ /// Candidates for this value are the following offsets:
+ /// client.dll+FB83BC
+ /// client.dll+FB83E4
+ /// client.dll+FB840C
+ ///
+ /// If one of these is returning an erroneous result, the offset used by this method might need
+ /// to be replaced with another one of these offsets.
+ ///
+ /// the current round number of the match
+ public int GetRoundNumber()
+ {
+ return Sharp.Memory.Read(Tf2Api.ClientDllBaseAddress + 0xFB83BC);
+ }
+
+ ///
+ /// Get the kills of the current user.
+ ///
+ /// the user's number of kills
+ public int GetMyKills()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the deaths of the current user.
+ ///
+ /// the user's number of deaths
+ public int GetMyDeaths()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+
+ ///
+ /// Get the titan damage of the current user.
+ ///
+ /// the amount of titan damage the current user has inflicted
+ public int GetMyTitanDamage()
+ {
+ throw new NotImplementedException(HelpMeBruh);
+ }
+ }
+}
\ No newline at end of file
diff --git a/titanfall2-rp/MpStats.cs b/titanfall2-rp/MpStats.cs
new file mode 100644
index 0000000..f9bd09f
--- /dev/null
+++ b/titanfall2-rp/MpStats.cs
@@ -0,0 +1,90 @@
+using System;
+using Process.NET;
+using titanfall2_rp.enums;
+using titanfall2_rp.MpGameStats;
+
+namespace titanfall2_rp
+{
+ ///
+ /// This class serves as the base class for all the multiplayer game modes.
+ ///
+ public abstract class MpStats
+ {
+ private protected const string HelpMeBruh =
+ "Getting this value is not supported. " +
+ "If you want this to be possible, you'll need to contribute this yourself or tell me how the heck to get it.";
+ private protected readonly Titanfall2Api Tf2Api;
+ private protected readonly ProcessSharp Sharp;
+
+ protected MpStats(Titanfall2Api titanfall2Api, ProcessSharp processSharp)
+ {
+ Tf2Api = titanfall2Api;
+ Sharp = processSharp;
+ }
+
+ public Faction GetCurrentFaction()
+ {
+ return FactionMethods.GetFaction(
+ Sharp.Memory.Read(Tf2Api.EngineDllBaseAddress + 0x7A7383, 1)[0]);
+ }
+
+ ///
+ /// Get the score of team 1. Whether this is your team or the enemy's doesn't always stay the same.
+ /// I'm not sure why. This is something that I need some help figuring out.
+ ///
+ /// the score of team 1, -1 if not applicable to this game mode
+ public virtual int GetTeam1Score()
+ {
+ return Sharp.Memory.Read(Tf2Api.EngineDllBaseAddress + 0x1121814C);
+ }
+
+ ///
+ /// Get the score of team 2. Whether this is your team or the enemy's doesn't always stay the same.
+ /// I'm not sure why. This is something that I need some help figuring out.
+ ///
+ /// the score of team 2, -1 if not applicable to this game mode
+ public virtual int GetTeam2Score()
+ {
+ return Sharp.Memory.Read(Tf2Api.EngineDllBaseAddress + 0x11218CA0);
+ }
+
+ ///
+ /// Get the number of points one team needs to win the match
+ ///
+ /// the number of points one team needs to win the match, -1 if not applicable (like in frontier defense)
+ // public abstract int MaxScore();
+
+ ///
+ /// Get an instance of the abstract MpStats class.
+ ///
+ /// a valid TF|2 API instance
+ /// a valid ProcessSharp that points to the current TF|2 process
+ ///
+ /// if the specified game mode isn't valid here
+ /// if you screw up big time
+ public static MpStats Of(Titanfall2Api titanfall2Api, ProcessSharp sharp)
+ {
+ return titanfall2Api.GetGameMode() switch
+ {
+ GameMode.coliseum => new Coliseum(titanfall2Api, sharp),
+ GameMode.aitdm => new Attrition(titanfall2Api, sharp),
+ GameMode.tdm => new Skirmish(titanfall2Api, sharp),
+ GameMode.cp => new AmpedHardpoint(titanfall2Api, sharp),
+ GameMode.at => new BountyHunt(titanfall2Api, sharp),
+ GameMode.ctf => new CaptureTheFlag(titanfall2Api, sharp),
+ GameMode.lts => new LastTitanStanding(titanfall2Api, sharp),
+ GameMode.ps => new PilotsVersusPilots(titanfall2Api, sharp),
+ GameMode.speedball => new LiveFire(titanfall2Api, sharp),
+ GameMode.mfd => new MarkedForDeath(titanfall2Api, sharp),
+ GameMode.ttdm => new TitanBrawl(titanfall2Api, sharp),
+ GameMode.fd_easy => new FrontierDefense(titanfall2Api, sharp),
+ GameMode.fd_normal => new FrontierDefense(titanfall2Api, sharp),
+ GameMode.fd_hard => new FrontierDefense(titanfall2Api, sharp),
+ GameMode.fd_master => new FrontierDefense(titanfall2Api, sharp),
+ GameMode.fd_insane => new FrontierDefense(titanfall2Api, sharp),
+ GameMode.solo => throw new ArgumentException("Tried to get multiplayer details for the campaign"),
+ _ => throw new ArgumentOutOfRangeException($"Unknown game mode '{titanfall2Api.GetGameMode()}'.")
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/titanfall2-rp/Titanfall2API.cs b/titanfall2-rp/Titanfall2API.cs
index 1ae5357..446c024 100644
--- a/titanfall2-rp/Titanfall2API.cs
+++ b/titanfall2-rp/Titanfall2API.cs
@@ -11,26 +11,25 @@ namespace titanfall2_rp
{
// This is probably not thread safe. Multiple threads could potentially attempt to initialize this class.
// However, this is unlikely given that the presence update time is multiple seconds.
- public partial class Titanfall2Api
+ public class Titanfall2Api
{
private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod()!.DeclaringType);
private static readonly Regex GameModeAndMapRegex = new Regex("Playing (.*) on (.*)");
private ProcessSharp? _sharp;
- private IntPtr _engineDllBaseAddress;
- private IntPtr _clientDllBaseAddress;
- private IntPtr _serverDllBaseAddress;
- private MpGameStats? _multiplayerGameStats;
+ public IntPtr EngineDllBaseAddress { get; private set; }
+ public IntPtr ClientDllBaseAddress { get; private set; }
+ public IntPtr ServerDllBaseAddress { get; private set; }
- public MpGameStats GetMultiPlayerGameStats()
+ public MpStats GetMultiPlayerGameStats()
{
_ensureInit();
- return this._multiplayerGameStats!;
+ return MpStats.Of(this, _sharp!);
}
public int GetPlayerHealth()
{
_ensureInit();
- return _sharp!.Memory.Read(_engineDllBaseAddress + 0x1122A8DC);
+ return _sharp!.Memory.Read(EngineDllBaseAddress + 0x1122A8DC);
}
///
@@ -87,13 +86,13 @@ public Titan GetTitan()
public int GetPlayerVelocity()
{
_ensureInit();
- return _sharp!.Memory.Read(_clientDllBaseAddress + 0x2A9F704);
+ return _sharp!.Memory.Read(ClientDllBaseAddress + 0x2A9F704);
}
public string GetGameModeAndMapName()
{
_ensureInit();
- return _sharp!.Memory.Read(_engineDllBaseAddress + 0x1397AC46, Encoding.UTF8, 50);
+ return _sharp!.Memory.Read(EngineDllBaseAddress + 0x1397AC46, Encoding.UTF8, 50);
}
public string GetFriendlyMapName()
@@ -114,26 +113,26 @@ public string GetGameModeName()
public GameMode GetGameMode()
{
_ensureInit();
- string gameModeCodeName = _sharp!.Memory.Read(_engineDllBaseAddress + 0x13984088, Encoding.UTF8, 15);
+ string gameModeCodeName = _sharp!.Memory.Read(EngineDllBaseAddress + 0x13984088, Encoding.UTF8, 15);
return GameModeMethods.GetGameMode(gameModeCodeName);
}
public string GetMultiplayerMapName()
{
_ensureInit();
- return _sharp!.Memory.Read(_clientDllBaseAddress + 0x23E0FA0, Encoding.UTF8, 50);
+ return _sharp!.Memory.Read(ClientDllBaseAddress + 0x23E0FA0, Encoding.UTF8, 50);
}
public string GetSinglePlayerMapName()
{
_ensureInit();
- return _sharp!.Memory.Read(_clientDllBaseAddress + 0xB34522, Encoding.UTF8, 50);
+ return _sharp!.Memory.Read(ClientDllBaseAddress + 0xB34522, Encoding.UTF8, 50);
}
public string GetSinglePlayerDifficulty()
{
_ensureInit();
- byte difficulty = _sharp!.Memory.Read(_serverDllBaseAddress + 0xC0963C, 1)[0];
+ byte difficulty = _sharp!.Memory.Read(ServerDllBaseAddress + 0xC0963C, 1)[0];
return difficulty switch
{
0 => "easy",
@@ -161,11 +160,10 @@ private void _ensureInit()
private void _populateFields(ProcessSharp sharp)
{
- this._sharp = sharp;
- this._engineDllBaseAddress = GetModuleBaseAddress(sharp.Native, "engine.dll");
- this._clientDllBaseAddress = GetModuleBaseAddress(sharp.Native, "client.dll");
- this._serverDllBaseAddress = GetModuleBaseAddress(sharp.Native, "server.dll");
- this._multiplayerGameStats = new MpGameStats(this);
+ _sharp = sharp;
+ EngineDllBaseAddress = GetModuleBaseAddress(sharp.Native, "engine.dll");
+ ClientDllBaseAddress = GetModuleBaseAddress(sharp.Native, "client.dll");
+ ServerDllBaseAddress = GetModuleBaseAddress(sharp.Native, "server.dll");
}
}
}
\ No newline at end of file
diff --git a/titanfall2-rp/Titanfall2Api.MpGameStats.cs b/titanfall2-rp/Titanfall2Api.MpGameStats.cs
deleted file mode 100644
index 450d4a2..0000000
--- a/titanfall2-rp/Titanfall2Api.MpGameStats.cs
+++ /dev/null
@@ -1,470 +0,0 @@
-using System;
-using titanfall2_rp.enums;
-
-namespace titanfall2_rp
-{
- public partial class Titanfall2Api
- {
- private const string HelpMeBruh =
- "Getting this value is not supported. " +
- "If you want this to be possible, you'll need to contribute this yourself or tell me how the heck to get it.";
-
- ///
- /// Inside this class are multiplayer subclasses for each game mode (because the stats are different
- /// based on the game type. They'll also be in different memory locations).
- ///
- public class MpGameStats
- {
- private Coliseum _coliseum;
- private Attrition _attrition;
- private Skirmish _skirmish;
- private AmpedHardpoint _ampedHardpoint;
- private BountyHunt _bountyHunt;
- private CaptureTheFlag _captureTheFlag;
- private LastTitanStanding _lastTitanStanding;
- private PilotsVersusPilots _pilotsVersusPilots;
- private LiveFire _liveFire;
- private MarkedForDeath _markedForDeath;
- private TitanBrawl _titanBrawl;
- private FrontierDefense _frontierDefense;
- private readonly Titanfall2Api _tf2Api;
-
- public MpGameStats(Titanfall2Api titanfall2Api)
- {
- _coliseum = new Coliseum(titanfall2Api);
- _attrition = new Attrition(titanfall2Api);
- _skirmish = new Skirmish(titanfall2Api);
- _ampedHardpoint = new AmpedHardpoint(titanfall2Api);
- _bountyHunt = new BountyHunt(titanfall2Api);
- _captureTheFlag = new CaptureTheFlag(titanfall2Api);
- _lastTitanStanding = new LastTitanStanding(titanfall2Api);
- _pilotsVersusPilots = new PilotsVersusPilots(titanfall2Api);
- _liveFire = new LiveFire(titanfall2Api);
- _markedForDeath = new MarkedForDeath(titanfall2Api);
- _titanBrawl = new TitanBrawl(titanfall2Api);
- _frontierDefense = new FrontierDefense(titanfall2Api);
- _tf2Api = titanfall2Api;
- }
-
- public class Coliseum
- {
- private readonly Titanfall2Api _tf2Api;
-
- public Coliseum(Titanfall2Api tf2Api)
- {
- _tf2Api = tf2Api;
- }
- }
-
- public class Attrition
- {
- private readonly Titanfall2Api _tf2Api;
-
- public Attrition(Titanfall2Api tf2Api)
- {
- _tf2Api = tf2Api;
- }
-
- ///
- /// Get the score of team 1. Whether this is your team or the enemy's doesn't always stay the same.
- /// I'm not sure why. This is something that I need some help figuring out.
- ///
- /// the score of team 1
- public int GetTeam1Score()
- {
- return _tf2Api._sharp!.Memory.Read(_tf2Api._engineDllBaseAddress + 0x1121814C);
- }
-
- ///
- /// Get the score of team 2. Whether this is your team or the enemy's doesn't always stay the same.
- /// I'm not sure why. This is something that I need some help figuring out.
- ///
- /// the score of team 2
- public int GetTeam2Score()
- {
- return _tf2Api._sharp!.Memory.Read(_tf2Api._engineDllBaseAddress + 0x11218CA0);
- }
-
- ///
- /// Get the score of the current user.
- ///
- /// the user's score
- public int GetMyScore()
- {
- throw new NotImplementedException(HelpMeBruh);
- }
-
- ///
- /// Get the pilot kills of the current user.
- ///
- /// the number of pilots the user has killed
- public int GetMyPilotKills()
- {
- throw new NotImplementedException(HelpMeBruh);
- }
-
- ///
- /// Get the titan kills of the current user.
- ///
- /// the number of titans the user has killed
- public int GetMyTitanKills()
- {
- throw new NotImplementedException(HelpMeBruh);
- }
-
- ///
- /// Get the minion kills of the current user.
- ///
- /// the number of minions the user has killed
- public int GetMyMinionKills()
- {
- throw new NotImplementedException(HelpMeBruh);
- }
- }
-
- public class Skirmish
- {
- private readonly Titanfall2Api _tf2Api;
-
- public Skirmish(Titanfall2Api tf2Api)
- {
- _tf2Api = tf2Api;
- }
- }
-
- public class AmpedHardpoint
- {
- private readonly Titanfall2Api _tf2Api;
-
- public AmpedHardpoint(Titanfall2Api tf2Api)
- {
- _tf2Api = tf2Api;
- }
-
- ///
- /// Get the score of team 1. Whether this is your team or the enemy's doesn't always stay the same.
- /// I'm not sure why. This is something that I need some help figuring out.
- ///
- /// the score of team 1
- public int GetTeam1Score()
- {
- return _tf2Api._sharp!.Memory.Read(_tf2Api._engineDllBaseAddress + 0x1121814C);
- }
-
- ///
- /// Get the score of team 2. Whether this is your team or the enemy's doesn't always stay the same.
- /// I'm not sure why. This is something that I need some help figuring out.
- ///
- /// the score of team 2
- public int GetTeam2Score()
- {
- return _tf2Api._sharp!.Memory.Read(_tf2Api._engineDllBaseAddress + 0x11218CA0);
- }
-
- ///
- /// Get the assault score of the current user.
- ///
- /// the user's assault score
- public int GetMyAssaultScore()
- {
- throw new NotImplementedException(HelpMeBruh);
- }
-
- ///
- /// Get the defense score of the current user.
- ///
- /// the user's defense score
- public int GetMyDefenseScore()
- {
- throw new NotImplementedException(HelpMeBruh);
- }
-
- ///
- /// Get the kill count of the current user.
- ///
- /// the user's kill count
- public int GetMyKills()
- {
- throw new NotImplementedException(HelpMeBruh);
- }
- }
-
- public class BountyHunt
- {
- private readonly Titanfall2Api _tf2Api;
-
- public BountyHunt(Titanfall2Api tf2Api)
- {
- _tf2Api = tf2Api;
- }
-
- ///
- /// Get the score of team 1. Whether this is your team or the enemy's doesn't always stay the same.
- /// I'm not sure why. This is something that I need some help figuring out.
- ///
- /// the score of team 1
- public int GetTeam1Score()
- {
- return _tf2Api._sharp!.Memory.Read(_tf2Api._engineDllBaseAddress + 0x1121814C);
- }
-
- ///
- /// Get the score of team 2. Whether this is your team or the enemy's doesn't always stay the same.
- /// I'm not sure why. This is something that I need some help figuring out.
- ///
- /// the score of team 2
- public int GetTeam2Score()
- {
- return _tf2Api._sharp!.Memory.Read(_tf2Api._engineDllBaseAddress + 0x11218CA0);
- }
-
- ///
- /// Get the score of the current user.
- ///
- /// the user's score
- public int GetMyScore()
- {
- throw new NotImplementedException(HelpMeBruh);
- }
-
- ///
- /// Get the bonus of the current user.
- ///
- /// the user's bonus
- public int GetMyBonus()
- {
- throw new NotImplementedException(HelpMeBruh);
- }
-
- ///
- /// Get the kills of the current user.
- ///
- /// the user's kills
- public int GetMyKills()
- {
- throw new NotImplementedException(HelpMeBruh);
- }
- }
-
- public class CaptureTheFlag
- {
- private readonly Titanfall2Api _tf2Api;
-
- public CaptureTheFlag(Titanfall2Api tf2Api)
- {
- _tf2Api = tf2Api;
- }
-
- ///
- /// Get the score of team 1. Whether this is your team or the enemy's doesn't always stay the same.
- /// I'm not sure why. This is something that I need some help figuring out.
- ///
- /// the score of team 1
- public int GetTeam1Score()
- {
- return _tf2Api._sharp!.Memory.Read(_tf2Api._engineDllBaseAddress + 0x1121814C);
- }
-
- ///
- /// Get the score of team 2. Whether this is your team or the enemy's doesn't always stay the same.
- /// I'm not sure why. This is something that I need some help figuring out.
- ///
- /// the score of team 2
- public int GetTeam2Score()
- {
- return _tf2Api._sharp!.Memory.Read(_tf2Api._engineDllBaseAddress + 0x11218CA0);
- }
- }
-
- public class LastTitanStanding
- {
- private readonly Titanfall2Api _tf2Api;
-
- public LastTitanStanding(Titanfall2Api tf2Api)
- {
- _tf2Api = tf2Api;
- }
- }
-
- public class PilotsVersusPilots
- {
- private readonly Titanfall2Api _tf2Api;
-
- public PilotsVersusPilots(Titanfall2Api tf2Api)
- {
- _tf2Api = tf2Api;
- }
- }
-
- public class LiveFire
- {
- private readonly Titanfall2Api _tf2Api;
-
- public LiveFire(Titanfall2Api tf2Api)
- {
- _tf2Api = tf2Api;
- }
- }
-
- public class MarkedForDeath
- {
- private readonly Titanfall2Api _tf2Api;
-
- public MarkedForDeath(Titanfall2Api tf2Api)
- {
- _tf2Api = tf2Api;
- }
- }
-
- public class TitanBrawl
- {
- private readonly Titanfall2Api _tf2Api;
-
- public TitanBrawl(Titanfall2Api tf2Api)
- {
- _tf2Api = tf2Api;
- }
-
- ///
- /// Get the score of team 1. Whether this is your team or the enemy's doesn't always stay the same.
- /// I'm not sure why. This is something that I need some help figuring out.
- ///
- /// the score of team 1
- public int GetTeam1Score()
- {
- return _tf2Api._sharp!.Memory.Read(_tf2Api._engineDllBaseAddress + 0x1121814C);
- }
-
- ///
- /// Get the score of team 2. Whether this is your team or the enemy's doesn't always stay the same.
- /// I'm not sure why. This is something that I need some help figuring out.
- ///
- /// the score of team 2
- public int GetTeam2Score()
- {
- return _tf2Api._sharp!.Memory.Read(_tf2Api._engineDllBaseAddress + 0x11218CA0);
- }
-
- ///
- /// Gets the round number (out of 5) of the current match.
- ///
- /// Candidates for this value are the following offsets:
- /// client.dll+FB83BC
- /// client.dll+FB83E4
- /// client.dll+FB840C
- ///
- /// If one of these is returning an erroneous result, the offset used by this method might need
- /// to be replaced with another one of these offsets.
- ///
- /// the current round number of the match
- public int GetRoundNumber()
- {
- return _tf2Api._sharp!.Memory.Read(_tf2Api._clientDllBaseAddress + 0xFB83BC);
- }
-
- ///
- /// Get the kills of the current user.
- ///
- /// the user's number of kills
- public int GetMyKills()
- {
- throw new NotImplementedException(HelpMeBruh);
- }
-
- ///
- /// Get the deaths of the current user.
- ///
- /// the user's number of deaths
- public int GetMyDeaths()
- {
- throw new NotImplementedException(HelpMeBruh);
- }
-
- ///
- /// Get the titan damage of the current user.
- ///
- /// the amount of titan damage the current user has inflicted
- public int GetMyTitanDamage()
- {
- throw new NotImplementedException(HelpMeBruh);
- }
- }
-
- public class FrontierDefense
- {
- private readonly Titanfall2Api _tf2Api;
-
- public FrontierDefense(Titanfall2Api tf2Api)
- {
- _tf2Api = tf2Api;
- }
- }
-
- public Coliseum GetColiseum()
- {
- return _coliseum;
- }
-
- public Attrition GetAttrition()
- {
- return _attrition;
- }
-
- public Skirmish GetSkirmish()
- {
- return _skirmish;
- }
-
- public AmpedHardpoint GetAmpedHardpoint()
- {
- return _ampedHardpoint;
- }
-
- public BountyHunt GetBountyHunt()
- {
- return _bountyHunt;
- }
-
- public CaptureTheFlag GetCaptureTheFlag()
- {
- return _captureTheFlag;
- }
-
- public LastTitanStanding GetLastTitanStanding()
- {
- return _lastTitanStanding;
- }
-
- public PilotsVersusPilots GetPilotsVersusPilots()
- {
- return _pilotsVersusPilots;
- }
-
- public LiveFire GetLiveFire()
- {
- return _liveFire;
- }
-
- public MarkedForDeath GetMarkedForDeath()
- {
- return _markedForDeath;
- }
-
- public TitanBrawl GetTitanBrawl()
- {
- return _titanBrawl;
- }
-
- public FrontierDefense GetFrontierDefense()
- {
- return _frontierDefense;
- }
-
- public Faction GetCurrentFaction()
- {
- return FactionMethods.GetFaction(
- _tf2Api._sharp!.Memory.Read(_tf2Api._engineDllBaseAddress + 0x7A7383, 1)[0]);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/titanfall2-rp/enums/GameMode.cs b/titanfall2-rp/enums/GameMode.cs
index dd3a3d4..ef56ae8 100644
--- a/titanfall2-rp/enums/GameMode.cs
+++ b/titanfall2-rp/enums/GameMode.cs
@@ -136,7 +136,7 @@ public enum GameMode
ps,
///
- /// Life Fire
+ /// Live Fire
///
speedball,
@@ -209,7 +209,7 @@ public static string ToFriendlyString(this GameMode gameMode)
GameMode.ctf => "Capture the Flag",
GameMode.lts => "Last Titan Standing",
GameMode.ps => "Pilots vs. Pilots",
- GameMode.speedball => "Life Fire",
+ GameMode.speedball => "Live Fire",
GameMode.mfd => "Marked For Death",
GameMode.ttdm => "Titan Brawl",
GameMode.fd_easy => "Frontier Defense (Easy)",
@@ -221,4 +221,4 @@ public static string ToFriendlyString(this GameMode gameMode)
};
}
}
-}
\ No newline at end of file
+}