Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
979f02e7f8 | ||
|
|
acbc45483e | ||
|
|
4e97e25b38 | ||
|
|
1803aaaa37 | ||
|
|
c035bf1a73 | ||
|
|
565f91408b | ||
|
|
e7118e259b | ||
|
|
65e00e2f57 | ||
|
|
c7e3f97a85 | ||
|
|
0914d55d9a | ||
|
|
ac79d2ac94 | ||
|
|
3b6a44a779 | ||
|
|
deafd98f40 | ||
|
|
3b63c5b4af | ||
|
|
cf17697a5e | ||
|
|
02c9a22bf1 |
@@ -0,0 +1,24 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using ProtoBuf;
|
||||||
|
|
||||||
|
namespace ClaimLink;
|
||||||
|
|
||||||
|
[ProtoContract]
|
||||||
|
public class ClaimLinkMember
|
||||||
|
{
|
||||||
|
[ProtoMember(1)]
|
||||||
|
public string OwnerPlayerUid = "";
|
||||||
|
|
||||||
|
[ProtoMember(2)]
|
||||||
|
public List<int> LocalClaimIndices = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
[ProtoContract]
|
||||||
|
public class ClaimLink
|
||||||
|
{
|
||||||
|
[ProtoMember(1)]
|
||||||
|
public int GroupId;
|
||||||
|
|
||||||
|
[ProtoMember(2)]
|
||||||
|
public List<ClaimLinkMember> Members = new();
|
||||||
|
}
|
||||||
@@ -16,6 +16,10 @@
|
|||||||
<HintPath>$(COMMANDHOOK)/CommandHook.dll</HintPath>
|
<HintPath>$(COMMANDHOOK)/CommandHook.dll</HintPath>
|
||||||
<Private>false</Private>
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="protobuf-net">
|
||||||
|
<HintPath>$(VINTAGE_STORY)/Lib/protobuf-net.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using Vintagestory.API.Common;
|
using Vintagestory.API.Common;
|
||||||
using Vintagestory.API.Server;
|
using Vintagestory.API.Server;
|
||||||
|
|
||||||
@@ -49,61 +52,64 @@ public static class ClaimLinkChatCommand
|
|||||||
|
|
||||||
var root = api.ChatCommands.Create("claimlink")
|
var root = api.ChatCommands.Create("claimlink")
|
||||||
.WithAlias("clink", "claiml", "cl")
|
.WithAlias("clink", "claiml", "cl")
|
||||||
.WithDescription("Link vanilla land claims into shared, derived protective territory.")
|
.WithDescription("Link vanilla land claims together via group.")
|
||||||
.RequiresPrivilege(Privilege.chat);
|
.RequiresPrivilege(Privilege.chat);
|
||||||
|
|
||||||
CommandSpec[] playerCommands =
|
CommandSpec[] playerCommands =
|
||||||
{
|
{
|
||||||
new(new[] { "new", "n" }, "Promote a group you own into a claim link (enters pending state).",
|
new(new[] { "new", "n" }, "Promote a group you own to a claim link.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname") }, true, New),
|
new ICommandArgumentParser[] { p.Word("groupname") }, true, New),
|
||||||
|
|
||||||
new(new[] { "link", "l" }, "Link a claim you own into the pending or committed claim link.",
|
new(new[] { "link", "l" }, "Link a claim you own to a claim link.",
|
||||||
new ICommandArgumentParser[] { p.Word("claim") }, true, Link),
|
new ICommandArgumentParser[] { p.Word("groupname"), p.IntRange("claim", 0, 999) }, true, Link),
|
||||||
|
|
||||||
new(new[] { "confirm", "c" }, "Commit your pending claim link.",
|
new(new[] { "confirm", "c" }, "Confirm pending action.",
|
||||||
Array.Empty<ICommandArgumentParser>(), true, Confirm),
|
Array.Empty<ICommandArgumentParser>(), true, Confirm),
|
||||||
|
|
||||||
new(new[] { "cancel" }, "Discard your pending claim link.",
|
new(new[] { "cancel" }, "Cancel pending action.",
|
||||||
Array.Empty<ICommandArgumentParser>(), true, Cancel),
|
Array.Empty<ICommandArgumentParser>(), true, Cancel),
|
||||||
|
|
||||||
new(new[] { "unlink", "ul" }, "Remove a claim you own from its claim link.",
|
new(new[] { "unlink", "ul" }, "Remove a claim you own from its claim link.",
|
||||||
new ICommandArgumentParser[] { p.Word("claim") }, true, Unlink),
|
new ICommandArgumentParser[] { p.IntRange("claim", 0, 999) }, true, Unlink),
|
||||||
|
|
||||||
new(new[] { "kick" }, "Force-unlink another player's claim from the link (Owner/Op).",
|
new(new[] { "kick" }, "Force-unlink all of a player's claims from the claim link.",
|
||||||
new ICommandArgumentParser[] { p.OnlinePlayer("playername"), p.Word("claim") }, true, Kick),
|
new ICommandArgumentParser[] { p.Word("groupname"), p.OnlinePlayer("playername") }, true, Kick),
|
||||||
|
|
||||||
new(new[] { "delete" }, "Delete the claim link entirely (Owner).",
|
new(new[] { "delete" }, "Delete a claim link.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname") }, true, Delete),
|
new ICommandArgumentParser[] { p.Word("groupname") }, true, Delete),
|
||||||
|
|
||||||
new(new[] { "transferownership", "transfer", "to" }, "Transfer ownership of the claim link to another player (Owner).",
|
new(new[] { "transferownership", "transfer", "to" }, "Transfer ownership of the claim link to another player.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname"), p.OnlinePlayer("playername") }, true, TransferOwnership),
|
new ICommandArgumentParser[] { p.Word("groupname"), p.OnlinePlayer("playername") }, true, TransferOwnership),
|
||||||
|
|
||||||
new(new[] { "info", "i" }, "Show a claim link's linked claims, members, and territory (Owner/Op or admin).",
|
new(new[] { "info", "i" }, "Show a claim link's members and linked claims.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname") }, true, Info),
|
new ICommandArgumentParser[] { p.Word("groupname") }, true, Info),
|
||||||
|
|
||||||
|
new(new[] { "list", "ls" }, "List all claim links.",
|
||||||
|
Array.Empty<ICommandArgumentParser>(), true, List),
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var spec in playerCommands)
|
foreach (var spec in playerCommands)
|
||||||
BuildSubCommand(root, spec);
|
BuildSubCommand(root, spec);
|
||||||
|
|
||||||
var admin = root.BeginSubCommands("admin", "a")
|
var admin = root.BeginSubCommands("admin", "a")
|
||||||
.WithDescription("Admin management for any claim link (op or console).")
|
.WithDescription("Admin commands for claim link.")
|
||||||
.RequiresPrivilege(Privilege.controlserver);
|
.RequiresPrivilege(Privilege.controlserver);
|
||||||
|
|
||||||
CommandSpec[] adminCommands =
|
CommandSpec[] adminCommands =
|
||||||
{
|
{
|
||||||
new(new[] { "delete", "del" }, "Delete any claim link entirely (claims and group untouched).",
|
new(new[] { "delete", "del" }, "Delete a claim link.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname") }, false, AdminDelete),
|
new ICommandArgumentParser[] { p.Word("groupname") }, false, AdminDelete),
|
||||||
|
|
||||||
new(new[] { "unlink" }, "Force a single claim out of its link by player and claim (claim untouched).",
|
new(new[] { "unlink" }, "Unlink a claim.",
|
||||||
new ICommandArgumentParser[] { p.OnlinePlayer("playername"), p.Word("claim") }, false, AdminUnlink),
|
new ICommandArgumentParser[] { p.OnlinePlayer("playername"), p.Word("claim") }, false, AdminUnlink),
|
||||||
|
|
||||||
new(new[] { "kick" }, "Force-unlink all of a player's claims from a link (claims untouched).",
|
new(new[] { "kick" }, "Force-unlink all of a player's claims.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname"), p.OnlinePlayer("playername") }, false, AdminKick),
|
new ICommandArgumentParser[] { p.Word("groupname"), p.OnlinePlayer("playername") }, false, AdminKick),
|
||||||
|
|
||||||
new(new[] { "transferownership", "transfer", "to" }, "Transfer ownership of any claim link to another player.",
|
new(new[] { "transferownership", "transfer", "to" }, "Transfer ownership of any claim link to another player.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname"), p.OnlinePlayer("playername") }, false, AdminTransferOwnership),
|
new ICommandArgumentParser[] { p.Word("groupname"), p.OnlinePlayer("playername") }, false, AdminTransferOwnership),
|
||||||
|
|
||||||
new(new[] { "info", "i" }, "Show any claim link's linked claims, members, and territory.",
|
new(new[] { "info", "i" }, "Show a claim link's members and linked claims.",
|
||||||
new ICommandArgumentParser[] { p.Word("groupname") }, false, AdminInfo),
|
new ICommandArgumentParser[] { p.Word("groupname") }, false, AdminInfo),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -113,15 +119,266 @@ public static class ClaimLinkChatCommand
|
|||||||
admin.EndSubCommand();
|
admin.EndSubCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextCommandResult New(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlinknew");
|
private static readonly Dictionary<string, Func<TextCommandResult>> pendingActions = new();
|
||||||
public static TextCommandResult Link(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink link");
|
|
||||||
public static TextCommandResult Confirm(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink confirm");
|
internal static void RemovePending(string playerUid) => pendingActions.Remove(playerUid);
|
||||||
public static TextCommandResult Cancel(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink cancel");
|
|
||||||
public static TextCommandResult Unlink(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink unlink");
|
private static TextCommandResult Stage(string playerUid, string prompt, Func<TextCommandResult> action)
|
||||||
public static TextCommandResult Kick(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink kick");
|
{
|
||||||
public static TextCommandResult Delete(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink delete");
|
pendingActions[playerUid] = action;
|
||||||
|
return TextCommandResult.Success($"{prompt} Use /claimlink confirm to proceed, or /claimlink cancel to cancel.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TextCommandResult? TryResolveGroup(string groupName, out PlayerGroup group)
|
||||||
|
{
|
||||||
|
group = ClaimLinkModSystem.Groups.GetPlayerGroupByName(groupName)!;
|
||||||
|
return group == null ? TextCommandResult.Error($"No group named '{groupName}' exists.") : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TextCommandResult? TryResolveClaimLink(PlayerGroup group, out ClaimLink link)
|
||||||
|
{
|
||||||
|
link = ClaimLinkModSystem.Registry.Get(group.Uid)!;
|
||||||
|
return link == null ? TextCommandResult.Error($"'{group.Name}' is not a claim link.") : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TextCommandResult? RequireMember(IPlayer player, PlayerGroup group)
|
||||||
|
{
|
||||||
|
return player.GetGroup(group.Uid) == null ? TextCommandResult.Error($"You are not a member of '{group.Name}'.") : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TextCommandResult? RequireOwner(IPlayer player, PlayerGroup group)
|
||||||
|
{
|
||||||
|
return group.OwnerUID != player.PlayerUID ? TextCommandResult.Error($"You do not own '{group.Name}'.") : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TextCommandResult? RequireOpOrOwner(IPlayer player, PlayerGroup group)
|
||||||
|
{
|
||||||
|
PlayerGroupMembership? membership = player.GetGroup(group.Uid);
|
||||||
|
return membership == null || membership.Level < EnumPlayerGroupMemberShip.Op
|
||||||
|
? TextCommandResult.Error($"You must be an operator of '{group.Name}' to do that.")
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextCommandResult New(TextCommandCallingArgs args)
|
||||||
|
{
|
||||||
|
string groupName = (string)args[0];
|
||||||
|
string playerUid = args.Caller.Player.PlayerUID;
|
||||||
|
|
||||||
|
TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group);
|
||||||
|
if (err != null) return err;
|
||||||
|
|
||||||
|
err = RequireOwner(args.Caller.Player, group);
|
||||||
|
if (err != null) return err;
|
||||||
|
|
||||||
|
if (ClaimLinkModSystem.Registry.Get(group.Uid) != null)
|
||||||
|
return TextCommandResult.Error($"'{groupName}' is already a claim link.");
|
||||||
|
|
||||||
|
int groupId = group.Uid;
|
||||||
|
return Stage(playerUid, $"'{groupName}' will become a claim link.", () =>
|
||||||
|
{
|
||||||
|
ClaimLinkModSystem.Registry.Add(new ClaimLink { GroupId = groupId });
|
||||||
|
return TextCommandResult.Success($"'{groupName}' is now a claim link.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextCommandResult Confirm(TextCommandCallingArgs args)
|
||||||
|
{
|
||||||
|
string playerUid = args.Caller.Player.PlayerUID;
|
||||||
|
|
||||||
|
if (!pendingActions.TryGetValue(playerUid, out Func<TextCommandResult>? action))
|
||||||
|
return TextCommandResult.Error("You do not have a pending action.");
|
||||||
|
|
||||||
|
pendingActions.Remove(playerUid);
|
||||||
|
return action();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextCommandResult Cancel(TextCommandCallingArgs args)
|
||||||
|
{
|
||||||
|
string playerUid = args.Caller.Player.PlayerUID;
|
||||||
|
|
||||||
|
if (!pendingActions.Remove(playerUid))
|
||||||
|
return TextCommandResult.Error("You do not have a pending action.");
|
||||||
|
|
||||||
|
return TextCommandResult.Success("Pending action cancelled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextCommandResult Link(TextCommandCallingArgs args)
|
||||||
|
{
|
||||||
|
string groupName = (string)args[0];
|
||||||
|
int claimIndex = (int)args[1];
|
||||||
|
|
||||||
|
TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group);
|
||||||
|
if (err != null) return err;
|
||||||
|
|
||||||
|
err = TryResolveClaimLink(group, out ClaimLink link);
|
||||||
|
if (err != null) return err;
|
||||||
|
|
||||||
|
IPlayer player = args.Caller.Player;
|
||||||
|
err = RequireMember(player, group);
|
||||||
|
if (err != null) return err;
|
||||||
|
|
||||||
|
string playerUid = player.PlayerUID;
|
||||||
|
|
||||||
|
if (!ClaimLinkModSystem.TryResolveOwnedClaim(playerUid, claimIndex, out _, out _))
|
||||||
|
return TextCommandResult.Error("You do not own that claim.");
|
||||||
|
|
||||||
|
if (ClaimLinkModSystem.Registry.IsClaimLinked(playerUid, claimIndex))
|
||||||
|
return TextCommandResult.Error("That claim is already part of a claim link.");
|
||||||
|
|
||||||
|
string claimDesc = DescribeClaim(playerUid, claimIndex);
|
||||||
|
return Stage(playerUid, $"{claimDesc} will be linked into '{groupName}'.", () =>
|
||||||
|
{
|
||||||
|
ClaimLinkMember? member = link.Members.Find(m => m.OwnerPlayerUid == playerUid);
|
||||||
|
if (member == null)
|
||||||
|
{
|
||||||
|
member = new ClaimLinkMember { OwnerPlayerUid = playerUid };
|
||||||
|
link.Members.Add(member);
|
||||||
|
}
|
||||||
|
|
||||||
|
member.LocalClaimIndices.Add(claimIndex);
|
||||||
|
ClaimLinkModSystem.Registry.Save();
|
||||||
|
|
||||||
|
return TextCommandResult.Success($"Linked {claimDesc} to '{groupName}'.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextCommandResult Unlink(TextCommandCallingArgs args)
|
||||||
|
{
|
||||||
|
int claimIndex = (int)args[0];
|
||||||
|
string playerUid = args.Caller.Player.PlayerUID;
|
||||||
|
|
||||||
|
ClaimLink? link = ClaimLinkModSystem.Registry.FindLinkContaining(playerUid, claimIndex);
|
||||||
|
if (link == null)
|
||||||
|
return TextCommandResult.Error($"Claim {claimIndex} is not linked into any claim link by you.");
|
||||||
|
|
||||||
|
string groupName = ClaimLinkModSystem.Groups.PlayerGroupsById[link.GroupId].Name;
|
||||||
|
string claimDesc = DescribeClaim(playerUid, claimIndex);
|
||||||
|
|
||||||
|
return Stage(playerUid, $"{claimDesc} will be unlinked from '{groupName}'.", () =>
|
||||||
|
{
|
||||||
|
ClaimLinkMember member = link.Members.Find(m => m.OwnerPlayerUid == playerUid)!;
|
||||||
|
member.LocalClaimIndices.Remove(claimIndex);
|
||||||
|
if (member.LocalClaimIndices.Count == 0)
|
||||||
|
link.Members.Remove(member);
|
||||||
|
|
||||||
|
ClaimLinkModSystem.Registry.Save();
|
||||||
|
return TextCommandResult.Success($"Unlinked {claimDesc} from '{groupName}'.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextCommandResult Kick(TextCommandCallingArgs args)
|
||||||
|
{
|
||||||
|
string groupName = (string)args[0];
|
||||||
|
IPlayer target = (IPlayer)args[1];
|
||||||
|
|
||||||
|
TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group);
|
||||||
|
if (err != null) return err;
|
||||||
|
|
||||||
|
err = TryResolveClaimLink(group, out ClaimLink link);
|
||||||
|
if (err != null) return err;
|
||||||
|
|
||||||
|
err = RequireOpOrOwner(args.Caller.Player, group);
|
||||||
|
if (err != null) return err;
|
||||||
|
|
||||||
|
string targetUid = target.PlayerUID;
|
||||||
|
string playerUid = args.Caller.Player.PlayerUID;
|
||||||
|
|
||||||
|
ClaimLinkMember? member = link.Members.Find(m => m.OwnerPlayerUid == targetUid);
|
||||||
|
if (member == null)
|
||||||
|
return TextCommandResult.Error($"{target.PlayerName} has no claims linked in '{groupName}'.");
|
||||||
|
|
||||||
|
return Stage(playerUid, $"All of {target.PlayerName}'s claims will be unlinked from '{groupName}'.", () =>
|
||||||
|
{
|
||||||
|
link.Members.Remove(member);
|
||||||
|
RemovePending(targetUid);
|
||||||
|
ClaimLinkModSystem.Registry.Save();
|
||||||
|
|
||||||
|
return TextCommandResult.Success($"Unlinked all claims of {target.PlayerName} from '{groupName}'.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextCommandResult Delete(TextCommandCallingArgs args)
|
||||||
|
{
|
||||||
|
string groupName = (string)args[0];
|
||||||
|
string playerUid = args.Caller.Player.PlayerUID;
|
||||||
|
|
||||||
|
TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group);
|
||||||
|
if (err != null) return err;
|
||||||
|
|
||||||
|
err = TryResolveClaimLink(group, out ClaimLink link);
|
||||||
|
if (err != null) return err;
|
||||||
|
|
||||||
|
err = RequireOwner(args.Caller.Player, group);
|
||||||
|
if (err != null) return err;
|
||||||
|
|
||||||
|
int groupId = group.Uid;
|
||||||
|
return Stage(playerUid, $"'{groupName}' will be deleted as a claim link.", () =>
|
||||||
|
{
|
||||||
|
foreach (ClaimLinkMember member in link.Members)
|
||||||
|
RemovePending(member.OwnerPlayerUid);
|
||||||
|
|
||||||
|
ClaimLinkModSystem.Registry.Remove(groupId);
|
||||||
|
return TextCommandResult.Success($"'{groupName}' is no longer a claim link.");
|
||||||
|
});
|
||||||
|
}
|
||||||
public static TextCommandResult TransferOwnership(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink transferownership");
|
public static TextCommandResult TransferOwnership(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink transferownership");
|
||||||
public static TextCommandResult Info(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink info");
|
|
||||||
|
public static TextCommandResult Info(TextCommandCallingArgs args)
|
||||||
|
{
|
||||||
|
string groupName = (string)args[0];
|
||||||
|
|
||||||
|
TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group);
|
||||||
|
if (err != null) return err;
|
||||||
|
|
||||||
|
err = TryResolveClaimLink(group, out ClaimLink link);
|
||||||
|
if (err != null) return err;
|
||||||
|
|
||||||
|
return TextCommandResult.Success(FormatInfo(groupName, link));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextCommandResult List(TextCommandCallingArgs args)
|
||||||
|
{
|
||||||
|
List<ClaimLink> links = ClaimLinkModSystem.Registry.All
|
||||||
|
.OrderByDescending(l => l.Members.Count)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (links.Count == 0)
|
||||||
|
return TextCommandResult.Success("There are no claim links.");
|
||||||
|
|
||||||
|
StringBuilder sb = new();
|
||||||
|
sb.AppendLine($"Claim links ({links.Count}):");
|
||||||
|
|
||||||
|
foreach (ClaimLink link in links)
|
||||||
|
{
|
||||||
|
string groupName = ClaimLinkModSystem.Groups.PlayerGroupsById[link.GroupId].Name;
|
||||||
|
sb.AppendLine($" {groupName}: {link.Members.Count} member{(link.Members.Count == 1 ? "" : "s")}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return TextCommandResult.Success(sb.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string DescribeClaim(string ownerPlayerUid, int localIndex)
|
||||||
|
{
|
||||||
|
if (!ClaimLinkModSystem.TryResolveOwnedClaim(ownerPlayerUid, localIndex, out _, out LandClaim? claim) || claim == null)
|
||||||
|
return $"claim {localIndex}";
|
||||||
|
|
||||||
|
return string.IsNullOrEmpty(claim.Description) ? $"claim {localIndex}" : claim.Description;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatInfo(string groupName, ClaimLink link)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new();
|
||||||
|
sb.AppendLine($"Claim link '{groupName}' ({link.Members.Count} member{(link.Members.Count == 1 ? "" : "s")}):");
|
||||||
|
|
||||||
|
foreach (ClaimLinkMember member in link.Members)
|
||||||
|
{
|
||||||
|
string name = ClaimLinkModSystem.World.PlayerByUid(member.OwnerPlayerUid)?.PlayerName ?? member.OwnerPlayerUid;
|
||||||
|
IEnumerable<string> claims = member.LocalClaimIndices.Select(i => DescribeClaim(member.OwnerPlayerUid, i));
|
||||||
|
sb.AppendLine($" {name}: claims [{string.Join(", ", claims)}]");
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
public static TextCommandResult AdminDelete(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink admin delete");
|
public static TextCommandResult AdminDelete(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink admin delete");
|
||||||
public static TextCommandResult AdminUnlink(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink admin unlink");
|
public static TextCommandResult AdminUnlink(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink admin unlink");
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using CommandHook;
|
using System.Collections.Generic;
|
||||||
|
using CommandHook;
|
||||||
using Vintagestory.API.Common;
|
using Vintagestory.API.Common;
|
||||||
using Vintagestory.API.Server;
|
using Vintagestory.API.Server;
|
||||||
|
|
||||||
@@ -6,8 +7,11 @@ namespace ClaimLink;
|
|||||||
|
|
||||||
public class ClaimLinkModSystem : ModSystem
|
public class ClaimLinkModSystem : ModSystem
|
||||||
{
|
{
|
||||||
internal static ILandClaimAPI LandClaimAPI;
|
internal static ILandClaimAPI LandClaimAPI = null!;
|
||||||
internal static ILogger Logger;
|
internal static ILogger Logger = null!;
|
||||||
|
internal static ClaimLinkRegistry Registry = null!;
|
||||||
|
internal static IGroupManager Groups = null!;
|
||||||
|
internal static IWorldAccessor World = null!;
|
||||||
internal ClaimLinkCommandListener? cmdListener;
|
internal ClaimLinkCommandListener? cmdListener;
|
||||||
|
|
||||||
public override bool ShouldLoad(EnumAppSide forSide) => forSide == EnumAppSide.Server;
|
public override bool ShouldLoad(EnumAppSide forSide) => forSide == EnumAppSide.Server;
|
||||||
@@ -16,6 +20,9 @@ public class ClaimLinkModSystem : ModSystem
|
|||||||
{
|
{
|
||||||
LandClaimAPI = api.World.Claims;
|
LandClaimAPI = api.World.Claims;
|
||||||
Logger = api.Logger;
|
Logger = api.Logger;
|
||||||
|
Registry = new ClaimLinkRegistry(api.WorldManager.SaveGame);
|
||||||
|
Groups = api.Groups;
|
||||||
|
World = api.World;
|
||||||
|
|
||||||
cmdListener = new ClaimLinkCommandListener();
|
cmdListener = new ClaimLinkCommandListener();
|
||||||
CommandHookModSystem.Register(cmdListener);
|
CommandHookModSystem.Register(cmdListener);
|
||||||
@@ -29,4 +36,29 @@ public class ClaimLinkModSystem : ModSystem
|
|||||||
if (cmdListener != null)
|
if (cmdListener != null)
|
||||||
CommandHookModSystem.Unregister(cmdListener);
|
CommandHookModSystem.Unregister(cmdListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static bool TryResolveOwnedClaim(string ownerPlayerUid, int localIndex, out int globalIndex, out LandClaim? claim)
|
||||||
|
{
|
||||||
|
globalIndex = -1;
|
||||||
|
claim = null;
|
||||||
|
|
||||||
|
List<LandClaim> claims = LandClaimAPI.All;
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < claims.Count; ++i)
|
||||||
|
{
|
||||||
|
if (claims[i].OwnedByPlayerUid != ownerPlayerUid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (count == localIndex)
|
||||||
|
{
|
||||||
|
globalIndex = i;
|
||||||
|
claim = claims[i];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using ProtoBuf;
|
||||||
|
using Vintagestory.API.Server;
|
||||||
|
|
||||||
|
namespace ClaimLink;
|
||||||
|
|
||||||
|
[ProtoContract]
|
||||||
|
public class ClaimLinkData
|
||||||
|
{
|
||||||
|
[ProtoMember(1)]
|
||||||
|
public List<ClaimLink> Links = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ClaimLinkRegistry
|
||||||
|
{
|
||||||
|
private const string SaveKey = "claimlink:links";
|
||||||
|
|
||||||
|
private readonly ISaveGame saveGame;
|
||||||
|
private readonly Dictionary<int, ClaimLink> byGroupId = new();
|
||||||
|
|
||||||
|
public ClaimLinkRegistry(ISaveGame saveGame)
|
||||||
|
{
|
||||||
|
this.saveGame = saveGame;
|
||||||
|
|
||||||
|
ClaimLinkData? data = saveGame.GetData<ClaimLinkData?>(SaveKey, null);
|
||||||
|
if (data == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (ClaimLink link in data.Links)
|
||||||
|
byGroupId[link.GroupId] = link;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClaimLink? Get(int groupId) => byGroupId.TryGetValue(groupId, out ClaimLink? link) ? link : null;
|
||||||
|
|
||||||
|
public IReadOnlyCollection<ClaimLink> All => byGroupId.Values;
|
||||||
|
|
||||||
|
public void Add(ClaimLink link)
|
||||||
|
{
|
||||||
|
byGroupId[link.GroupId] = link;
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(int groupId)
|
||||||
|
{
|
||||||
|
byGroupId.Remove(groupId);
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsClaimLinked(string ownerPlayerUid, int localIndex) => FindLinkContaining(ownerPlayerUid, localIndex) != null;
|
||||||
|
|
||||||
|
public ClaimLink? FindLinkContaining(string ownerPlayerUid, int localIndex)
|
||||||
|
{
|
||||||
|
foreach (ClaimLink link in byGroupId.Values)
|
||||||
|
foreach (ClaimLinkMember member in link.Members)
|
||||||
|
if (member.OwnerPlayerUid == ownerPlayerUid && member.LocalClaimIndices.Contains(localIndex))
|
||||||
|
return link;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
saveGame.StoreData(SaveKey, new ClaimLinkData { Links = new List<ClaimLink>(byGroupId.Values) });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -55,7 +55,7 @@ public class ClaimLinkCommandListener : ICommandHookListener
|
|||||||
{
|
{
|
||||||
string word = rawArgs.PeekWord();
|
string word = rawArgs.PeekWord();
|
||||||
|
|
||||||
if (topLevel.TryGetValue(word, out SubHandler handler))
|
if (topLevel.TryGetValue(word, out SubHandler? handler))
|
||||||
{
|
{
|
||||||
rawArgs.PopWord();
|
rawArgs.PopWord();
|
||||||
handler(args.Caller, rawArgs);
|
handler(args.Caller, rawArgs);
|
||||||
@@ -77,7 +77,7 @@ public class ClaimLinkCommandListener : ICommandHookListener
|
|||||||
{
|
{
|
||||||
string word = args.PeekWord();
|
string word = args.PeekWord();
|
||||||
|
|
||||||
if (claimSub.TryGetValue(word, out SubHandler handler))
|
if (claimSub.TryGetValue(word, out SubHandler? handler))
|
||||||
{
|
{
|
||||||
args.PopWord();
|
args.PopWord();
|
||||||
handler(caller, args);
|
handler(caller, args);
|
||||||
@@ -93,21 +93,10 @@ public class ClaimLinkCommandListener : ICommandHookListener
|
|||||||
if (claimIndex == null || claimIndex < 0 || claimIndex > 999)
|
if (claimIndex == null || claimIndex < 0 || claimIndex > 999)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
List<LandClaim> claims = ClaimLinkModSystem.LandClaimAPI.All, ownedClaims = new List<LandClaim>();
|
if (!ClaimLinkModSystem.TryResolveOwnedClaim(caller.Player.PlayerUID, (int)claimIndex, out int globalIndex, out _))
|
||||||
List<int> globalIndex = new List<int>();
|
|
||||||
for (int i = 0; i < claims.Count; ++i)
|
|
||||||
{
|
|
||||||
if (claims[i].OwnedByPlayerUid != caller.Player.PlayerUID)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
globalIndex.Add(i);
|
|
||||||
ownedClaims.Add(claims[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (claimIndex >= ownedClaims.Count)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pendingLoads[caller.Player.PlayerUID] = globalIndex[(int)claimIndex];
|
pendingLoads[caller.Player.PlayerUID] = globalIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ClaimCancel(Caller caller, CmdArgs args)
|
private static void ClaimCancel(Caller caller, CmdArgs args)
|
||||||
@@ -142,5 +131,6 @@ public class ClaimLinkCommandListener : ICommandHookListener
|
|||||||
internal static void OnPlayerDisconnect(IServerPlayer player)
|
internal static void OnPlayerDisconnect(IServerPlayer player)
|
||||||
{
|
{
|
||||||
pendingLoads.Remove(player.PlayerUID);
|
pendingLoads.Remove(player.PlayerUID);
|
||||||
|
ClaimLinkChatCommand.RemovePending(player.PlayerUID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"anth64"
|
"anth64"
|
||||||
],
|
],
|
||||||
"description": "Link claims together with groups.",
|
"description": "Link claims together with groups.",
|
||||||
"version": "0.0.2",
|
"version": "0.0.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"game": "1.22.3",
|
"game": "1.22.3",
|
||||||
"commandhook": "2.1.0"
|
"commandhook": "2.1.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user