Skip to content

Commit

Permalink
Update for new version
Browse files Browse the repository at this point in the history
kinda slow, and images don't work. but it's something
  • Loading branch information
ardittristan committed Oct 8, 2023
1 parent 71cfc9a commit f3ee097
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 159 deletions.
127 changes: 72 additions & 55 deletions HSReflection/Reflection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,105 +5,119 @@
using HSReflection.Objects;
using HSReflection.Util;
using ScryDotNet;
using HMReflection = HearthMirror.Reflection;

namespace HSReflection;

public static partial class Reflection
{
internal static Mirror Mirror => (Mirror)MirrorGetter(null);
private static readonly MemberGetter MirrorGetter =
Reflect.PropertyGetter(typeof(HearthMirror.Reflection), "Mirror", FasterflectFlags.StaticPrivate);

public static string GetLocalization(dynamic obj) => (string)GetLocalizationInvoker(obj);
private static readonly MethodInvoker GetLocalizationInvoker =
Reflect.Method(typeof(HearthMirror.Reflection).GetMethod("GetLocalization", FasterflectFlags.StaticPrivate));
private static readonly MemberGetter MirrorGetter =
Reflect.PropertyGetter(typeof(HMReflection), "Mirror", FasterflectFlags.StaticPrivate);

#pragma warning disable CS0067,CS0414 // Event is never used
public static event Action<Exception> Exception = null!;
#pragma warning restore CS0067,CS0414 // Event is never used
public static event Action<Exception> Exception
{
add => HMReflection.Exception += value;
remove => HMReflection.Exception -= value;
}

internal static dynamic GetService(string name) => HearthMirror.Reflection.GetService(name);
internal static dynamic GetService(string name) => HMReflection.GetService(name);

public static void Reinitialize() => HearthMirror.Reflection.Reinitialize();
public static void Reinitialize() => HMReflection.Reinitialize();

public static Dictionary<int, QuestRecord> GetQuestRecords() => TryGetInternal(GetQuestRecordsInternal);

private static Dictionary<int, QuestRecord> GetQuestRecordsInternal()
{
Dictionary<int, QuestRecord> questRecords = new();

MonoObject? questPoolState = Services.QuestManager["m_questPoolState"];

MonoObject? quests = Services.GameDbf["Quest"]?["m_records"];

if (quests == null) return questRecords;
lock (QuestRecordCacheLock)
{
MonoWrapper? questPoolState = Services.QuestManager["m_questPoolState"];

object[] questEntries = quests["_items"];
MonoWrapper? quests = Services.GameDbf["Quest"]?["m_records"];

foreach (MonoObject quest in questEntries.Cast<MonoObject>())
{
int questPoolId = quest["m_questPoolId"];
if (quests == null) return questRecords;

MonoObject? questPoolStateEntry = questPoolState == null
? null
: Map.GetValue(questPoolState, questPoolId);
MonoWrapper[] questEntries = quests["_items"]!.AsArray();

questRecords.Add(quest["m_ID"], new QuestRecord()
foreach (MonoWrapper quest in questEntries)
{
CanAbandon = quest["m_canAbandon"],
Description = GetLocalization(quest["m_description"]),
Icon = quest["m_icon"],
Name = GetLocalization(quest["m_name"]),
NextInChain = quest["m_nextInChainId"],
PoolGuaranteed = quest["m_poolGuaranteed"],
QuestPool = new QuestPool()
{
Id = questPoolId,
PoolType = (QuestPoolType)(questPoolStateEntry?["_QuestPoolId"] ?? QuestPoolType.INVALID),
RerollAvailableCount = questPoolStateEntry?["_RerollAvailableCount"] ?? 0
},
Quota = quest["m_quota"],
RewardList = quest["m_rewardListId"],
RewardTrackXp = quest["m_rewardTrackXp"],
RewardTrackType = (RewardTrackType)(quest["m_rewardTrackType"] ?? RewardTrackType.NONE)
});
int questPoolId = quest["m_questPoolId"]!.Value;

MonoObject? questPoolStateEntry = questPoolState == null
? null
: Map.GetValue(questPoolState, questPoolId);

int questId = quest["m_ID"]!.Value;

if (!QuestRecordCache.ContainsKey(questId))
QuestRecordCache.Add(questId, new QuestRecord()
{
CanAbandon = quest["m_canAbandon"]!.Value,
Description = quest["m_description"]?["m_currentLocaleValue"]?.Value ?? "",
Icon = quest["m_icon"]?.Value,
Name = quest["m_name"]?["m_currentLocaleValue"]?.Value ?? "",
NextInChain = quest["m_nextInChainId"]!.Value,
PoolGuaranteed = quest["m_poolGuaranteed"]!.Value,
QuestPool = new QuestPool()
{
Id = questPoolId,
PoolType = (QuestPoolType)(questPoolStateEntry?["_QuestPoolId"] ?? QuestPoolType.INVALID),
RerollAvailableCount = questPoolStateEntry?["_RerollAvailableCount"] ?? 0
},
Quota = quest["m_quota"]!.Value,
RewardList = quest["m_rewardListId"]!.Value,
RewardTrackXp = quest["m_rewardTrackXp"]!.Value,
RewardTrackType = (RewardTrackType)(quest["m_rewardTrackType"]?.Value ?? RewardTrackType.NONE)
});


questRecords.Add(questId, QuestRecordCache[questId]);
}
}

return questRecords;
}

private static readonly Dictionary<int, QuestRecord> QuestRecordCache = new();
private static readonly object QuestRecordCacheLock = new();

public static List<PlayerQuestState> GetQuestStates() => TryGetInternal(GetQuestStatesInternal);

private static List<PlayerQuestState> GetQuestStatesInternal()
{
List<PlayerQuestState> quests = new();

object[]? currentQuestValues = Services.QuestManager["m_questState"]["_entries"];
MonoWrapper[]? currentQuestValues = Services.QuestManager["m_questState"]?["_entries"]?.AsArray();

if (currentQuestValues == null) return quests;

foreach (MonoStruct? val in currentQuestValues.Cast<MonoStruct?>())
foreach (MonoWrapper val in currentQuestValues)
{
MonoObject? curVal = val?["value"];
MonoWrapper? curVal = val["value"];
if (curVal == null) continue;

quests.Add(new PlayerQuestState()
{
Progress = (int)curVal["_Progress"],
QuestId = (int)curVal["_QuestId"],
Status = (QuestStatus)(int)curVal["_Status"],
Progress = (int)curVal["_Progress"]!.Value!,
QuestId = (int)curVal["_QuestId"]!.Value!,
Status = (QuestStatus)(int)curVal["_Status"]!.Value!,
});
}

return quests;
}

public static List<Quest> GetQuests() => TryGetInternal(GetQuestsInternal);

private static List<Quest> GetQuestsInternal()
{
List<Quest> quests = new();

int rewardTrackBonusXp =
RewardTracksManager.Global?["<TrackDataModel>k__BackingField"]?["m_XpBonusPercent"] ?? 0;
RewardTracksManager.Global?["TrackDataModel"]?["m_XpBonusPercent"]?.Value ?? 0;

Dictionary<int, QuestRecord> questRecords = GetQuestRecordsInternal();

Expand Down Expand Up @@ -165,23 +179,25 @@ private static List<Quest> GetQuestsInternal()
}

public static Dictionary<QuestPoolType, DateTime>? GetNextQuestTimes() => TryGetInternal(GetNextQuestTimesInternal);

private static Dictionary<QuestPoolType, DateTime>? GetNextQuestTimesInternal()
{
MonoObject? questPoolState = Services.QuestManager["m_questPoolState"];
MonoWrapper? questPoolState = Services.QuestManager["m_questPoolState"];

if (questPoolState == null) return null;

Dictionary<QuestPoolType, DateTime> questPools = new();

foreach (MonoStruct? curEntry in questPoolState["_entries"])
foreach (MonoWrapper curEntry in questPoolState["_entries"]!.AsArray())
{
MonoObject? questPoolEntry = curEntry?["value"];
double secondsUntilNextGrant = DynamicUtil.TryCast<double>(questPoolEntry?["_SecondsUntilNextGrant"]);
MonoWrapper? questPoolEntry = curEntry["value"];
double secondsUntilNextGrant =
DynamicUtil.TryCast<double>(questPoolEntry?["_SecondsUntilNextGrant"]?.Value);

try
{
if (secondsUntilNextGrant != 0)
questPools.Add((QuestPoolType)questPoolEntry!["_QuestPoolId"],
questPools.Add((QuestPoolType)questPoolEntry!["_QuestPoolId"]!.Value!,
DateTime.Now.AddSeconds(secondsUntilNextGrant));
}
catch (ArgumentException)
Expand All @@ -193,14 +209,15 @@ private static List<Quest> GetQuestsInternal()
}

public static string? FindGameString(string key) => TryGetInternal(() => FindGameStringInternal(key));

private static string? FindGameStringInternal(string key)
{
object[]? gameStrings = Mirror.Root?["GameStrings"]["s_tables"]["valueSlots"];
MonoWrapper[]? gameStrings = new MonoWrapper(Mirror.Root?["GameStrings"])["s_tables"]?["valueSlots"]?.AsArray();
if (gameStrings == null) return null;

foreach (MonoObject? gameStringTable in gameStrings.Cast<MonoObject?>())
foreach (MonoWrapper? gameStringTable in gameStrings)
{
string? text = Map.GetValue(gameStringTable?["m_table"], key);
string? text = Map.GetValue(gameStringTable["m_table"]?.Value, key);
if (text != null) return text;
}

Expand Down
16 changes: 8 additions & 8 deletions HSReflection/Util/Map.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@

public static class Map
{
public static dynamic? GetValue(dynamic map, dynamic key)
public static dynamic? GetValue(MonoWrapper? map, dynamic key)
{
if (map == null) return null;

if (map["keySlots"] == null)
foreach (dynamic? curEntry in map["_entries"])
foreach (MonoWrapper? curEntry in map["_entries"]!.AsArray())
{
if (curEntry == null) continue;
if (key == curEntry["key"]) return curEntry["value"];
if (curEntry.Value == null) continue;
if (key == curEntry["key"]!.Value) return curEntry["value"]!.Value;
}
else
{
int i = 0;
foreach (dynamic? curKey in map["keySlots"])
foreach (MonoWrapper? curKey in map["keySlots"]!.AsArray())
{
if (curKey == null) continue;
if (key == curKey) return map["valueSlots"][i];
if (curKey.Value == null) continue;
if (key == curKey.Value) return map["valueSlots"]!.Value[i];

i++;
}
}

return null;
}
}
}
58 changes: 58 additions & 0 deletions HSReflection/Util/MonoWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System.Diagnostics;
using ScryDotNet;

namespace HSReflection.Util;

[DebuggerDisplay("{Value}")]
public class MonoWrapper
{
public dynamic? Value { get; }

public MonoWrapper(dynamic? value)
{
Value = value!;
}

public MonoWrapper[] AsArray() => ((dynamic[])Value!).Select(v => new MonoWrapper(v)).ToArray();

public MonoWrapper? this[string key]
{
get
{
try
{
switch (Value)
{
case MonoObject mObj:
Dictionary<string, object> mObjFields = mObj.getFields();
return mObjFields.Count == 0
? new MonoWrapper(mObj[key])
: new MonoWrapper(mObjFields[key]);
case MonoStruct mStr:
Dictionary<string, object> mStrFields = mStr.getFields();
return mStrFields.Count == 0
? new MonoWrapper(mStr[key])
: new MonoWrapper(mStrFields[key]);
default:
return null;
}
}
catch
{
return null;
}
}
}

public static bool operator ==(MonoWrapper? obj1, MonoWrapper? obj2) =>
obj1?.Value is null
? obj2?.Value is null
: obj1.Equals(obj2);

public static bool operator !=(MonoWrapper obj1, MonoWrapper obj2) => !(obj1 == obj2);

// ReSharper disable once BaseObjectEqualsIsObjectEquals
public override bool Equals(object? obj) => base.Equals(obj);

public override int GetHashCode() => Value?.GetHashCode();
}
15 changes: 7 additions & 8 deletions HSReflection/Util/RewardTracksManager.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using HSReflection.Enums;
using ScryDotNet;

namespace HSReflection.Util;

Expand All @@ -13,21 +12,21 @@ internal static class RewardTracksManager
{ RewardTrackType.NONE, -1 }
};

private static dynamic[] Entries => Services.RewardTrackManager["m_rewardTrackEntries"]["_entries"];
private static MonoWrapper[] Entries => Services.RewardTrackManager["m_rewardTrackEntries"]!["_entries"]!.AsArray();

public static MonoObject? Global => GetRewardTrack(RewardTrackType.GLOBAL);
public static MonoWrapper? Global => GetRewardTrack(RewardTrackType.GLOBAL);

public static MonoObject? BattleGrounds => GetRewardTrack(RewardTrackType.BATTLEGROUNDS);
public static MonoWrapper? BattleGrounds => GetRewardTrack(RewardTrackType.BATTLEGROUNDS);

public static MonoObject? Event => GetRewardTrack(RewardTrackType.EVENT);
public static MonoWrapper? Event => GetRewardTrack(RewardTrackType.EVENT);

public static MonoObject? GetRewardTrack(RewardTrackType type)
public static MonoWrapper? GetRewardTrack(RewardTrackType type)
{
if (TypeIndex[type] == -1)
TypeIndex[type] = Entries
.Select((entry, index) => (
(int?)entry["value"]?["<TrackDataModel>k__BackingField"]?[
"m_RewardTrackType"], index)).First(tuple => tuple.Item1 == (int)type).index;
(int?)entry["value"]?["TrackDataModel"]?["m_RewardTrackType"]?.Value, index))
.First(tuple => tuple.Item1 == (int)type).index;

return Entries[TypeIndex[type]]["value"];
}
Expand Down
Loading

0 comments on commit f3ee097

Please sign in to comment.