Compare commits
No commits in common. "88600db7790378e84ee781dfdafb8b8eeec93cf8" and "d722deeefce5985a74bca9545b217e03abb0e48b" have entirely different histories.
88600db779
...
d722deeefc
12 changed files with 29 additions and 425 deletions
|
|
@ -1,309 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Decal.Adapter;
|
|
||||||
using Decal.Adapter.Wrappers;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace MosswartMassacre
|
|
||||||
{
|
|
||||||
public struct AllegianceInfoRecord
|
|
||||||
{
|
|
||||||
public string name;
|
|
||||||
public int rank;
|
|
||||||
public int race;
|
|
||||||
public int gender;
|
|
||||||
|
|
||||||
public AllegianceInfoRecord(string _name, int _rank, int _race, int _gender)
|
|
||||||
{
|
|
||||||
name = _name;
|
|
||||||
rank = _rank;
|
|
||||||
race = _race;
|
|
||||||
gender = _gender;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class CharacterStats
|
|
||||||
{
|
|
||||||
// Cached allegiance data (populated from network messages)
|
|
||||||
private static string allegianceName;
|
|
||||||
private static int allegianceSize;
|
|
||||||
private static int followers;
|
|
||||||
private static AllegianceInfoRecord monarch;
|
|
||||||
private static AllegianceInfoRecord patron;
|
|
||||||
private static int allegianceRank;
|
|
||||||
|
|
||||||
// Cached luminance data (populated from network messages)
|
|
||||||
private static long luminanceEarned = -1;
|
|
||||||
private static long luminanceTotal = -1;
|
|
||||||
|
|
||||||
// Cached title data (populated from network messages)
|
|
||||||
private static int currentTitle = -1;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reset all cached data. Call on plugin init.
|
|
||||||
/// </summary>
|
|
||||||
internal static void Init()
|
|
||||||
{
|
|
||||||
allegianceName = null;
|
|
||||||
allegianceSize = 0;
|
|
||||||
followers = 0;
|
|
||||||
monarch = new AllegianceInfoRecord();
|
|
||||||
patron = new AllegianceInfoRecord();
|
|
||||||
allegianceRank = 0;
|
|
||||||
luminanceEarned = -1;
|
|
||||||
luminanceTotal = -1;
|
|
||||||
currentTitle = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Process game event 0x0020 - Allegiance info.
|
|
||||||
/// Extracts monarch, patron, rank, followers from the allegiance tree.
|
|
||||||
/// Reference: TreeStats Character.cs:642-745
|
|
||||||
/// </summary>
|
|
||||||
internal static void ProcessAllegianceInfoMessage(NetworkMessageEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
allegianceName = e.Message.Value<string>("allegianceName");
|
|
||||||
allegianceSize = e.Message.Value<Int32>("allegianceSize");
|
|
||||||
followers = e.Message.Value<Int32>("followers");
|
|
||||||
|
|
||||||
monarch = new AllegianceInfoRecord();
|
|
||||||
patron = new AllegianceInfoRecord();
|
|
||||||
|
|
||||||
MessageStruct records = e.Message.Struct("records");
|
|
||||||
int currentId = CoreManager.Current.CharacterFilter.Id;
|
|
||||||
var parentMap = new Dictionary<int, int>();
|
|
||||||
var recordMap = new Dictionary<int, AllegianceInfoRecord>();
|
|
||||||
|
|
||||||
for (int i = 0; i < records.Count; i++)
|
|
||||||
{
|
|
||||||
var record = records.Struct(i);
|
|
||||||
int charId = record.Value<int>("character");
|
|
||||||
int treeParent = record.Value<int>("treeParent");
|
|
||||||
|
|
||||||
parentMap[charId] = treeParent;
|
|
||||||
recordMap[charId] = new AllegianceInfoRecord(
|
|
||||||
record.Value<string>("name"),
|
|
||||||
record.Value<int>("rank"),
|
|
||||||
record.Value<int>("race"),
|
|
||||||
record.Value<int>("gender"));
|
|
||||||
|
|
||||||
// Monarch: treeParent <= 1
|
|
||||||
if (treeParent <= 1)
|
|
||||||
{
|
|
||||||
monarch = recordMap[charId];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Patron: parent of current character
|
|
||||||
if (parentMap.ContainsKey(currentId) && recordMap.ContainsKey(parentMap[currentId]))
|
|
||||||
{
|
|
||||||
patron = recordMap[parentMap[currentId]];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Our rank from the record
|
|
||||||
if (recordMap.ContainsKey(currentId))
|
|
||||||
{
|
|
||||||
allegianceRank = recordMap[currentId].rank;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
PluginCore.WriteToChat($"[CharStats] Allegiance processing error: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Process game event 0x0013 - Character property data.
|
|
||||||
/// Extracts luminance from QWORD keys 6 and 7.
|
|
||||||
/// Reference: TreeStats Character.cs:582-640
|
|
||||||
/// </summary>
|
|
||||||
internal static void ProcessCharacterPropertyData(NetworkMessageEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
MessageStruct props = e.Message.Struct("properties");
|
|
||||||
MessageStruct qwords = props.Struct("qwords");
|
|
||||||
|
|
||||||
for (int i = 0; i < qwords.Count; i++)
|
|
||||||
{
|
|
||||||
var tmpStruct = qwords.Struct(i);
|
|
||||||
long key = tmpStruct.Value<Int64>("key");
|
|
||||||
long value = tmpStruct.Value<Int64>("value");
|
|
||||||
|
|
||||||
if (key == 6) // AvailableLuminance
|
|
||||||
luminanceEarned = value;
|
|
||||||
else if (key == 7) // MaximumLuminance
|
|
||||||
luminanceTotal = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
PluginCore.WriteToChat($"[CharStats] Property processing error: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Process game event 0x0029 - Titles list.
|
|
||||||
/// Extracts current title ID.
|
|
||||||
/// Reference: TreeStats Character.cs:551-580
|
|
||||||
/// </summary>
|
|
||||||
internal static void ProcessTitlesMessage(NetworkMessageEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
currentTitle = e.Message.Value<Int32>("current");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
PluginCore.WriteToChat($"[CharStats] Title processing error: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Process game event 0x002b - Set title (when player changes title).
|
|
||||||
/// </summary>
|
|
||||||
internal static void ProcessSetTitleMessage(NetworkMessageEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
currentTitle = e.Message.Value<Int32>("title");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
PluginCore.WriteToChat($"[CharStats] Set title error: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Collect all character data and send via WebSocket.
|
|
||||||
/// Called on login (after delay) and every 10 minutes.
|
|
||||||
/// </summary>
|
|
||||||
internal static void CollectAndSend()
|
|
||||||
{
|
|
||||||
if (!PluginCore.WebSocketEnabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var cf = CoreManager.Current.CharacterFilter;
|
|
||||||
var culture = new CultureInfo("en-US");
|
|
||||||
|
|
||||||
// --- Attributes ---
|
|
||||||
var attributes = new Dictionary<string, object>();
|
|
||||||
foreach (var attr in cf.Attributes)
|
|
||||||
{
|
|
||||||
attributes[attr.Name.ToLower()] = new
|
|
||||||
{
|
|
||||||
@base = attr.Base,
|
|
||||||
creation = attr.Creation
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Vitals (base values) ---
|
|
||||||
var vitals = new Dictionary<string, object>();
|
|
||||||
foreach (var vital in cf.Vitals)
|
|
||||||
{
|
|
||||||
vitals[vital.Name.ToLower()] = new
|
|
||||||
{
|
|
||||||
@base = vital.Base
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Skills ---
|
|
||||||
var skills = new Dictionary<string, object>();
|
|
||||||
Decal.Filters.FileService fs = CoreManager.Current.FileService as Decal.Filters.FileService;
|
|
||||||
if (fs != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < fs.SkillTable.Length; i++)
|
|
||||||
{
|
|
||||||
Decal.Interop.Filters.SkillInfo skillinfo = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
skillinfo = cf.Underlying.get_Skill(
|
|
||||||
(Decal.Interop.Filters.eSkillID)fs.SkillTable[i].Id);
|
|
||||||
|
|
||||||
string name = skillinfo.Name.ToLower().Replace(" ", "_");
|
|
||||||
string training = skillinfo.Training.ToString();
|
|
||||||
// Training enum returns "eTrainSpecialized" etc, strip "eTrain" prefix
|
|
||||||
if (training.Length > 6)
|
|
||||||
training = training.Substring(6);
|
|
||||||
|
|
||||||
skills[name] = new
|
|
||||||
{
|
|
||||||
@base = skillinfo.Base,
|
|
||||||
training = training
|
|
||||||
};
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (skillinfo != null)
|
|
||||||
{
|
|
||||||
Marshal.ReleaseComObject(skillinfo);
|
|
||||||
skillinfo = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Allegiance ---
|
|
||||||
object allegiance = null;
|
|
||||||
if (allegianceName != null)
|
|
||||||
{
|
|
||||||
allegiance = new
|
|
||||||
{
|
|
||||||
name = allegianceName,
|
|
||||||
monarch = monarch.name != null ? new
|
|
||||||
{
|
|
||||||
name = monarch.name,
|
|
||||||
race = monarch.race,
|
|
||||||
rank = monarch.rank,
|
|
||||||
gender = monarch.gender
|
|
||||||
} : null,
|
|
||||||
patron = patron.name != null ? new
|
|
||||||
{
|
|
||||||
name = patron.name,
|
|
||||||
race = patron.race,
|
|
||||||
rank = patron.rank,
|
|
||||||
gender = patron.gender
|
|
||||||
} : null,
|
|
||||||
rank = allegianceRank,
|
|
||||||
followers = followers
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Build payload ---
|
|
||||||
var payload = new
|
|
||||||
{
|
|
||||||
type = "character_stats",
|
|
||||||
timestamp = DateTime.UtcNow.ToString("o"),
|
|
||||||
character_name = cf.Name,
|
|
||||||
level = cf.Level,
|
|
||||||
race = cf.Race,
|
|
||||||
gender = cf.Gender,
|
|
||||||
birth = cf.Birth.ToString(culture),
|
|
||||||
total_xp = cf.TotalXP,
|
|
||||||
unassigned_xp = cf.UnassignedXP,
|
|
||||||
skill_credits = cf.SkillPoints,
|
|
||||||
deaths = cf.Deaths,
|
|
||||||
luminance_earned = luminanceEarned >= 0 ? (long?)luminanceEarned : null,
|
|
||||||
luminance_total = luminanceTotal >= 0 ? (long?)luminanceTotal : null,
|
|
||||||
current_title = currentTitle >= 0 ? (int?)currentTitle : null,
|
|
||||||
attributes = attributes,
|
|
||||||
vitals = vitals,
|
|
||||||
skills = skills,
|
|
||||||
allegiance = allegiance
|
|
||||||
};
|
|
||||||
|
|
||||||
_ = WebSocket.SendCharacterStatsAsync(payload);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
PluginCore.WriteToChat($"[CharStats] Error collecting stats: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -35,12 +35,10 @@
|
||||||
<DefineConstants>TRACE;VVS_REFERENCED;DECAL_INTEROP</DefineConstants>
|
<DefineConstants>TRACE;VVS_REFERENCED;DECAL_INTEROP</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="0Harmony">
|
<Reference Include="0Harmony">
|
||||||
<HintPath>lib\0Harmony.dll</HintPath>
|
<HintPath>..\..\..\..\Documents\Decal Plugins\UtilityBelt\0Harmony.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Costura, Version=5.7.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Costura, Version=5.7.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
|
@ -51,18 +49,18 @@
|
||||||
<EmbedInteropTypes>False</EmbedInteropTypes>
|
<EmbedInteropTypes>False</EmbedInteropTypes>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Decal.FileService">
|
<Reference Include="Decal.FileService">
|
||||||
<HintPath>lib\Decal.FileService.dll</HintPath>
|
<HintPath>..\..\..\..\..\..\Program Files (x86)\Decal 3.0\Decal.FileService.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Decal.Interop.Core">
|
<Reference Include="Decal.Interop.Core, Version=2.9.8.3, Culture=neutral, PublicKeyToken=481f17d392f1fb65, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<EmbedInteropTypes>False</EmbedInteropTypes>
|
<EmbedInteropTypes>False</EmbedInteropTypes>
|
||||||
<HintPath>lib\Decal.Interop.Core.DLL</HintPath>
|
<HintPath>..\..\..\..\..\..\Program Files (x86)\Decal 3.0\.NET 4.0 PIA\Decal.Interop.Core.DLL</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Decal.Interop.Filters">
|
<Reference Include="Decal.Interop.Filters, Version=2.9.8.3, Culture=neutral, PublicKeyToken=481f17d392f1fb65, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<EmbedInteropTypes>False</EmbedInteropTypes>
|
<EmbedInteropTypes>False</EmbedInteropTypes>
|
||||||
<HintPath>lib\Decal.Interop.Filters.DLL</HintPath>
|
<HintPath>..\..\..\..\..\..\Program Files (x86)\Decal 3.0\.NET 4.0 PIA\Decal.Interop.Filters.DLL</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Decal.Interop.Inject, Version=2.9.8.3, Culture=neutral, PublicKeyToken=481f17d392f1fb65, processorArchitecture=MSIL">
|
<Reference Include="Decal.Interop.Inject, Version=2.9.8.3, Culture=neutral, PublicKeyToken=481f17d392f1fb65, processorArchitecture=MSIL">
|
||||||
|
|
@ -70,16 +68,16 @@
|
||||||
<EmbedInteropTypes>False</EmbedInteropTypes>
|
<EmbedInteropTypes>False</EmbedInteropTypes>
|
||||||
<HintPath>lib\Decal.Interop.Inject.dll</HintPath>
|
<HintPath>lib\Decal.Interop.Inject.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Decal.Interop.D3DService">
|
<Reference Include="Decal.Interop.D3DService, Version=2.9.8.3, Culture=neutral, PublicKeyToken=481f17d392f1fb65, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<EmbedInteropTypes>False</EmbedInteropTypes>
|
<EmbedInteropTypes>False</EmbedInteropTypes>
|
||||||
<HintPath>lib\Decal.Interop.D3DService.DLL</HintPath>
|
<HintPath>..\..\..\..\..\..\Program Files (x86)\Decal 3.0\.NET 4.0 PIA\Decal.Interop.D3DService.DLL</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Decal.Interop.Input">
|
<Reference Include="Decal.Interop.Input">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<EmbedInteropTypes>False</EmbedInteropTypes>
|
<EmbedInteropTypes>False</EmbedInteropTypes>
|
||||||
<HintPath>lib\Decal.Interop.Input.DLL</HintPath>
|
<HintPath>..\..\..\..\..\..\Program Files (x86)\Decal 3.0\.NET 4.0 PIA\Decal.Interop.Input.DLL</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Microsoft.Win32.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
<Reference Include="Microsoft.Win32.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
|
@ -226,12 +224,12 @@
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="utank2-i">
|
<Reference Include="utank2-i, Version=1.0.0.0, Culture=neutral, processorArchitecture=x86">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>lib\utank2-i.dll</HintPath>
|
<HintPath>bin\Debug\utank2-i.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="VCS5">
|
<Reference Include="VCS5">
|
||||||
<HintPath>lib\VCS5.dll</HintPath>
|
<HintPath>..\..\..\..\..\..\Games\Decal Plugins\Virindi\VirindiChatSystem5\VCS5.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="VirindiViewService">
|
<Reference Include="VirindiViewService">
|
||||||
<HintPath>lib\VirindiViewService.dll</HintPath>
|
<HintPath>lib\VirindiViewService.dll</HintPath>
|
||||||
|
|
@ -335,7 +333,6 @@
|
||||||
<Compile Include="Views\FlagTrackerView.cs" />
|
<Compile Include="Views\FlagTrackerView.cs" />
|
||||||
<Compile Include="Views\VVSBaseView.cs" />
|
<Compile Include="Views\VVSBaseView.cs" />
|
||||||
<Compile Include="Views\VVSTabbedMainView.cs" />
|
<Compile Include="Views\VVSTabbedMainView.cs" />
|
||||||
<Compile Include="CharacterStats.cs" />
|
|
||||||
<Compile Include="WebSocket.cs" />
|
<Compile Include="WebSocket.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
@ -357,17 +354,24 @@
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Decal">
|
<COMReference Include="Decal">
|
||||||
<HintPath>lib\Decal.dll</HintPath>
|
<Guid>{FF7F5F6D-34E0-4B6F-B3BB-8141DE2EF732}</Guid>
|
||||||
|
<VersionMajor>2</VersionMajor>
|
||||||
|
<VersionMinor>0</VersionMinor>
|
||||||
|
<Lcid>0</Lcid>
|
||||||
|
<WrapperTool>primary</WrapperTool>
|
||||||
|
<Isolated>False</Isolated>
|
||||||
<EmbedInteropTypes>False</EmbedInteropTypes>
|
<EmbedInteropTypes>False</EmbedInteropTypes>
|
||||||
</Reference>
|
</COMReference>
|
||||||
<Reference Include="DecalNet">
|
<COMReference Include="DecalNet">
|
||||||
<HintPath>lib\decalnet.dll</HintPath>
|
<Guid>{572B87C4-93BD-46B3-A291-CD58181D25DC}</Guid>
|
||||||
|
<VersionMajor>2</VersionMajor>
|
||||||
|
<VersionMinor>0</VersionMinor>
|
||||||
|
<Lcid>0</Lcid>
|
||||||
|
<WrapperTool>primary</WrapperTool>
|
||||||
|
<Isolated>False</Isolated>
|
||||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||||
</Reference>
|
</COMReference>
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="All" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="..\packages\Fody.6.9.3\build\Fody.targets" Condition="Exists('..\packages\Fody.6.9.3\build\Fody.targets')" />
|
<Import Project="..\packages\Fody.6.9.3\build\Fody.targets" Condition="Exists('..\packages\Fody.6.9.3\build\Fody.targets')" />
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,6 @@ namespace MosswartMassacre
|
||||||
internal static Timer updateTimer;
|
internal static Timer updateTimer;
|
||||||
private static Timer vitalsTimer;
|
private static Timer vitalsTimer;
|
||||||
private static System.Windows.Forms.Timer commandTimer;
|
private static System.Windows.Forms.Timer commandTimer;
|
||||||
private static Timer characterStatsTimer;
|
|
||||||
private static readonly Queue<string> pendingCommands = new Queue<string>();
|
private static readonly Queue<string> pendingCommands = new Queue<string>();
|
||||||
public static bool RareMetaEnabled { get; set; } = true;
|
public static bool RareMetaEnabled { get; set; } = true;
|
||||||
|
|
||||||
|
|
@ -183,8 +182,6 @@ namespace MosswartMassacre
|
||||||
CoreManager.Current.WorldFilter.CreateObject += OnInventoryCreate;
|
CoreManager.Current.WorldFilter.CreateObject += OnInventoryCreate;
|
||||||
CoreManager.Current.WorldFilter.ReleaseObject += OnInventoryRelease;
|
CoreManager.Current.WorldFilter.ReleaseObject += OnInventoryRelease;
|
||||||
CoreManager.Current.WorldFilter.ChangeObject += OnInventoryChange;
|
CoreManager.Current.WorldFilter.ChangeObject += OnInventoryChange;
|
||||||
// Subscribe to server messages for allegiance/luminance/title data
|
|
||||||
CoreManager.Current.EchoFilter.ServerDispatch += EchoFilter_ServerDispatch;
|
|
||||||
// Initialize VVS view after character login
|
// Initialize VVS view after character login
|
||||||
ViewManager.ViewInit();
|
ViewManager.ViewInit();
|
||||||
|
|
||||||
|
|
@ -254,8 +251,7 @@ namespace MosswartMassacre
|
||||||
CoreManager.Current.WorldFilter.CreateObject -= OnInventoryCreate;
|
CoreManager.Current.WorldFilter.CreateObject -= OnInventoryCreate;
|
||||||
CoreManager.Current.WorldFilter.ReleaseObject -= OnInventoryRelease;
|
CoreManager.Current.WorldFilter.ReleaseObject -= OnInventoryRelease;
|
||||||
CoreManager.Current.WorldFilter.ChangeObject -= OnInventoryChange;
|
CoreManager.Current.WorldFilter.ChangeObject -= OnInventoryChange;
|
||||||
// Unsubscribe from server dispatch
|
|
||||||
CoreManager.Current.EchoFilter.ServerDispatch -= EchoFilter_ServerDispatch;
|
|
||||||
|
|
||||||
// Stop and dispose of the timers
|
// Stop and dispose of the timers
|
||||||
if (updateTimer != null)
|
if (updateTimer != null)
|
||||||
|
|
@ -288,15 +284,6 @@ namespace MosswartMassacre
|
||||||
questStreamingTimer = null;
|
questStreamingTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop and dispose character stats timer
|
|
||||||
if (characterStatsTimer != null)
|
|
||||||
{
|
|
||||||
characterStatsTimer.Stop();
|
|
||||||
characterStatsTimer.Elapsed -= OnCharacterStatsUpdate;
|
|
||||||
characterStatsTimer.Dispose();
|
|
||||||
characterStatsTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dispose quest manager
|
// Dispose quest manager
|
||||||
if (questManager != null)
|
if (questManager != null)
|
||||||
{
|
{
|
||||||
|
|
@ -416,34 +403,6 @@ namespace MosswartMassacre
|
||||||
WriteToChat($"[ERROR] Quest streaming initialization failed: {ex.Message}");
|
WriteToChat($"[ERROR] Quest streaming initialization failed: {ex.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize character stats streaming
|
|
||||||
try
|
|
||||||
{
|
|
||||||
CharacterStats.Init();
|
|
||||||
|
|
||||||
// Start 10-minute character stats timer
|
|
||||||
characterStatsTimer = new Timer(600000); // 10 minutes
|
|
||||||
characterStatsTimer.Elapsed += OnCharacterStatsUpdate;
|
|
||||||
characterStatsTimer.AutoReset = true;
|
|
||||||
characterStatsTimer.Start();
|
|
||||||
|
|
||||||
// Send initial stats after 5-second delay (let CharacterFilter populate)
|
|
||||||
var initialDelay = new Timer(5000);
|
|
||||||
initialDelay.AutoReset = false;
|
|
||||||
initialDelay.Elapsed += (s, args) =>
|
|
||||||
{
|
|
||||||
CharacterStats.CollectAndSend();
|
|
||||||
((Timer)s).Dispose();
|
|
||||||
};
|
|
||||||
initialDelay.Start();
|
|
||||||
|
|
||||||
WriteToChat("[OK] Character stats streaming initialized (10-min interval)");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
WriteToChat($"[ERROR] Character stats initialization failed: {ex.Message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Quest Streaming Methods
|
#region Quest Streaming Methods
|
||||||
|
|
@ -1202,50 +1161,6 @@ namespace MosswartMassacre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnCharacterStatsUpdate(object sender, ElapsedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
CharacterStats.CollectAndSend();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
WriteToChat($"[CharStats] Timer error: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EchoFilter_ServerDispatch(object sender, NetworkMessageEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (e.Message.Type == 0xF7B0) // Game Event
|
|
||||||
{
|
|
||||||
int eventId = (int)e.Message["event"];
|
|
||||||
|
|
||||||
if (eventId == 0x0020) // Allegiance info
|
|
||||||
{
|
|
||||||
CharacterStats.ProcessAllegianceInfoMessage(e);
|
|
||||||
}
|
|
||||||
else if (eventId == 0x0013) // Login Character (properties)
|
|
||||||
{
|
|
||||||
CharacterStats.ProcessCharacterPropertyData(e);
|
|
||||||
}
|
|
||||||
else if (eventId == 0x0029) // Titles list
|
|
||||||
{
|
|
||||||
CharacterStats.ProcessTitlesMessage(e);
|
|
||||||
}
|
|
||||||
else if (eventId == 0x002b) // Set title
|
|
||||||
{
|
|
||||||
CharacterStats.ProcessSetTitleMessage(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
WriteToChat($"[CharStats] ServerDispatch error: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CalculateKillsPerInterval()
|
private void CalculateKillsPerInterval()
|
||||||
{
|
{
|
||||||
double minutesElapsed = (DateTime.Now - statsStartTime).TotalMinutes;
|
double minutesElapsed = (DateTime.Now - statsStartTime).TotalMinutes;
|
||||||
|
|
|
||||||
|
|
@ -296,12 +296,6 @@ namespace MosswartMassacre
|
||||||
await SendEncodedAsync(json, CancellationToken.None);
|
await SendEncodedAsync(json, CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task SendCharacterStatsAsync(object statsData)
|
|
||||||
{
|
|
||||||
var json = JsonConvert.SerializeObject(statsData);
|
|
||||||
await SendEncodedAsync(json, CancellationToken.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task SendQuestDataAsync(string questName, string countdown)
|
public static async Task SendQuestDataAsync(string questName, string countdown)
|
||||||
{
|
{
|
||||||
var envelope = new
|
var envelope = new
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue