fix: transferownership correctly sets owner level and demotes old owner to op, works for offline players, notifies members

This commit is contained in:
2026-07-14 22:52:32 +02:00
parent 1c0a5f88a1
commit eaa79f8f52
+67 -24
View File
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using Vintagestory.API.Common;
using Vintagestory.API.Config;
using Vintagestory.API.Server;
namespace ClaimLink;
@@ -117,7 +118,7 @@ public static class ClaimLinkChatCommand
new(
new[] { "transferownership", "transfer", "to" },
"Transfer ownership of the claim link to another player.",
new ICommandArgumentParser[] { p.Word("groupname"), p.OnlinePlayer("playername") },
new ICommandArgumentParser[] { p.Word("groupname"), p.PlayerUids("playername") },
true,
TransferOwnership
),
@@ -170,7 +171,7 @@ public static class ClaimLinkChatCommand
new(
new[] { "transferownership", "transfer", "to" },
"Transfer ownership of any claim link to another player.",
new ICommandArgumentParser[] { p.Word("groupname"), p.OnlinePlayer("playername") },
new ICommandArgumentParser[] { p.Word("groupname"), p.PlayerUids("playername") },
false,
AdminTransferOwnership
),
@@ -449,15 +450,21 @@ public static class ClaimLinkChatCommand
public static TextCommandResult TransferOwnership(TextCommandCallingArgs args)
{
string groupName = (string)args[0];
IPlayer target = (IPlayer)args[1];
IPlayer player = args.Caller.Player;
string playerUid = player.PlayerUID;
TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group);
TextCommandResult? err = TryResolveTargetPlayer(
(PlayerUidName[])args[1],
out IPlayer target
);
if (err != null)
return err;
err = TryResolveClaimLink(group, out _);
err = TryResolveGroup(groupName, out PlayerGroup group);
if (err != null)
return err;
err = TryResolveClaimLink(group, out ClaimLink link);
if (err != null)
return err;
@@ -476,10 +483,28 @@ public static class ClaimLinkChatCommand
return Stage(
playerUid,
$"Ownership of '{groupName}' will be transferred to {target.PlayerName}.",
() => ExecuteTransferOwnership(group, target)
() => ExecuteTransferOwnership(group, link, target)
);
}
private static TextCommandResult? TryResolveTargetPlayer(
PlayerUidName[] matches,
out IPlayer target
)
{
target = null!;
if (matches.Length != 1)
return TextCommandResult.Error("Name a single player.");
IPlayer? resolved = ClaimLinkModSystem.World.PlayerByUid(matches[0].Uid);
if (resolved == null)
return TextCommandResult.Error($"No such player '{matches[0].Name}'.");
target = resolved;
return null;
}
private static TextCommandResult? RequireNotAlreadyOwner(PlayerGroup group, IPlayer target)
{
return target.PlayerUID == group.OwnerUID
@@ -487,27 +512,39 @@ public static class ClaimLinkChatCommand
: null;
}
private static TextCommandResult ExecuteTransferOwnership(PlayerGroup group, IPlayer target)
private static TextCommandResult ExecuteTransferOwnership(
PlayerGroup group,
ClaimLink link,
IPlayer target
)
{
string oldOwnerUid = group.OwnerUID;
string targetUid = target.PlayerUID;
IPlayer? oldOwner = ClaimLinkModSystem.World.PlayerByUid(oldOwnerUid);
EnumPlayerGroupMemberShip? oldOwnerLevel = oldOwner?.GetGroup(group.Uid)?.Level;
EnumPlayerGroupMemberShip targetLevel = target.GetGroup(group.Uid)!.Level;
PlayerGroupMembership? oldOwnerMembership = oldOwner?.GetGroup(group.Uid);
PlayerGroupMembership targetMembership = target.GetGroup(group.Uid)!;
// TODO remove debug logging once transfer ownership persistence is confirmed tested
ClaimLinkModSystem.Logger.Notification(
$"claimlink: transferownership '{group.Name}' (uid {group.Uid}) BEFORE OwnerUID={oldOwnerUid} "
+ $"(old owner {oldOwner?.PlayerName ?? oldOwnerUid} level={oldOwnerLevel}, new owner {target.PlayerName}/{targetUid} level={targetLevel})"
);
group.OwnerUID = target.PlayerUID;
targetMembership.Level = EnumPlayerGroupMemberShip.Owner;
group.OwnerUID = targetUid;
if (oldOwnerMembership != null)
oldOwnerMembership.Level = EnumPlayerGroupMemberShip.Op;
ClaimLinkModSystem.Logger.Notification(
$"claimlink: transferownership '{group.Name}' (uid {group.Uid}) AFTER OwnerUID={group.OwnerUID}"
);
string notice = $"'{group.Name}' is now owned by {target.PlayerName}.";
return TextCommandResult.Success($"'{group.Name}' is now owned by {target.PlayerName}.");
HashSet<string> notifyUids = link.Members.Select(m => m.OwnerPlayerUid).ToHashSet();
notifyUids.Add(oldOwnerUid);
notifyUids.Add(target.PlayerUID);
foreach (string uid in notifyUids)
NotifyIfOnline(ClaimLinkModSystem.World.PlayerByUid(uid), notice);
return TextCommandResult.Success(notice);
}
private static void NotifyIfOnline(IPlayer? player, string message)
{
if (player is IServerPlayer sp && sp.ConnectionState == EnumClientState.Playing)
sp.SendMessage(GlobalConstants.GeneralChatGroup, message, EnumChatType.Notification);
}
public static TextCommandResult Info(TextCommandCallingArgs args)
@@ -597,13 +634,19 @@ public static class ClaimLinkChatCommand
public static TextCommandResult AdminTransferOwnership(TextCommandCallingArgs args)
{
string groupName = (string)args[0];
IPlayer target = (IPlayer)args[1];
TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group);
TextCommandResult? err = TryResolveTargetPlayer(
(PlayerUidName[])args[1],
out IPlayer target
);
if (err != null)
return err;
err = TryResolveClaimLink(group, out _);
err = TryResolveGroup(groupName, out PlayerGroup group);
if (err != null)
return err;
err = TryResolveClaimLink(group, out ClaimLink link);
if (err != null)
return err;
@@ -615,7 +658,7 @@ public static class ClaimLinkChatCommand
if (err != null)
return err;
return ExecuteTransferOwnership(group, target);
return ExecuteTransferOwnership(group, link, target);
}
public static TextCommandResult AdminInfo(TextCommandCallingArgs args) =>