Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ active, disable it when visual artifacts or added latency appear.
for strawberries in nearby rooms.
- Optional MiaoNet players, avatars, off-screen players, and names on the minimap.
Names can be hidden, limited to watched players, or shown for everyone.
- Optional suppression of MiaoNet's native off-screen name labels.

### MiaoNet watching and notifications

Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ Present hook 只会重复这张最终图像,无法提供帧生成所需的深
- 根据存档显示收集状态;可选在边缘显示附近房间的草莓。
- 可选显示 MiaoNet 同地图玩家、头像、越界玩家和玩家名称;玩家名称可以设置为
不显示、仅显示关注玩家或显示所有人。
- 可隐藏 MiaoNet 原生的越界名字标签。

### MiaoNet 关注与通知

Expand Down
76 changes: 0 additions & 76 deletions Source/MiaoNetBridge.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using System.Collections;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Monocle;
using MonoMod.RuntimeDetour;

namespace Celeste.Mod.MicroblocksQolUtils;

Expand All @@ -28,10 +26,6 @@ public static class MiaoNetBridge {
private static Assembly? assembly;
private static bool commandInstalled;
private static int retryFrames;
private static Hook? offscreenNameHook;
private static bool offscreenNameHookAttempted;
private static PropertyInfo? ghostNameTagEntityProperty;
private static PropertyInfo? ghostNameTagIsOnSelfProperty;
private static PixelFont? avatarFont;
private static float avatarBaseSize;
private static Type? emojiType;
Expand Down Expand Up @@ -63,16 +57,10 @@ public static void Update(Level? level) {
retryFrames = 0;
TryInstallChatCommand();
}
TryInstallOffscreenNameHook();
ReadPlayers(level);
}

public static void Unload() {
offscreenNameHook?.Dispose();
offscreenNameHook = null;
offscreenNameHookAttempted = false;
ghostNameTagEntityProperty = null;
ghostNameTagIsOnSelfProperty = null;
CurrentPlayers.Clear();
LocalPlayer = null;
LoggedIn = false;
Expand Down Expand Up @@ -303,70 +291,6 @@ private static void ObserveRoomChange(int id, string name, string room) {
LastRooms[id] = room;
}

private static void TryInstallOffscreenNameHook() {
if (offscreenNameHook is not null || offscreenNameHookAttempted || assembly is null) return;
offscreenNameHookAttempted = true;
try {
Type nameTagType = assembly.GetType("Celeste.Mod.MiaoNet.GhostNameTag", throwOnError: true)!;
MethodInfo render = nameTagType.GetMethod(
nameof(Entity.Render),
BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
binder: null,
Type.EmptyTypes,
modifiers: null
) ?? throw new MissingMethodException(nameTagType.FullName, nameof(Entity.Render));

ghostNameTagEntityProperty = nameTagType.GetProperty("Entity", BindingFlags.Public | BindingFlags.Instance)
?? throw new MissingMemberException(nameTagType.FullName, "Entity");
ghostNameTagIsOnSelfProperty = nameTagType.GetProperty("IsOnSelf", BindingFlags.Public | BindingFlags.Instance);

Type originalDelegateType = Expression.GetDelegateType(nameTagType, typeof(void));
Type detourDelegateType = Expression.GetDelegateType(originalDelegateType, nameTagType, typeof(void));
MethodInfo shouldRender = typeof(MiaoNetBridge).GetMethod(
nameof(ShouldRenderGhostNameTag),
BindingFlags.NonPublic | BindingFlags.Static
)!;
DynamicMethod detourMethod = new(
"MicroblocksQolUtils_MiaoNetGhostNameTagRender",
typeof(void),
[originalDelegateType, nameTagType],
typeof(MiaoNetBridge).Module,
skipVisibility: true
);
ILGenerator il = detourMethod.GetILGenerator();
Label done = il.DefineLabel();
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, shouldRender);
il.Emit(OpCodes.Brfalse_S, done);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Callvirt, originalDelegateType.GetMethod(nameof(Action.Invoke))!);
il.MarkLabel(done);
il.Emit(OpCodes.Ret);
Delegate detour = detourMethod.CreateDelegate(detourDelegateType);

offscreenNameHook = new Hook(render, detour);
Logger.Log(LogLevel.Info, "MicroblocksQolUtils", "MiaoNet off-screen name filtering enabled");
} catch (Exception exception) {
ghostNameTagEntityProperty = null;
ghostNameTagIsOnSelfProperty = null;
Logger.Log(LogLevel.Warn, "MicroblocksQolUtils/MiaoNet", $"Cannot hook off-screen names: {exception.Message}");
}
}

private static bool ShouldRenderGhostNameTag(object nameTag) {
if (!MicroblocksQolUtilsModule.Settings.HideMiaoNetOffscreenNames) return true;
try {
if (ghostNameTagIsOnSelfProperty?.GetValue(nameTag) is true) return true;
if (ghostNameTagEntityProperty?.GetValue(nameTag) is not Entity player
|| player.Scene is not Level level) return true;
return level.InsideCamera(player.Position);
} catch {
// A MiaoNet update should never make its normal name rendering disappear.
return true;
}
}

private static bool TryResolveAvatarFont() {
if (avatarFont is not null && emojiType is not null) return true;
Type? fontType = assembly?.GetType("Celeste.Mod.MiaoNet.MiaoNetFont");
Expand Down
3 changes: 0 additions & 3 deletions Source/QolSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,6 @@ public void CreateFontFamilyEntry(TextMenu menu, bool inGame) {
[DefaultValue(MiniMapNameMode.WatchedOnly)]
public MiniMapNameMode MiniMapNames { get; set; } = MiniMapNameMode.WatchedOnly;

[DefaultValue(true)]
public bool HideMiaoNetOffscreenNames { get; set; } = true;

[DefaultValue(true)]
public bool ShowRoomsRemaining { get; set; } = true;

Expand Down
4 changes: 1 addition & 3 deletions Source/QolSettingsOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1638,9 +1638,7 @@ private List<SettingsTab> BuildTabs() {
value => settings.MiniMapShowOffscreenPlayers = value),
EnumRow("头像裁剪形状", () => settings.MiniMapAvatarShape,
value => settings.MiniMapAvatarShape = value),
EnumRow("玩家名字", () => settings.MiniMapNames, value => settings.MiniMapNames = value),
Toggle("隐藏原生越界名字", () => settings.HideMiaoNetOffscreenNames,
value => settings.HideMiaoNetOffscreenNames = value)
EnumRow("玩家名字", () => settings.MiniMapNames, value => settings.MiniMapNames = value)
]),
new SettingsTab("录制", "videocam", BuildRecorderRows(settings), RecorderPage: true),
new SettingsTab("界面与系统", "settings", [
Expand Down