tModLoader 关于物品收藏的联机同步

由于我未寻找到tModLoader给出相关方法,在物品在收藏时调用,我使用favorited作为关键字查找,最后找到了状态修改的地方,这个是私有方法,被LeftClick调用,隶属于Terraria.UI.ItemSlot,在调用前后均没有看到有钩子的迹象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
private static bool OverrideLeftClick(Item[] inv, int context = 0, int slot = 0)
{
	if (Main.cursorOverride == 3) {
		if (!canFavoriteAt[Math.Abs(context)])
			return false;
	
		item.favorited = !item.favorited;
		SoundEngine.PlaySound(12);
		return true;
        
        
        
public static void LeftClick(Item[] inv, int context = 0, int slot = 0)
{
	Player player = Main.player[Main.myPlayer];
	bool flag = Main.mouseLeftRelease && Main.mouseLeft;
	if (flag) {
		if (OverrideLeftClick(inv, context, slot))
			return;

现在我们要求其更改时服务器能收到消息,所以要对他进行挂钩。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[ModuleInitializer]
internal static void HookItemSlot()
{
    On_ItemSlot.OverrideLeftClick += On_ItemSlot_OverrideLeftClick; ;
}

private static bool On_ItemSlot_OverrideLeftClick(On_ItemSlot.orig_OverrideLeftClick orig, Item[] inv, int context, int slot)
{
    var oldFavoritedStatu = inv[slot].favorited;
    var retValue = orig.Invoke(inv, context, slot);
    var newFavoritedStatu = inv[slot].favorited;
    if(oldFavoritedStatu != newFavoritedStatu) {
        var packet = ModLoader.GetMod(nameof(NoNPCSpawn)).GetPacket();
        packet.Write(slot);
        packet.Write(newFavoritedStatu);
        packet.Send();
    }
    return retValue;
}

public override void HandlePacket(BinaryReader reader, int whoAmI)
{
    //这里看需求,如果其他客户端需要知道状态,可进行 (netmode == server) 后转发
    var slot = reader.ReadInt32();
    var newFavoritedStatu = reader.ReadBoolean();
    Main.player[whoAmI].inventory[slot].favorited = newFavoritedStatu;
    base.HandlePacket(reader, whoAmI);
}

如果玩家进入世界前就收藏了物品,需要手动同步一下状态

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class NoNPCSpawnPlayer : ModPlayer
{
    private volatile List<Action> updateExter = [];

    public override void PostUpdate()
    {
        foreach (var action in updateExter) {
            action.Invoke();
        }
        updateExter.Clear();
        base.PostUpdate();
    }

    public override void OnEnterWorld()
    {
        updateExter.Add(SendItemFavorited);
        base.OnEnterWorld();
    }
    private void SendItemFavorited()
    {
        if (Main.netMode == NetmodeID.MultiplayerClient) {
            var packet = ModLoader.GetMod(nameof(NoNPCSpawn)).GetPacket();
            List<int> items = [];
            for (int i = 0; i < Player.inventory.Length; i++) {
                if (Player.inventory[i].favorited) {
                    items.Add(i);
                }
            }
            items.ForEach(f => {
                packet.Write(f);
                packet.Write(true);
                packet.Send();
            });
        }
    }
}
使用 Hugo 构建
主题 StackJimmy 设计