Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e0e4e0f74 | ||
|
|
154e7b7848 | ||
|
|
9e37ec11cf | ||
|
|
4d98a115ed | ||
|
|
99238c4744 | ||
|
|
1c079b7e44 | ||
|
|
b7ca9fa53b | ||
|
|
c55787ce40 |
@@ -69,14 +69,18 @@ public static class ClaimLinkChatCommand
|
|||||||
new(
|
new(
|
||||||
new[] { "new", "n" },
|
new[] { "new", "n" },
|
||||||
"Promote a group you own to a claim link.",
|
"Promote a group you own to a claim link.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname") },
|
new ICommandArgumentParser[] { p.OptionalWord("groupname") },
|
||||||
true,
|
true,
|
||||||
New
|
New
|
||||||
),
|
),
|
||||||
new(
|
new(
|
||||||
new[] { "link", "l" },
|
new[] { "link", "l" },
|
||||||
"Link a claim you own to a claim link.",
|
"Link a claim you own to a claim link.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname"), p.IntRange("claim", 0, 999) },
|
new ICommandArgumentParser[]
|
||||||
|
{
|
||||||
|
p.IntRange("claim", 0, 999),
|
||||||
|
p.OptionalWord("groupname"),
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
Link
|
Link
|
||||||
),
|
),
|
||||||
@@ -104,28 +108,28 @@ public static class ClaimLinkChatCommand
|
|||||||
new(
|
new(
|
||||||
new[] { "kick" },
|
new[] { "kick" },
|
||||||
"Force-unlink all of a player's claims from the claim link.",
|
"Force-unlink all of a player's claims from the claim link.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname"), p.OnlinePlayer("playername") },
|
new ICommandArgumentParser[] { p.Word("groupname"), p.OptionalWord("playername") },
|
||||||
true,
|
true,
|
||||||
Kick
|
Kick
|
||||||
),
|
),
|
||||||
new(
|
new(
|
||||||
new[] { "delete" },
|
new[] { "delete" },
|
||||||
"Delete a claim link.",
|
"Delete a claim link.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname") },
|
new ICommandArgumentParser[] { p.OptionalWord("groupname") },
|
||||||
true,
|
true,
|
||||||
Delete
|
Delete
|
||||||
),
|
),
|
||||||
new(
|
new(
|
||||||
new[] { "transferownership", "transfer", "to" },
|
new[] { "transferownership", "transfer", "to" },
|
||||||
"Transfer ownership of the claim link to another player.",
|
"Transfer ownership of the claim link to another player.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname"), p.PlayerUids("playername") },
|
new ICommandArgumentParser[] { p.Word("groupname"), p.OptionalWord("playername") },
|
||||||
true,
|
true,
|
||||||
TransferOwnership
|
TransferOwnership
|
||||||
),
|
),
|
||||||
new(
|
new(
|
||||||
new[] { "info", "i" },
|
new[] { "info", "i" },
|
||||||
"Show a claim link's members and linked claims.",
|
"Show a claim link's members and linked claims.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname") },
|
new ICommandArgumentParser[] { p.OptionalWord("groupname") },
|
||||||
true,
|
true,
|
||||||
Info
|
Info
|
||||||
),
|
),
|
||||||
@@ -150,38 +154,35 @@ public static class ClaimLinkChatCommand
|
|||||||
new(
|
new(
|
||||||
new[] { "delete", "del" },
|
new[] { "delete", "del" },
|
||||||
"Delete a claim link.",
|
"Delete a claim link.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname") },
|
new ICommandArgumentParser[] { p.OptionalWord("groupname") },
|
||||||
false,
|
false,
|
||||||
AdminDelete
|
AdminDelete
|
||||||
),
|
),
|
||||||
new(
|
new(
|
||||||
new[] { "unlink" },
|
new[] { "unlink" },
|
||||||
"Unlink a claim.",
|
"Unlink a claim.",
|
||||||
new ICommandArgumentParser[] { p.OnlinePlayer("playername"), p.Word("claim") },
|
new ICommandArgumentParser[] { p.Word("playername"), p.IntRange("claim", 0, 999) },
|
||||||
false,
|
false,
|
||||||
AdminUnlink
|
AdminUnlink
|
||||||
),
|
),
|
||||||
new(
|
new(
|
||||||
new[] { "kick" },
|
new[] { "kick" },
|
||||||
"Force-unlink all of a player's claims.",
|
"Force-unlink all of a player's claims.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname"), p.OnlinePlayer("playername") },
|
new ICommandArgumentParser[] { p.Word("groupname"), p.OptionalWord("playername") },
|
||||||
false,
|
false,
|
||||||
AdminKick
|
AdminKick
|
||||||
),
|
),
|
||||||
new(
|
new(
|
||||||
new[] { "transferownership", "transfer", "to" },
|
new[] { "transferownership", "transfer", "to" },
|
||||||
"Transfer ownership of any claim link to another player.",
|
"Transfer ownership of any claim link to another player.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname"), p.PlayerUids("playername") },
|
new ICommandArgumentParser[]
|
||||||
|
{
|
||||||
|
p.PlayerUids("playername"),
|
||||||
|
p.OptionalWord("groupname"),
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
AdminTransferOwnership
|
AdminTransferOwnership
|
||||||
),
|
),
|
||||||
new(
|
|
||||||
new[] { "info", "i" },
|
|
||||||
"Show a claim link's members and linked claims.",
|
|
||||||
new ICommandArgumentParser[] { p.Word("groupname") },
|
|
||||||
false,
|
|
||||||
AdminInfo
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var spec in adminCommands)
|
foreach (var spec in adminCommands)
|
||||||
@@ -190,20 +191,53 @@ public static class ClaimLinkChatCommand
|
|||||||
admin.EndSubCommand();
|
admin.EndSubCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static readonly Dictionary<string, Func<TextCommandResult>> PendingActions = new();
|
internal static readonly Dictionary<
|
||||||
|
string,
|
||||||
|
(int GroupId, Func<TextCommandResult> Action)
|
||||||
|
> PendingActions = new();
|
||||||
|
|
||||||
|
internal static readonly Dictionary<string, string> LastCancelReason = new();
|
||||||
|
|
||||||
private static TextCommandResult Stage(
|
private static TextCommandResult Stage(
|
||||||
string playerUid,
|
string playerUid,
|
||||||
|
int groupId,
|
||||||
string prompt,
|
string prompt,
|
||||||
Func<TextCommandResult> action
|
Func<TextCommandResult> action
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
PendingActions[playerUid] = action;
|
PendingActions[playerUid] = (groupId, action);
|
||||||
|
LastCancelReason.Remove(playerUid);
|
||||||
return TextCommandResult.Success(
|
return TextCommandResult.Success(
|
||||||
$"{prompt} Use /claimlink confirm to proceed, or /claimlink cancel to cancel."
|
$"{prompt} Use /claimlink confirm to proceed, or /claimlink cancel to cancel."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static void RemovePendingActionsForGroup(int groupId, string reason)
|
||||||
|
{
|
||||||
|
List<string>? toRemove = null;
|
||||||
|
foreach (var (uid, entry) in PendingActions)
|
||||||
|
if (entry.GroupId == groupId)
|
||||||
|
(toRemove ??= new()).Add(uid);
|
||||||
|
|
||||||
|
if (toRemove == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (string uid in toRemove)
|
||||||
|
{
|
||||||
|
PendingActions.Remove(uid);
|
||||||
|
LastCancelReason[uid] = reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void CancelPendingAction(string uid, int groupId, string reason)
|
||||||
|
{
|
||||||
|
if (!PendingActions.TryGetValue(uid, out var pending) || pending.GroupId != groupId)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PendingActions.Remove(uid);
|
||||||
|
LastCancelReason[uid] = reason;
|
||||||
|
}
|
||||||
|
|
||||||
private static TextCommandResult? TryResolveGroup(string groupName, out PlayerGroup group)
|
private static TextCommandResult? TryResolveGroup(string groupName, out PlayerGroup group)
|
||||||
{
|
{
|
||||||
group = ClaimLinkModSystem.Groups.GetPlayerGroupByName(groupName)!;
|
group = ClaimLinkModSystem.Groups.GetPlayerGroupByName(groupName)!;
|
||||||
@@ -212,6 +246,24 @@ public static class ClaimLinkChatCommand
|
|||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static TextCommandResult? TryResolveGroupArg(
|
||||||
|
TextCommandCallingArgs args,
|
||||||
|
int argIndex,
|
||||||
|
out PlayerGroup group
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (!args.Parsers[argIndex].IsMissing)
|
||||||
|
return TryResolveGroup((string)args[argIndex], out group);
|
||||||
|
|
||||||
|
int chatGroupId = args.Caller.FromChatGroupId;
|
||||||
|
if (!ClaimLinkModSystem.Groups.PlayerGroupsById.TryGetValue(chatGroupId, out group!))
|
||||||
|
return TextCommandResult.Error(
|
||||||
|
"No group specified and you are not sending this from a group chat channel."
|
||||||
|
);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private static TextCommandResult? TryResolveClaimLink(PlayerGroup group)
|
private static TextCommandResult? TryResolveClaimLink(PlayerGroup group)
|
||||||
{
|
{
|
||||||
return !ClaimLinkModSystem.Registry.Exists(group.Uid)
|
return !ClaimLinkModSystem.Registry.Exists(group.Uid)
|
||||||
@@ -246,10 +298,9 @@ public static class ClaimLinkChatCommand
|
|||||||
|
|
||||||
public static TextCommandResult New(TextCommandCallingArgs args)
|
public static TextCommandResult New(TextCommandCallingArgs args)
|
||||||
{
|
{
|
||||||
string groupName = (string)args[0];
|
|
||||||
string playerUid = args.Caller.Player.PlayerUID;
|
string playerUid = args.Caller.Player.PlayerUID;
|
||||||
|
|
||||||
TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group);
|
TextCommandResult? err = TryResolveGroupArg(args, 0, out PlayerGroup group);
|
||||||
if (err != null)
|
if (err != null)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -258,14 +309,19 @@ public static class ClaimLinkChatCommand
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (ClaimLinkModSystem.Registry.Exists(group.Uid))
|
if (ClaimLinkModSystem.Registry.Exists(group.Uid))
|
||||||
return TextCommandResult.Error($"'{groupName}' is already a claim link.");
|
return TextCommandResult.Error($"'{group.Name}' is already a claim link.");
|
||||||
|
|
||||||
int groupId = group.Uid;
|
int groupId = group.Uid;
|
||||||
|
string groupName = group.Name;
|
||||||
return Stage(
|
return Stage(
|
||||||
playerUid,
|
playerUid,
|
||||||
|
groupId,
|
||||||
$"'{groupName}' will become a claim link.",
|
$"'{groupName}' will become a claim link.",
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
|
if (!ClaimLinkModSystem.Groups.PlayerGroupsById.ContainsKey(groupId))
|
||||||
|
return TextCommandResult.Error($"'{groupName}' no longer exists.");
|
||||||
|
|
||||||
ClaimLinkModSystem.Registry.Add(groupId);
|
ClaimLinkModSystem.Registry.Add(groupId);
|
||||||
return TextCommandResult.Success($"'{groupName}' is now a claim link.");
|
return TextCommandResult.Success($"'{groupName}' is now a claim link.");
|
||||||
}
|
}
|
||||||
@@ -276,11 +332,16 @@ public static class ClaimLinkChatCommand
|
|||||||
{
|
{
|
||||||
string playerUid = args.Caller.Player.PlayerUID;
|
string playerUid = args.Caller.Player.PlayerUID;
|
||||||
|
|
||||||
if (!PendingActions.TryGetValue(playerUid, out Func<TextCommandResult>? action))
|
if (!PendingActions.TryGetValue(playerUid, out var pending))
|
||||||
|
{
|
||||||
|
if (LastCancelReason.Remove(playerUid, out string? reason))
|
||||||
|
return TextCommandResult.Error($"You do not have a pending action ({reason}).");
|
||||||
return TextCommandResult.Error("You do not have a pending action.");
|
return TextCommandResult.Error("You do not have a pending action.");
|
||||||
|
}
|
||||||
|
|
||||||
PendingActions.Remove(playerUid);
|
PendingActions.Remove(playerUid);
|
||||||
return action();
|
LastCancelReason.Remove(playerUid);
|
||||||
|
return pending.Action();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextCommandResult Cancel(TextCommandCallingArgs args)
|
public static TextCommandResult Cancel(TextCommandCallingArgs args)
|
||||||
@@ -295,10 +356,9 @@ public static class ClaimLinkChatCommand
|
|||||||
|
|
||||||
public static TextCommandResult Link(TextCommandCallingArgs args)
|
public static TextCommandResult Link(TextCommandCallingArgs args)
|
||||||
{
|
{
|
||||||
string groupName = (string)args[0];
|
int claimIndex = (int)args[0];
|
||||||
int claimIndex = (int)args[1];
|
|
||||||
|
|
||||||
TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group);
|
TextCommandResult? err = TryResolveGroupArg(args, 1, out PlayerGroup group);
|
||||||
if (err != null)
|
if (err != null)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -313,6 +373,7 @@ public static class ClaimLinkChatCommand
|
|||||||
|
|
||||||
string playerUid = player.PlayerUID;
|
string playerUid = player.PlayerUID;
|
||||||
int groupId = group.Uid;
|
int groupId = group.Uid;
|
||||||
|
string groupName = group.Name;
|
||||||
|
|
||||||
if (!ClaimLinkModSystem.TryResolveOwnedClaim(playerUid, claimIndex, out _))
|
if (!ClaimLinkModSystem.TryResolveOwnedClaim(playerUid, claimIndex, out _))
|
||||||
return TextCommandResult.Error("You do not own that claim.");
|
return TextCommandResult.Error("You do not own that claim.");
|
||||||
@@ -323,9 +384,17 @@ public static class ClaimLinkChatCommand
|
|||||||
string claimDesc = DescribeClaim(playerUid, claimIndex);
|
string claimDesc = DescribeClaim(playerUid, claimIndex);
|
||||||
return Stage(
|
return Stage(
|
||||||
playerUid,
|
playerUid,
|
||||||
|
groupId,
|
||||||
$"{claimDesc} will be linked into '{groupName}'.",
|
$"{claimDesc} will be linked into '{groupName}'.",
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
|
bool stillMember =
|
||||||
|
ClaimLinkModSystem
|
||||||
|
.PlayerData.GetPlayerDataByUid(playerUid)
|
||||||
|
?.PlayerGroupMemberships.ContainsKey(groupId) == true;
|
||||||
|
if (!stillMember)
|
||||||
|
return TextCommandResult.Error($"You are no longer a member of '{groupName}'.");
|
||||||
|
|
||||||
bool success = ClaimLinkModSystem.Registry.AddEntry(playerUid, groupId, claimIndex);
|
bool success = ClaimLinkModSystem.Registry.AddEntry(playerUid, groupId, claimIndex);
|
||||||
return success
|
return success
|
||||||
? TextCommandResult.Success($"Linked {claimDesc} to '{groupName}'.")
|
? TextCommandResult.Success($"Linked {claimDesc} to '{groupName}'.")
|
||||||
@@ -352,6 +421,7 @@ public static class ClaimLinkChatCommand
|
|||||||
|
|
||||||
return Stage(
|
return Stage(
|
||||||
playerUid,
|
playerUid,
|
||||||
|
(int)groupId,
|
||||||
$"{claimDesc} will be unlinked from '{groupName}'.",
|
$"{claimDesc} will be unlinked from '{groupName}'.",
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
@@ -363,40 +433,60 @@ public static class ClaimLinkChatCommand
|
|||||||
|
|
||||||
public static TextCommandResult Kick(TextCommandCallingArgs args)
|
public static TextCommandResult Kick(TextCommandCallingArgs args)
|
||||||
{
|
{
|
||||||
string groupName = (string)args[0];
|
string word1 = (string)args[0];
|
||||||
IPlayer target = (IPlayer)args[1];
|
string? word2 = args.Parsers[1].IsMissing ? null : (string)args[1];
|
||||||
|
|
||||||
TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group);
|
string targetName;
|
||||||
|
PlayerGroup group;
|
||||||
|
if (word2 != null)
|
||||||
|
{
|
||||||
|
TextCommandResult? err = TryResolveGroup(word1, out group);
|
||||||
if (err != null)
|
if (err != null)
|
||||||
return err;
|
return err;
|
||||||
|
targetName = word2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int chatGroupId = args.Caller.FromChatGroupId;
|
||||||
|
if (!ClaimLinkModSystem.Groups.PlayerGroupsById.TryGetValue(chatGroupId, out group!))
|
||||||
|
return TextCommandResult.Error(
|
||||||
|
"No group specified and you are not sending this from a group chat channel."
|
||||||
|
);
|
||||||
|
targetName = word1;
|
||||||
|
}
|
||||||
|
|
||||||
err = TryResolveClaimLink(group);
|
TextCommandResult? linkErr = TryResolveClaimLink(group);
|
||||||
if (err != null)
|
if (linkErr != null)
|
||||||
return err;
|
return linkErr;
|
||||||
|
|
||||||
err = RequireOpOrOwner(args.Caller.Player, group);
|
linkErr = RequireOpOrOwner(args.Caller.Player, group);
|
||||||
if (err != null)
|
if (linkErr != null)
|
||||||
return err;
|
return linkErr;
|
||||||
|
|
||||||
|
string? targetUid = ClaimLinkModSystem
|
||||||
|
.PlayerData.GetPlayerDataByLastKnownName(targetName)
|
||||||
|
?.PlayerUID;
|
||||||
|
if (targetUid == null)
|
||||||
|
return TextCommandResult.Error($"No such player '{targetName}'.");
|
||||||
|
|
||||||
string targetUid = target.PlayerUID;
|
|
||||||
string playerUid = args.Caller.Player.PlayerUID;
|
string playerUid = args.Caller.Player.PlayerUID;
|
||||||
|
string groupName = group.Name;
|
||||||
|
|
||||||
if (!ClaimLinkModSystem.Registry.HasAnyEntry(targetUid, group.Uid))
|
if (!ClaimLinkModSystem.Registry.HasAnyEntry(targetUid, group.Uid))
|
||||||
return TextCommandResult.Error(
|
return TextCommandResult.Error($"{targetName} has no claims linked in '{groupName}'.");
|
||||||
$"{target.PlayerName} has no claims linked in '{groupName}'."
|
|
||||||
);
|
|
||||||
|
|
||||||
return Stage(
|
return Stage(
|
||||||
playerUid,
|
playerUid,
|
||||||
$"All of {target.PlayerName}'s claims will be unlinked from '{groupName}'.",
|
group.Uid,
|
||||||
|
$"All of {targetName}'s claims will be unlinked from '{groupName}'.",
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
ClaimLinkModSystem.Registry.RemoveAllForPlayerInGroup(targetUid, group.Uid);
|
ClaimLinkModSystem.Registry.RemoveAllForPlayerInGroup(targetUid, group.Uid);
|
||||||
ClaimLinkCommandListener.PendingLoads.Remove(targetUid);
|
CommandListener.PendingLoads.Remove(targetUid);
|
||||||
PendingActions.Remove(targetUid);
|
PendingActions.Remove(targetUid);
|
||||||
|
|
||||||
return TextCommandResult.Success(
|
return TextCommandResult.Success(
|
||||||
$"Unlinked all claims of {target.PlayerName} from '{groupName}'."
|
$"Unlinked all claims of {targetName} from '{groupName}'."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -404,10 +494,9 @@ public static class ClaimLinkChatCommand
|
|||||||
|
|
||||||
public static TextCommandResult Delete(TextCommandCallingArgs args)
|
public static TextCommandResult Delete(TextCommandCallingArgs args)
|
||||||
{
|
{
|
||||||
string groupName = (string)args[0];
|
|
||||||
string playerUid = args.Caller.Player.PlayerUID;
|
string playerUid = args.Caller.Player.PlayerUID;
|
||||||
|
|
||||||
TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group);
|
TextCommandResult? err = TryResolveGroupArg(args, 0, out PlayerGroup group);
|
||||||
if (err != null)
|
if (err != null)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -420,14 +509,14 @@ public static class ClaimLinkChatCommand
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
int groupId = group.Uid;
|
int groupId = group.Uid;
|
||||||
|
string groupName = group.Name;
|
||||||
return Stage(
|
return Stage(
|
||||||
playerUid,
|
playerUid,
|
||||||
|
groupId,
|
||||||
$"'{groupName}' will be deleted as a claim link.",
|
$"'{groupName}' will be deleted as a claim link.",
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
foreach (string uid in ClaimLinkModSystem.Registry.MemberUidsForGroup(groupId))
|
RemovePendingActionsForGroup(groupId, "claim link was deleted");
|
||||||
PendingActions.Remove(uid);
|
|
||||||
|
|
||||||
ClaimLinkModSystem.Registry.Remove(groupId);
|
ClaimLinkModSystem.Registry.Remove(groupId);
|
||||||
return TextCommandResult.Success($"'{groupName}' is no longer a claim link.");
|
return TextCommandResult.Success($"'{groupName}' is no longer a claim link.");
|
||||||
}
|
}
|
||||||
@@ -436,18 +525,32 @@ public static class ClaimLinkChatCommand
|
|||||||
|
|
||||||
public static TextCommandResult TransferOwnership(TextCommandCallingArgs args)
|
public static TextCommandResult TransferOwnership(TextCommandCallingArgs args)
|
||||||
{
|
{
|
||||||
string groupName = (string)args[0];
|
string word1 = (string)args[0];
|
||||||
|
string? word2 = args.Parsers[1].IsMissing ? null : (string)args[1];
|
||||||
|
|
||||||
|
string targetName;
|
||||||
|
PlayerGroup group;
|
||||||
|
if (word2 != null)
|
||||||
|
{
|
||||||
|
TextCommandResult? groupErr = TryResolveGroup(word1, out group);
|
||||||
|
if (groupErr != null)
|
||||||
|
return groupErr;
|
||||||
|
targetName = word2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int chatGroupId = args.Caller.FromChatGroupId;
|
||||||
|
if (!ClaimLinkModSystem.Groups.PlayerGroupsById.TryGetValue(chatGroupId, out group!))
|
||||||
|
return TextCommandResult.Error(
|
||||||
|
"No group specified and you are not sending this from a group chat channel."
|
||||||
|
);
|
||||||
|
targetName = word1;
|
||||||
|
}
|
||||||
|
|
||||||
IPlayer player = args.Caller.Player;
|
IPlayer player = args.Caller.Player;
|
||||||
string playerUid = player.PlayerUID;
|
string playerUid = player.PlayerUID;
|
||||||
|
|
||||||
TextCommandResult? err = TryResolveTargetPlayer(
|
TextCommandResult? err = TryResolveOnlinePlayerByName(targetName, out IPlayer target);
|
||||||
(PlayerUidName[])args[1],
|
|
||||||
out IPlayer target
|
|
||||||
);
|
|
||||||
if (err != null)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
err = TryResolveGroup(groupName, out PlayerGroup group);
|
|
||||||
if (err != null)
|
if (err != null)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -467,13 +570,31 @@ public static class ClaimLinkChatCommand
|
|||||||
if (err != null)
|
if (err != null)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
string groupName = group.Name;
|
||||||
return Stage(
|
return Stage(
|
||||||
playerUid,
|
playerUid,
|
||||||
|
group.Uid,
|
||||||
$"Ownership of '{groupName}' will be transferred to {target.PlayerName}.",
|
$"Ownership of '{groupName}' will be transferred to {target.PlayerName}.",
|
||||||
() => ExecuteTransferOwnership(group, target)
|
() => ExecuteTransferOwnership(group, target)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static TextCommandResult? TryResolveOnlinePlayerByName(string name, out IPlayer target)
|
||||||
|
{
|
||||||
|
target = null!;
|
||||||
|
|
||||||
|
foreach (IPlayer online in ClaimLinkModSystem.World.AllOnlinePlayers)
|
||||||
|
{
|
||||||
|
if (string.Equals(online.PlayerName, name, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
target = online;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TextCommandResult.Error($"No such player '{name}' online.");
|
||||||
|
}
|
||||||
|
|
||||||
private static TextCommandResult? TryResolveTargetPlayer(
|
private static TextCommandResult? TryResolveTargetPlayer(
|
||||||
PlayerUidName[] matches,
|
PlayerUidName[] matches,
|
||||||
out IPlayer target
|
out IPlayer target
|
||||||
@@ -536,9 +657,7 @@ public static class ClaimLinkChatCommand
|
|||||||
|
|
||||||
public static TextCommandResult Info(TextCommandCallingArgs args)
|
public static TextCommandResult Info(TextCommandCallingArgs args)
|
||||||
{
|
{
|
||||||
string groupName = (string)args[0];
|
TextCommandResult? err = TryResolveGroupArg(args, 0, out PlayerGroup group);
|
||||||
|
|
||||||
TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group);
|
|
||||||
if (err != null)
|
if (err != null)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -550,31 +669,58 @@ public static class ClaimLinkChatCommand
|
|||||||
bool showDetails =
|
bool showDetails =
|
||||||
player.HasPrivilege(Privilege.controlserver) || player.GetGroup(group.Uid) != null;
|
player.HasPrivilege(Privilege.controlserver) || player.GetGroup(group.Uid) != null;
|
||||||
|
|
||||||
return TextCommandResult.Success(FormatInfo(groupName, group.Uid, showDetails));
|
return TextCommandResult.Success(FormatInfo(group.Name, group.Uid, showDetails));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextCommandResult List(TextCommandCallingArgs args)
|
public static TextCommandResult List(TextCommandCallingArgs args)
|
||||||
{
|
{
|
||||||
List<int> groupIds = ClaimLinkModSystem
|
List<int> groupIds = new(ClaimLinkModSystem.Registry.All);
|
||||||
.Registry.All.OrderByDescending(id =>
|
groupIds.Sort((a, b) => GroupMemberCount(b).CompareTo(GroupMemberCount(a)));
|
||||||
ClaimLinkModSystem.Registry.MemberCountForGroup(id)
|
|
||||||
)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (groupIds.Count == 0)
|
if (groupIds.Count == 0)
|
||||||
return TextCommandResult.Success("There are no claim links.");
|
return TextCommandResult.Success("There are no claim links.");
|
||||||
|
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
sb.AppendLine($"Claim links ({groupIds.Count}):");
|
int shown = 0;
|
||||||
|
|
||||||
foreach (int groupId in groupIds)
|
foreach (int groupId in groupIds)
|
||||||
{
|
{
|
||||||
string groupName = ClaimLinkModSystem.Groups.PlayerGroupsById[groupId].Name;
|
if (
|
||||||
int memberCount = ClaimLinkModSystem.Registry.MemberCountForGroup(groupId);
|
!ClaimLinkModSystem.Groups.PlayerGroupsById.TryGetValue(
|
||||||
sb.AppendLine($" {groupName}: {memberCount} member{(memberCount == 1 ? "" : "s")}");
|
groupId,
|
||||||
|
out PlayerGroup? group
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
RemovePendingActionsForGroup(groupId, "group no longer exists");
|
||||||
|
ClaimLinkModSystem.Registry.Remove(groupId);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TextCommandResult.Success(sb.ToString());
|
int memberCount = GroupMemberCount(groupId);
|
||||||
|
sb.AppendLine($" {group.Name}: {memberCount} member{(memberCount == 1 ? "" : "s")}");
|
||||||
|
shown++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shown == 0)
|
||||||
|
return TextCommandResult.Success("There are no claim links.");
|
||||||
|
|
||||||
|
return TextCommandResult.Success($"Claim links ({shown}):\n{sb}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<string> GroupMemberUids(int groupId)
|
||||||
|
{
|
||||||
|
foreach (var playerData in ClaimLinkModSystem.PlayerData.PlayerDataByUid.Values)
|
||||||
|
if (playerData.PlayerGroupMemberships.ContainsKey(groupId))
|
||||||
|
yield return playerData.PlayerUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GroupMemberCount(int groupId)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
foreach (string _ in GroupMemberUids(groupId))
|
||||||
|
count++;
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string DescribeClaim(string ownerPlayerUid, int claimIndex)
|
private static string DescribeClaim(string ownerPlayerUid, int claimIndex)
|
||||||
@@ -594,14 +740,14 @@ public static class ClaimLinkChatCommand
|
|||||||
|
|
||||||
private static string FormatInfo(string groupName, int groupId, bool showDetails)
|
private static string FormatInfo(string groupName, int groupId, bool showDetails)
|
||||||
{
|
{
|
||||||
int memberCount = ClaimLinkModSystem.Registry.MemberCountForGroup(groupId);
|
int memberCount = GroupMemberCount(groupId);
|
||||||
|
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
sb.AppendLine(
|
sb.AppendLine(
|
||||||
$"Claim link '{groupName}' ({memberCount} member{(memberCount == 1 ? "" : "s")}):"
|
$"Claim link '{groupName}' ({memberCount} member{(memberCount == 1 ? "" : "s")}):"
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach (string uid in ClaimLinkModSystem.Registry.MemberUidsForGroup(groupId))
|
foreach (string uid in GroupMemberUids(groupId))
|
||||||
{
|
{
|
||||||
string name = ClaimLinkModSystem.World.PlayerByUid(uid)?.PlayerName ?? uid;
|
string name = ClaimLinkModSystem.World.PlayerByUid(uid)?.PlayerName ?? uid;
|
||||||
|
|
||||||
@@ -620,27 +766,108 @@ public static class ClaimLinkChatCommand
|
|||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextCommandResult AdminDelete(TextCommandCallingArgs args) =>
|
public static TextCommandResult AdminDelete(TextCommandCallingArgs args)
|
||||||
TextCommandResult.Success("stub: claimlink admin delete");
|
{
|
||||||
|
TextCommandResult? err = TryResolveGroupArg(args, 0, out PlayerGroup group);
|
||||||
|
if (err != null)
|
||||||
|
return err;
|
||||||
|
|
||||||
public static TextCommandResult AdminUnlink(TextCommandCallingArgs args) =>
|
err = TryResolveClaimLink(group);
|
||||||
TextCommandResult.Success("stub: claimlink admin unlink");
|
if (err != null)
|
||||||
|
return err;
|
||||||
|
|
||||||
public static TextCommandResult AdminKick(TextCommandCallingArgs args) =>
|
int groupId = group.Uid;
|
||||||
TextCommandResult.Success("stub: claimlink admin kick");
|
string groupName = group.Name;
|
||||||
|
|
||||||
|
RemovePendingActionsForGroup(groupId, "claim link was deleted");
|
||||||
|
ClaimLinkModSystem.Registry.Remove(groupId);
|
||||||
|
return TextCommandResult.Success($"'{groupName}' is no longer a claim link.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextCommandResult AdminUnlink(TextCommandCallingArgs args)
|
||||||
|
{
|
||||||
|
string playerName = (string)args[0];
|
||||||
|
int claimIndex = (int)args[1];
|
||||||
|
|
||||||
|
string? targetUid = ClaimLinkModSystem
|
||||||
|
.PlayerData.GetPlayerDataByLastKnownName(playerName)
|
||||||
|
?.PlayerUID;
|
||||||
|
if (targetUid == null)
|
||||||
|
return TextCommandResult.Error($"No such player '{playerName}'.");
|
||||||
|
|
||||||
|
int? groupId = ClaimLinkModSystem.Registry.FindGroupContaining(targetUid, claimIndex);
|
||||||
|
if (groupId == null)
|
||||||
|
return TextCommandResult.Error(
|
||||||
|
$"Claim {claimIndex} is not linked into any claim link by {playerName}."
|
||||||
|
);
|
||||||
|
|
||||||
|
string groupName = ClaimLinkModSystem.Groups.PlayerGroupsById[(int)groupId].Name;
|
||||||
|
string claimDesc = DescribeClaim(targetUid, claimIndex);
|
||||||
|
|
||||||
|
ClaimLinkModSystem.Registry.RemoveEntry(targetUid, (int)groupId, claimIndex);
|
||||||
|
return TextCommandResult.Success(
|
||||||
|
$"Unlinked {claimDesc} from '{groupName}' (owned by {playerName})."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextCommandResult AdminKick(TextCommandCallingArgs args)
|
||||||
|
{
|
||||||
|
string word1 = (string)args[0];
|
||||||
|
string? word2 = args.Parsers[1].IsMissing ? null : (string)args[1];
|
||||||
|
|
||||||
|
string targetName;
|
||||||
|
PlayerGroup group;
|
||||||
|
if (word2 != null)
|
||||||
|
{
|
||||||
|
TextCommandResult? err = TryResolveGroup(word1, out group);
|
||||||
|
if (err != null)
|
||||||
|
return err;
|
||||||
|
targetName = word2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int chatGroupId = args.Caller.FromChatGroupId;
|
||||||
|
if (!ClaimLinkModSystem.Groups.PlayerGroupsById.TryGetValue(chatGroupId, out group!))
|
||||||
|
return TextCommandResult.Error(
|
||||||
|
"No group specified and you are not sending this from a group chat channel."
|
||||||
|
);
|
||||||
|
targetName = word1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextCommandResult? linkErr = TryResolveClaimLink(group);
|
||||||
|
if (linkErr != null)
|
||||||
|
return linkErr;
|
||||||
|
|
||||||
|
string? targetUid = ClaimLinkModSystem
|
||||||
|
.PlayerData.GetPlayerDataByLastKnownName(targetName)
|
||||||
|
?.PlayerUID;
|
||||||
|
if (targetUid == null)
|
||||||
|
return TextCommandResult.Error($"No such player '{targetName}'.");
|
||||||
|
|
||||||
|
string groupName = group.Name;
|
||||||
|
|
||||||
|
if (!ClaimLinkModSystem.Registry.HasAnyEntry(targetUid, group.Uid))
|
||||||
|
return TextCommandResult.Error($"{targetName} has no claims linked in '{groupName}'.");
|
||||||
|
|
||||||
|
ClaimLinkModSystem.Registry.RemoveAllForPlayerInGroup(targetUid, group.Uid);
|
||||||
|
CommandListener.PendingLoads.Remove(targetUid);
|
||||||
|
PendingActions.Remove(targetUid);
|
||||||
|
|
||||||
|
return TextCommandResult.Success(
|
||||||
|
$"Unlinked all claims of {targetName} from '{groupName}'."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public static TextCommandResult AdminTransferOwnership(TextCommandCallingArgs args)
|
public static TextCommandResult AdminTransferOwnership(TextCommandCallingArgs args)
|
||||||
{
|
{
|
||||||
string groupName = (string)args[0];
|
|
||||||
|
|
||||||
TextCommandResult? err = TryResolveTargetPlayer(
|
TextCommandResult? err = TryResolveTargetPlayer(
|
||||||
(PlayerUidName[])args[1],
|
(PlayerUidName[])args[0],
|
||||||
out IPlayer target
|
out IPlayer target
|
||||||
);
|
);
|
||||||
if (err != null)
|
if (err != null)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = TryResolveGroup(groupName, out PlayerGroup group);
|
err = TryResolveGroupArg(args, 1, out PlayerGroup group);
|
||||||
if (err != null)
|
if (err != null)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -659,9 +886,6 @@ public static class ClaimLinkChatCommand
|
|||||||
return ExecuteTransferOwnership(group, target);
|
return ExecuteTransferOwnership(group, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextCommandResult AdminInfo(TextCommandCallingArgs args) =>
|
|
||||||
TextCommandResult.Success("stub: claimlink admin info");
|
|
||||||
|
|
||||||
internal static void OnPlayerDisconnect(IServerPlayer player)
|
internal static void OnPlayerDisconnect(IServerPlayer player)
|
||||||
{
|
{
|
||||||
PendingActions.Remove(player.PlayerUID);
|
PendingActions.Remove(player.PlayerUID);
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ public class ClaimLinkModSystem : ModSystem
|
|||||||
internal static IGroupManager Groups = null!;
|
internal static IGroupManager Groups = null!;
|
||||||
internal static IWorldAccessor World = null!;
|
internal static IWorldAccessor World = null!;
|
||||||
internal static IPlayerDataManager PlayerData = null!;
|
internal static IPlayerDataManager PlayerData = null!;
|
||||||
internal ClaimLinkCommandListener? CmdListener;
|
internal CommandListener? CmdListener;
|
||||||
|
internal GroupCommandListener? GroupCmdListener;
|
||||||
|
|
||||||
public override bool ShouldLoad(EnumAppSide forSide) => forSide == EnumAppSide.Server;
|
public override bool ShouldLoad(EnumAppSide forSide) => forSide == EnumAppSide.Server;
|
||||||
|
|
||||||
@@ -26,11 +27,14 @@ public class ClaimLinkModSystem : ModSystem
|
|||||||
PlayerData = api.PlayerData;
|
PlayerData = api.PlayerData;
|
||||||
Registry = new ClaimLinkRegistry(api.WorldManager.SaveGame);
|
Registry = new ClaimLinkRegistry(api.WorldManager.SaveGame);
|
||||||
|
|
||||||
CmdListener = new ClaimLinkCommandListener();
|
CmdListener = new CommandListener();
|
||||||
CommandHookModSystem.Register(CmdListener);
|
CommandHookModSystem.Register(CmdListener);
|
||||||
|
GroupCmdListener = new GroupCommandListener();
|
||||||
|
CommandHookModSystem.Register(GroupCmdListener);
|
||||||
ClaimLinkChatCommand.Register(api);
|
ClaimLinkChatCommand.Register(api);
|
||||||
|
|
||||||
api.Event.PlayerDisconnect += ClaimLinkCommandListener.OnPlayerDisconnect;
|
api.Event.PlayerDisconnect += CommandListener.OnPlayerDisconnect;
|
||||||
|
api.Event.PlayerDisconnect += GroupCommandListener.OnPlayerDisconnect;
|
||||||
api.Event.PlayerDisconnect += ClaimLinkChatCommand.OnPlayerDisconnect;
|
api.Event.PlayerDisconnect += ClaimLinkChatCommand.OnPlayerDisconnect;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,6 +42,8 @@ public class ClaimLinkModSystem : ModSystem
|
|||||||
{
|
{
|
||||||
if (CmdListener != null)
|
if (CmdListener != null)
|
||||||
CommandHookModSystem.Unregister(CmdListener);
|
CommandHookModSystem.Unregister(CmdListener);
|
||||||
|
if (GroupCmdListener != null)
|
||||||
|
CommandHookModSystem.Unregister(GroupCmdListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<(int claimIndex, LandClaim claim)> EnumerateOwnedClaims(
|
private static IEnumerable<(int claimIndex, LandClaim claim)> EnumerateOwnedClaims(
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class ClaimLinkRegistry
|
|||||||
|
|
||||||
public bool AddEntry(string uid, int groupId, int claimIndex)
|
public bool AddEntry(string uid, int groupId, int claimIndex)
|
||||||
{
|
{
|
||||||
if (ClaimLinkCommandListener.PendingLoads.ContainsKey(uid))
|
if (CommandListener.PendingLoads.ContainsKey(uid))
|
||||||
return false;
|
return false;
|
||||||
if (!Exists(groupId))
|
if (!Exists(groupId))
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -0,0 +1,307 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using CommandHook;
|
||||||
|
using Vintagestory.API.Common;
|
||||||
|
using Vintagestory.API.Server;
|
||||||
|
|
||||||
|
namespace ClaimLink;
|
||||||
|
|
||||||
|
public class CommandListener : ICommandHookListener
|
||||||
|
{
|
||||||
|
public string ModId => "claimlink";
|
||||||
|
|
||||||
|
public IReadOnlyList<string> Commands => new[] { "land" };
|
||||||
|
|
||||||
|
public CommandRegistration Registration => new(Before, After);
|
||||||
|
|
||||||
|
internal static Dictionary<string, int> PendingLoads = new Dictionary<string, int>();
|
||||||
|
|
||||||
|
private delegate void SubHandler(Caller caller, CmdArgs args);
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, SubHandler> topLevel = new()
|
||||||
|
{
|
||||||
|
["claim"] = Claim,
|
||||||
|
["free"] = Free,
|
||||||
|
["adminfree"] = AdminFree,
|
||||||
|
["adminfreehere"] = AdminFreeHere,
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, SubHandler> claimSub = new()
|
||||||
|
{
|
||||||
|
["load"] = ClaimLoad,
|
||||||
|
["save"] = ClaimSave,
|
||||||
|
["cancel"] = ClaimCancel,
|
||||||
|
};
|
||||||
|
|
||||||
|
private static void Dispatch(TextCommandCallingArgs args)
|
||||||
|
{
|
||||||
|
CmdArgs rawArgs = args.RawArgs.Clone();
|
||||||
|
|
||||||
|
while (rawArgs.Length > 0)
|
||||||
|
{
|
||||||
|
string word = rawArgs.PeekWord();
|
||||||
|
|
||||||
|
if (topLevel.TryGetValue(word, out SubHandler? handler))
|
||||||
|
{
|
||||||
|
rawArgs.PopWord();
|
||||||
|
handler(args.Caller, rawArgs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rawArgs.PopWord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TextCommandResult? Before(TextCommandCallingArgs args)
|
||||||
|
{
|
||||||
|
Dispatch(args);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void After(TextCommandCallingArgs args, TextCommandResult result) { }
|
||||||
|
|
||||||
|
private static void Claim(Caller caller, CmdArgs args)
|
||||||
|
{
|
||||||
|
string? word = args.PeekWord();
|
||||||
|
if (word == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (claimSub.TryGetValue(word, out SubHandler? handler))
|
||||||
|
{
|
||||||
|
args.PopWord();
|
||||||
|
handler(caller, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ClaimSave(Caller caller, CmdArgs args)
|
||||||
|
{
|
||||||
|
if (caller.Player == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string uid = caller.Player.PlayerUID;
|
||||||
|
if (!PendingLoads.TryGetValue(uid, out int pendingIndex))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ClaimLinkModSystem.Registry.ClaimSaved(uid, pendingIndex);
|
||||||
|
PendingLoads.Remove(uid);
|
||||||
|
ClaimLinkChatCommand.PendingActions.Remove(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ClaimLoad(Caller caller, CmdArgs args)
|
||||||
|
{
|
||||||
|
int? claimIndex = args.PopInt();
|
||||||
|
if (caller.Player == null || claimIndex == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (
|
||||||
|
ClaimLinkModSystem.TryResolveOwnedClaim(caller.Player.PlayerUID, (int)claimIndex, out _)
|
||||||
|
)
|
||||||
|
PendingLoads[caller.Player.PlayerUID] = (int)claimIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ClaimCancel(Caller caller, CmdArgs args)
|
||||||
|
{
|
||||||
|
if (caller.Player == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PendingLoads.Remove(caller.Player.PlayerUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Free(Caller caller, CmdArgs args)
|
||||||
|
{
|
||||||
|
if (caller.Player == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string uid = caller.Player.PlayerUID;
|
||||||
|
int? claimIndex = args.PopInt();
|
||||||
|
if (claimIndex == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (args.PopWord() != "confirm")
|
||||||
|
return;
|
||||||
|
|
||||||
|
ClaimLinkModSystem.Registry.ClaimRemoved(uid, (int)claimIndex);
|
||||||
|
ClaimLinkChatCommand.PendingActions.Remove(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AdminFree(Caller caller, CmdArgs args)
|
||||||
|
{
|
||||||
|
if (caller.Player == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string? name = args.PopWord();
|
||||||
|
if (name == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string? uid = ClaimLinkModSystem.PlayerData.GetPlayerDataByLastKnownName(name)?.PlayerUID;
|
||||||
|
if (uid == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ClaimLinkModSystem.Registry.ClearAllForPlayer(uid);
|
||||||
|
ClaimLinkChatCommand.PendingActions.Remove(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AdminFreeHere(Caller caller, CmdArgs args)
|
||||||
|
{
|
||||||
|
if (caller.Player == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LandClaim[] claims = ClaimLinkModSystem.LandClaimAPI.Get(
|
||||||
|
caller.Player.Entity.Pos.AsBlockPos
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach (LandClaim c in claims)
|
||||||
|
if (ClaimLinkModSystem.TryResolveClaimIndex(c.OwnedByPlayerUid, c, out int claimIndex))
|
||||||
|
{
|
||||||
|
ClaimLinkModSystem.Registry.ClaimRemoved(c.OwnedByPlayerUid, claimIndex);
|
||||||
|
ClaimLinkChatCommand.PendingActions.Remove(c.OwnedByPlayerUid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void OnPlayerDisconnect(IServerPlayer player)
|
||||||
|
{
|
||||||
|
PendingLoads.Remove(player.PlayerUID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GroupCommandListener : ICommandHookListener
|
||||||
|
{
|
||||||
|
public string ModId => "claimlink.group";
|
||||||
|
|
||||||
|
public IReadOnlyList<string> Commands => new[] { "group" };
|
||||||
|
|
||||||
|
public CommandRegistration Registration => new(Before, After);
|
||||||
|
|
||||||
|
internal static Dictionary<string, int> PendingDisbands = new Dictionary<string, int>();
|
||||||
|
internal static Dictionary<string, (string AffectedUid, int GroupId)> PendingMembershipChecks =
|
||||||
|
new Dictionary<string, (string, int)>();
|
||||||
|
|
||||||
|
private TextCommandResult? Before(TextCommandCallingArgs args)
|
||||||
|
{
|
||||||
|
if (args.Caller.Player == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
string callerUid = args.Caller.Player.PlayerUID;
|
||||||
|
CmdArgs rawArgs = args.RawArgs.Clone();
|
||||||
|
string? word = rawArgs.PopWord();
|
||||||
|
|
||||||
|
switch (word)
|
||||||
|
{
|
||||||
|
case "confirmdisband":
|
||||||
|
ConfirmDisband(args, callerUid, rawArgs);
|
||||||
|
break;
|
||||||
|
case "leave":
|
||||||
|
Leave(args, callerUid, rawArgs);
|
||||||
|
break;
|
||||||
|
case "kick":
|
||||||
|
Kick(args, callerUid, rawArgs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ConfirmDisband(
|
||||||
|
TextCommandCallingArgs args,
|
||||||
|
string callerUid,
|
||||||
|
CmdArgs rawArgs
|
||||||
|
)
|
||||||
|
{
|
||||||
|
string? name = rawArgs.PopWord();
|
||||||
|
int? groupId =
|
||||||
|
name != null
|
||||||
|
? ClaimLinkModSystem.Groups.GetPlayerGroupByName(name)?.Uid
|
||||||
|
: args.Caller.FromChatGroupId;
|
||||||
|
|
||||||
|
if (groupId != null)
|
||||||
|
PendingDisbands[callerUid] = (int)groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Leave(TextCommandCallingArgs args, string callerUid, CmdArgs rawArgs)
|
||||||
|
{
|
||||||
|
string? name = rawArgs.PopWord();
|
||||||
|
int? groupId =
|
||||||
|
name != null
|
||||||
|
? ClaimLinkModSystem.Groups.GetPlayerGroupByName(name)?.Uid
|
||||||
|
: args.Caller.FromChatGroupId;
|
||||||
|
|
||||||
|
if (groupId != null)
|
||||||
|
PendingMembershipChecks[callerUid] = (callerUid, (int)groupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Kick(TextCommandCallingArgs args, string callerUid, CmdArgs rawArgs)
|
||||||
|
{
|
||||||
|
string? word1 = rawArgs.PopWord();
|
||||||
|
string? word2 = rawArgs.PopWord();
|
||||||
|
|
||||||
|
string? targetName;
|
||||||
|
int? groupId;
|
||||||
|
if (word2 != null)
|
||||||
|
{
|
||||||
|
groupId =
|
||||||
|
word1 != null ? ClaimLinkModSystem.Groups.GetPlayerGroupByName(word1)?.Uid : null;
|
||||||
|
targetName = word2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
targetName = word1;
|
||||||
|
groupId = args.Caller.FromChatGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetName == null || groupId == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string? targetUid = ClaimLinkModSystem
|
||||||
|
.PlayerData.GetPlayerDataByLastKnownName(targetName)
|
||||||
|
?.PlayerUID;
|
||||||
|
if (targetUid != null)
|
||||||
|
PendingMembershipChecks[callerUid] = (targetUid, (int)groupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void After(TextCommandCallingArgs args, TextCommandResult result)
|
||||||
|
{
|
||||||
|
if (args.Caller.Player == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string callerUid = args.Caller.Player.PlayerUID;
|
||||||
|
|
||||||
|
if (PendingDisbands.TryGetValue(callerUid, out int disbandedGroupId))
|
||||||
|
{
|
||||||
|
PendingDisbands.Remove(callerUid);
|
||||||
|
|
||||||
|
if (!ClaimLinkModSystem.Groups.PlayerGroupsById.ContainsKey(disbandedGroupId))
|
||||||
|
{
|
||||||
|
ClaimLinkChatCommand.RemovePendingActionsForGroup(
|
||||||
|
disbandedGroupId,
|
||||||
|
"group no longer exists"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ClaimLinkModSystem.Registry.Exists(disbandedGroupId))
|
||||||
|
ClaimLinkModSystem.Registry.Remove(disbandedGroupId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PendingMembershipChecks.TryGetValue(callerUid, out var check))
|
||||||
|
{
|
||||||
|
PendingMembershipChecks.Remove(callerUid);
|
||||||
|
|
||||||
|
bool stillMember =
|
||||||
|
ClaimLinkModSystem
|
||||||
|
.PlayerData.GetPlayerDataByUid(check.AffectedUid)
|
||||||
|
?.PlayerGroupMemberships.ContainsKey(check.GroupId) == true;
|
||||||
|
|
||||||
|
if (!stillMember)
|
||||||
|
ClaimLinkChatCommand.CancelPendingAction(
|
||||||
|
check.AffectedUid,
|
||||||
|
check.GroupId,
|
||||||
|
"you are no longer a member of the group"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void OnPlayerDisconnect(IServerPlayer player)
|
||||||
|
{
|
||||||
|
PendingDisbands.Remove(player.PlayerUID);
|
||||||
|
PendingMembershipChecks.Remove(player.PlayerUID);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using CommandHook;
|
|
||||||
using Vintagestory.API.Common;
|
|
||||||
using Vintagestory.API.Server;
|
|
||||||
|
|
||||||
namespace ClaimLink;
|
|
||||||
|
|
||||||
public class ClaimLinkCommandListener : ICommandHookListener
|
|
||||||
{
|
|
||||||
public string ModId => "claimlink";
|
|
||||||
|
|
||||||
public IReadOnlyList<string> Commands => new[] { "land" };
|
|
||||||
|
|
||||||
public CommandRegistration Registration => new(Before, After);
|
|
||||||
|
|
||||||
internal static Dictionary<string, int> PendingLoads = new Dictionary<string, int>();
|
|
||||||
|
|
||||||
private delegate void SubHandler(Caller caller, CmdArgs args);
|
|
||||||
|
|
||||||
private static readonly Dictionary<string, SubHandler> topLevel = new()
|
|
||||||
{
|
|
||||||
["claim"] = Claim,
|
|
||||||
["free"] = Free,
|
|
||||||
["adminfree"] = AdminFree,
|
|
||||||
["adminfreehere"] = AdminFreeHere,
|
|
||||||
};
|
|
||||||
|
|
||||||
private static readonly Dictionary<string, SubHandler> claimSub = new()
|
|
||||||
{
|
|
||||||
["load"] = ClaimLoad,
|
|
||||||
["save"] = ClaimSave,
|
|
||||||
["cancel"] = ClaimCancel,
|
|
||||||
};
|
|
||||||
|
|
||||||
private static void Dispatch(TextCommandCallingArgs args)
|
|
||||||
{
|
|
||||||
CmdArgs rawArgs = args.RawArgs.Clone();
|
|
||||||
|
|
||||||
while (rawArgs.Length > 0)
|
|
||||||
{
|
|
||||||
string word = rawArgs.PeekWord();
|
|
||||||
|
|
||||||
if (topLevel.TryGetValue(word, out SubHandler? handler))
|
|
||||||
{
|
|
||||||
rawArgs.PopWord();
|
|
||||||
handler(args.Caller, rawArgs);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rawArgs.PopWord();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private TextCommandResult? Before(TextCommandCallingArgs args)
|
|
||||||
{
|
|
||||||
Dispatch(args);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void After(TextCommandCallingArgs args, TextCommandResult result) { }
|
|
||||||
|
|
||||||
private static void Claim(Caller caller, CmdArgs args)
|
|
||||||
{
|
|
||||||
string? word = args.PeekWord();
|
|
||||||
if (word == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (claimSub.TryGetValue(word, out SubHandler? handler))
|
|
||||||
{
|
|
||||||
args.PopWord();
|
|
||||||
handler(caller, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ClaimSave(Caller caller, CmdArgs args)
|
|
||||||
{
|
|
||||||
if (caller.Player == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
string uid = caller.Player.PlayerUID;
|
|
||||||
if (!PendingLoads.TryGetValue(uid, out int pendingIndex))
|
|
||||||
return;
|
|
||||||
|
|
||||||
ClaimLinkModSystem.Registry.ClaimSaved(uid, pendingIndex);
|
|
||||||
PendingLoads.Remove(uid);
|
|
||||||
ClaimLinkChatCommand.PendingActions.Remove(uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ClaimLoad(Caller caller, CmdArgs args)
|
|
||||||
{
|
|
||||||
int? claimIndex = args.PopInt();
|
|
||||||
if (caller.Player == null || claimIndex == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (
|
|
||||||
ClaimLinkModSystem.TryResolveOwnedClaim(caller.Player.PlayerUID, (int)claimIndex, out _)
|
|
||||||
)
|
|
||||||
PendingLoads[caller.Player.PlayerUID] = (int)claimIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ClaimCancel(Caller caller, CmdArgs args)
|
|
||||||
{
|
|
||||||
if (caller.Player == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
PendingLoads.Remove(caller.Player.PlayerUID);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void Free(Caller caller, CmdArgs args)
|
|
||||||
{
|
|
||||||
if (caller.Player == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
string uid = caller.Player.PlayerUID;
|
|
||||||
int? claimIndex = args.PopInt();
|
|
||||||
if (claimIndex == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (args.PopWord() != "confirm")
|
|
||||||
return;
|
|
||||||
|
|
||||||
ClaimLinkModSystem.Registry.ClaimRemoved(uid, (int)claimIndex);
|
|
||||||
ClaimLinkChatCommand.PendingActions.Remove(uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void AdminFree(Caller caller, CmdArgs args)
|
|
||||||
{
|
|
||||||
if (caller.Player == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
string? name = args.PopWord();
|
|
||||||
if (name == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
string? uid = ClaimLinkModSystem.PlayerData.GetPlayerDataByLastKnownName(name)?.PlayerUID;
|
|
||||||
if (uid == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ClaimLinkModSystem.Registry.ClearAllForPlayer(uid);
|
|
||||||
ClaimLinkChatCommand.PendingActions.Remove(uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void AdminFreeHere(Caller caller, CmdArgs args)
|
|
||||||
{
|
|
||||||
if (caller.Player == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
LandClaim[] claims = ClaimLinkModSystem.LandClaimAPI.Get(
|
|
||||||
caller.Player.Entity.Pos.AsBlockPos
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach (LandClaim c in claims)
|
|
||||||
if (ClaimLinkModSystem.TryResolveClaimIndex(c.OwnedByPlayerUid, c, out int claimIndex))
|
|
||||||
{
|
|
||||||
ClaimLinkModSystem.Registry.ClaimRemoved(c.OwnedByPlayerUid, claimIndex);
|
|
||||||
ClaimLinkChatCommand.PendingActions.Remove(c.OwnedByPlayerUid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void OnPlayerDisconnect(IServerPlayer player)
|
|
||||||
{
|
|
||||||
PendingLoads.Remove(player.PlayerUID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,9 +8,9 @@
|
|||||||
"anth64"
|
"anth64"
|
||||||
],
|
],
|
||||||
"description": "Link claims together with groups.",
|
"description": "Link claims together with groups.",
|
||||||
"version": "0.0.6",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"game": "1.22.3",
|
"game": "1.22.5",
|
||||||
"commandhook": "2.1.0"
|
"commandhook": "2.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user