Skip to content

Commit 7ab391f

Browse files
committed
Merge branch 'main' into net-10
2 parents 5d8abc9 + a2ac98d commit 7ab391f

17 files changed

+982
-260
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
using Hi3Helper.Plugin.Core.Management.PresetConfig;
2+
using Hi3Helper.Plugin.Core.Utility;
3+
using System;
4+
using System.Runtime.InteropServices;
5+
using System.Runtime.InteropServices.Marshalling;
6+
using static Hi3Helper.Plugin.Core.SharedStaticV1Ext;
7+
8+
namespace Hi3Helper.Plugin.Core.DiscordPresence;
9+
10+
/// <summary>
11+
/// This extension provides a method to get the Discord Presence information for the current game region.
12+
/// </summary>
13+
/// <remarks>
14+
/// This extension IS ONLY SUPPOSEDLY BE USED by the launcher, NOT by the plugin.
15+
/// </remarks>
16+
public static class DiscordPresenceExtension
17+
{
18+
/// <summary>
19+
/// A context used to manage the context of Discord Presence information.
20+
/// </summary>
21+
public unsafe class DiscordPresenceContext : IDisposable
22+
{
23+
// Fields
24+
private DiscordPresenceInfo* _data;
25+
26+
internal DiscordPresenceContext(IPluginPresetConfig presetConfig) : this(0, presetConfig)
27+
{
28+
}
29+
30+
public DiscordPresenceContext(nint pluginHandle, IPluginPresetConfig presetConfig)
31+
{
32+
if (pluginHandle == nint.Zero)
33+
{
34+
return;
35+
}
36+
37+
if (!pluginHandle.TryGetExport("GetCurrentDiscordPresenceInfo",
38+
out GetCurrentDiscordPresenceInfoDelegate method))
39+
{
40+
return;
41+
}
42+
43+
DiscordPresenceInfo* info = null;
44+
45+
void* ptr = ComInterfaceMarshaller<IPluginPresetConfig>.ConvertToUnmanaged(presetConfig);
46+
HResult result = method(ptr, &info);
47+
48+
if (result == HResult.Ok && info != null)
49+
{
50+
_data = info;
51+
}
52+
}
53+
54+
/// <summary>
55+
/// Indicates whether the Discord Presence feature is available.
56+
/// </summary>
57+
public bool IsFeatureAvailable => _data != null;
58+
59+
/// <inheritdoc cref="DiscordPresenceInfo.PresenceId"/>
60+
public ulong PresenceId => _data != null ? _data->PresenceId : 0;
61+
62+
/// <inheritdoc cref="DiscordPresenceInfo.LargeIconUrl"/>
63+
public string? LargeIconUrl
64+
{
65+
get
66+
{
67+
if (_data == null || _data->LargeIconUrl == null)
68+
{
69+
return null;
70+
}
71+
72+
return field ??= Utf16StringMarshaller.ConvertToManaged(_data->LargeIconUrl);
73+
}
74+
}
75+
76+
/// <inheritdoc cref="DiscordPresenceInfo.LargeIconTooltip"/>
77+
public string? LargeIconTooltip
78+
{
79+
get
80+
{
81+
if (_data == null || _data->LargeIconTooltip == null)
82+
{
83+
return null;
84+
}
85+
86+
return field ??= Utf16StringMarshaller.ConvertToManaged(_data->LargeIconTooltip);
87+
}
88+
}
89+
90+
/// <inheritdoc cref="DiscordPresenceInfo.SmallIconUrl"/>
91+
public string? SmallIconUrl
92+
{
93+
get
94+
{
95+
if (_data == null || _data->SmallIconUrl == null)
96+
{
97+
return null;
98+
}
99+
100+
return field ??= Utf16StringMarshaller.ConvertToManaged(_data->SmallIconUrl);
101+
}
102+
}
103+
104+
/// <inheritdoc cref="DiscordPresenceInfo.SmallIconTooltip"/>
105+
public string? SmallIconTooltip
106+
{
107+
get
108+
{
109+
if (_data == null || _data->SmallIconTooltip == null)
110+
{
111+
return null;
112+
}
113+
114+
return field ??= Utf16StringMarshaller.ConvertToManaged(_data->SmallIconTooltip);
115+
}
116+
}
117+
118+
/// <inheritdoc cref="IDisposable.Dispose"/>
119+
public void Dispose()
120+
{
121+
if (_data == null)
122+
{
123+
return;
124+
}
125+
126+
_data->Dispose();
127+
NativeMemory.Free(_data);
128+
129+
_data = null;
130+
131+
GC.SuppressFinalize(this);
132+
}
133+
}
134+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using System.Runtime.InteropServices.Marshalling;
4+
using Hi3Helper.Plugin.Core.Utility;
5+
6+
namespace Hi3Helper.Plugin.Core.DiscordPresence;
7+
8+
/// <summary>
9+
/// Represents presence information for a Discord user, including logo URLs and tooltips for display in rich presence
10+
/// integrations.
11+
/// </summary>
12+
[StructLayout(LayoutKind.Sequential)]
13+
public unsafe struct DiscordPresenceInfo : IDisposable
14+
{
15+
/// <summary>
16+
/// Represents the UID of the Discord Application ID.
17+
/// </summary>
18+
public ulong PresenceId; // 00 - 08
19+
20+
/// <summary>
21+
/// Represents which logo to be used for large-icon display in Discord.<br/>
22+
/// The format of the URL can be just the name of the asset inside the Discord Application -> Rich Presence -> Art Assets menu or a full URL to an external logo (max: 256 chars).<br/>
23+
/// </summary>
24+
public ushort* LargeIconUrl; // 08 - 16
25+
26+
/// <summary>
27+
/// The tooltip text to be displayed when hovering over the large-icon in Discord.
28+
/// </summary>
29+
public ushort* LargeIconTooltip; // 16 - 24
30+
31+
/// <summary>
32+
/// Represents which logo to be used for small-icon display in Discord.<br/>
33+
/// The format of the URL can be just the name of the asset inside the Discord Application -> Rich Presence -> Art Assets menu or a full URL to an external logo (max: 256 chars).<br/>
34+
/// </summary>
35+
public ushort* SmallIconUrl; // 24 - 32
36+
37+
/// <summary>
38+
/// The tooltip text to be displayed when hovering over the small-icon in Discord.
39+
/// </summary>
40+
public ushort* SmallIconTooltip; // 32 - 40
41+
42+
/// <summary>
43+
/// Reserved for future use. Should be unused for now.
44+
/// </summary>
45+
public void* Reserved; // 40 - 48 (For future use)
46+
47+
/// <inheritdoc cref="IDisposable.Dispose"/>
48+
public void Dispose()
49+
{
50+
Utf16StringMarshaller.Free(LargeIconUrl);
51+
Utf16StringMarshaller.Free(LargeIconTooltip);
52+
Utf16StringMarshaller.Free(SmallIconUrl);
53+
Utf16StringMarshaller.Free(SmallIconTooltip);
54+
55+
if (Reserved != null)
56+
{
57+
Mem.Free(Reserved);
58+
}
59+
}
60+
}

Hi3Helper.Plugin.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>net10.0</TargetFramework>

Management/Api/ILauncherApiNews.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public unsafe partial interface ILauncherApiNews : ILauncherApi
1919
{
2020
/// <summary>
2121
/// Get the news entries fot the launcher.<br/>
22-
/// This method returns a handle to the <see cref="PluginDisposableMemory{T}"/> of <see cref="LauncherPathEntry"/>.<br/>
22+
/// This method returns a handle to the <see cref="PluginDisposableMemory{T}"/> of <see cref="LauncherNewsEntry"/>.<br/>
2323
/// Pass this method to <see cref="PluginDisposableMemoryExtension.ToManagedSpan{T}(PluginDisposableMemoryExtension.MarshalToMemorySelectorDelegate)"/> to get the span.
2424
/// </summary>
2525
/// <param name="handle">The handle to the pointer of the <see cref="LauncherNewsEntry"/> data</param>
@@ -30,7 +30,7 @@ public unsafe partial interface ILauncherApiNews : ILauncherApi
3030

3131
/// <summary>
3232
/// Get the carousel image entries for the launcher.<br/>
33-
/// This method returns a handle to the <see cref="PluginDisposableMemory{T}"/> of <see cref="LauncherPathEntry"/>.<br/>
33+
/// This method returns a handle to the <see cref="PluginDisposableMemory{T}"/> of <see cref="LauncherCarouselEntry"/>.<br/>
3434
/// Pass this method to <see cref="PluginDisposableMemoryExtension.ToManagedSpan{T}(PluginDisposableMemoryExtension.MarshalToMemorySelectorDelegate)"/> to get the span.
3535
/// </summary>
3636
/// <param name="handle">The handle to the pointer of the <see cref="LauncherCarouselEntry"/> data</param>
@@ -41,7 +41,7 @@ public unsafe partial interface ILauncherApiNews : ILauncherApi
4141

4242
/// <summary>
4343
/// Get the social media info entries for the launcher.<br/>
44-
/// This method returns a handle to the <see cref="PluginDisposableMemory{T}"/> of <see cref="LauncherPathEntry"/>.<br/>
44+
/// This method returns a handle to the <see cref="PluginDisposableMemory{T}"/> of <see cref="LauncherSocialMediaEntry"/>.<br/>
4545
/// Pass this method to <see cref="PluginDisposableMemoryExtension.ToManagedSpan{T}(PluginDisposableMemoryExtension.MarshalToMemorySelectorDelegate)"/> to get the span.
4646
/// </summary>
4747
/// <param name="handle">The handle to the pointer of the <see cref="LauncherSocialMediaEntry"/> data</param>

Management/Api/LauncherApiBase.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ protected virtual async Task DownloadAssetAsyncInner(HttpClient?
9191
}
9292

9393
await client.DownloadFilesAsync(fileUrl, outputStream, downloadProgress, token: token).ConfigureAwait(false);
94+
await outputStream.FlushAsync(token);
9495
}
9596

9697
/// <inheritdoc cref="IFree.Free"/>

Management/Api/LauncherNewsEntry.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,15 @@ namespace Hi3Helper.Plugin.Core.Management.Api;
99
/// Entry of the launcher's news data.
1010
/// </summary>
1111
[StructLayout(LayoutKind.Sequential, Pack = 8)]
12-
public unsafe struct LauncherNewsEntry(LauncherNewsEntryType newsType)
12+
public unsafe struct LauncherNewsEntry()
1313
: IDisposable
1414
{
1515
private byte _isFreed = 0;
1616

1717
/// <summary>
1818
/// The type of the news entry. See <see cref="LauncherNewsEntryType"/> for the types.
1919
/// </summary>
20-
public readonly LauncherNewsEntryType Type = newsType;
21-
20+
public LauncherNewsEntryType Type = LauncherNewsEntryType.Event;
2221
private byte* _title = null;
2322
private byte* _description = null;
2423
private byte* _url = null;
@@ -51,7 +50,8 @@ public unsafe struct LauncherNewsEntry(LauncherNewsEntryType newsType)
5150
/// <param name="description">The description of the news entry.</param>
5251
/// <param name="url">The HREF/click URL of the news entry.</param>
5352
/// <param name="postDate">The short format (DD/MM) of the date for the news entry.</param>
54-
public void Write(string? title, string? description, string? url, string? postDate)
53+
/// <param name="type">Type of the news entry</param>
54+
public void Write(string? title, string? description, string? url, string? postDate, LauncherNewsEntryType type = LauncherNewsEntryType.Event)
5555
{
5656
Utf8StringMarshaller.Free(_title);
5757
Utf8StringMarshaller.Free(_description);
@@ -62,11 +62,15 @@ public void Write(string? title, string? description, string? url, string? postD
6262
_description = Utf8StringMarshaller.ConvertToUnmanaged(description);
6363
_url = Utf8StringMarshaller.ConvertToUnmanaged(url);
6464
_postDate = Utf8StringMarshaller.ConvertToUnmanaged(postDate);
65+
Type = type;
6566
}
6667

6768
public void Dispose()
6869
{
69-
if (_isFreed == 1) return;
70+
if (_isFreed == 1)
71+
{
72+
return;
73+
}
7074

7175
Utf8StringMarshaller.Free(_title);
7276
Utf8StringMarshaller.Free(_description);

0 commit comments

Comments
 (0)