Compare commits
2
Commits
c1158d50c3
...
a03219c114
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a03219c114 | ||
|
|
095b826178 |
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using ProtoBuf;
|
||||
using Vintagestory.API.Common;
|
||||
|
||||
namespace ClaimLink;
|
||||
|
||||
@@ -11,6 +12,22 @@ public class ClaimLinkSaveData
|
||||
|
||||
[ProtoMember(2)]
|
||||
public List<ClaimLinkEntrySaveData> Entries = new();
|
||||
|
||||
[ProtoMember(3)]
|
||||
public List<ClaimLinkPermissionSaveData> Permissions = new();
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public class ClaimLinkPermissionSaveData
|
||||
{
|
||||
[ProtoMember(1)]
|
||||
public int GroupId;
|
||||
|
||||
[ProtoMember(2)]
|
||||
public Dictionary<string, EnumBlockAccessFlags> PermittedPlayerUids = new();
|
||||
|
||||
[ProtoMember(3)]
|
||||
public Dictionary<int, EnumBlockAccessFlags> PermittedPlayerGroupIds = new();
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
|
||||
@@ -34,4 +34,10 @@
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="assets\**">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
using System.Collections.Generic;
|
||||
using Vintagestory.API.MathTools;
|
||||
|
||||
namespace ClaimLink;
|
||||
|
||||
internal static class ClaimLinkBufferIndex
|
||||
{
|
||||
private static readonly Dictionary<long, HashSet<int>> groupIdsByRegion = new();
|
||||
private static readonly Dictionary<int, List<Cuboidi>> buffersByGroupId = new();
|
||||
|
||||
internal static void Rebuild()
|
||||
{
|
||||
groupIdsByRegion.Clear();
|
||||
buffersByGroupId.Clear();
|
||||
|
||||
int regionSize = ClaimLinkModSystem.WorldManager.RegionSize;
|
||||
if (regionSize <= 0)
|
||||
return;
|
||||
|
||||
foreach (int groupId in ClaimLinkModSystem.Registry.All)
|
||||
{
|
||||
List<Cuboidi> buffers = ClaimLinkBuffer.GetBuffer(groupId);
|
||||
buffersByGroupId[groupId] = buffers;
|
||||
|
||||
HashSet<long> regionKeys = new();
|
||||
foreach (Cuboidi buffer in buffers)
|
||||
{
|
||||
int minRegionX = buffer.MinX / regionSize;
|
||||
int maxRegionX = buffer.MaxX / regionSize;
|
||||
int minRegionZ = buffer.MinZ / regionSize;
|
||||
int maxRegionZ = buffer.MaxZ / regionSize;
|
||||
|
||||
for (int rx = minRegionX; rx <= maxRegionX; rx++)
|
||||
for (int rz = minRegionZ; rz <= maxRegionZ; rz++)
|
||||
regionKeys.Add(ClaimLinkModSystem.WorldManager.MapRegionIndex2D(rx, rz));
|
||||
}
|
||||
|
||||
foreach (long regionKey in regionKeys)
|
||||
{
|
||||
if (!groupIdsByRegion.TryGetValue(regionKey, out HashSet<int>? groupIds))
|
||||
groupIdsByRegion[regionKey] = groupIds = new();
|
||||
groupIds.Add(groupId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static IEnumerable<int> CandidateGroupIds(BlockPos pos)
|
||||
{
|
||||
int regionSize = ClaimLinkModSystem.WorldManager.RegionSize;
|
||||
if (regionSize <= 0)
|
||||
return System.Array.Empty<int>();
|
||||
|
||||
long regionKey = ClaimLinkModSystem.WorldManager.MapRegionIndex2D(
|
||||
pos.X / regionSize,
|
||||
pos.Z / regionSize
|
||||
);
|
||||
|
||||
return groupIdsByRegion.TryGetValue(regionKey, out HashSet<int>? groupIds)
|
||||
? groupIds
|
||||
: System.Array.Empty<int>();
|
||||
}
|
||||
|
||||
internal static List<Cuboidi> CachedBuffer(int groupId) =>
|
||||
buffersByGroupId.TryGetValue(groupId, out List<Cuboidi>? buffers)
|
||||
? buffers
|
||||
: new List<Cuboidi>();
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using Vintagestory.API.Common;
|
||||
using Vintagestory.API.MathTools;
|
||||
using Vintagestory.API.Server;
|
||||
|
||||
namespace ClaimLink;
|
||||
|
||||
internal static class ClaimLinkBufferProtection
|
||||
{
|
||||
internal static void Register(ICoreServerAPI api)
|
||||
{
|
||||
api.Event.CanPlaceOrBreakBlock += OnCanPlaceOrBreakBlock;
|
||||
api.Event.CanUseBlock += OnCanUseBlock;
|
||||
}
|
||||
|
||||
private static bool OnCanUseBlock(IServerPlayer byPlayer, BlockSelection blockSel) =>
|
||||
IsAllowed(byPlayer, blockSel.Position, EnumBlockAccessFlags.Use);
|
||||
|
||||
private static bool OnCanPlaceOrBreakBlock(
|
||||
IServerPlayer byPlayer,
|
||||
BlockSelection blockSel,
|
||||
out string claimant
|
||||
)
|
||||
{
|
||||
bool allowed = IsAllowed(byPlayer, blockSel.Position, EnumBlockAccessFlags.BuildOrBreak);
|
||||
claimant = allowed ? null! : "custommessage-claimlink-buffer-zone";
|
||||
return allowed;
|
||||
}
|
||||
|
||||
private static bool IsAllowed(
|
||||
IServerPlayer byPlayer,
|
||||
BlockPos pos,
|
||||
EnumBlockAccessFlags accessFlag
|
||||
)
|
||||
{
|
||||
bool allowed = true;
|
||||
|
||||
foreach (int groupId in ClaimLinkBufferIndex.CandidateGroupIds(pos))
|
||||
{
|
||||
if (IsMember(byPlayer, groupId))
|
||||
continue;
|
||||
|
||||
foreach (Cuboidi buffer in ClaimLinkBufferIndex.CachedBuffer(groupId))
|
||||
if (
|
||||
buffer.Contains(pos)
|
||||
&& !ClaimLinkModSystem.Registry.HasPermission(groupId, byPlayer, accessFlag)
|
||||
)
|
||||
allowed = false;
|
||||
}
|
||||
|
||||
return allowed || HasClaimAccess(byPlayer, pos, accessFlag);
|
||||
}
|
||||
|
||||
private static bool IsMember(IServerPlayer player, int groupId)
|
||||
{
|
||||
foreach (PlayerGroupMembership membership in player.Groups)
|
||||
if (membership.GroupUid == groupId)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool HasClaimAccess(
|
||||
IServerPlayer player,
|
||||
BlockPos pos,
|
||||
EnumBlockAccessFlags accessFlag
|
||||
)
|
||||
{
|
||||
LandClaim[]? claims = ClaimLinkModSystem.LandClaimAPI.Get(pos);
|
||||
if (claims == null)
|
||||
return false;
|
||||
|
||||
foreach (LandClaim claim in claims)
|
||||
{
|
||||
if (claim.TestPlayerAccess(player, accessFlag) != EnumPlayerAccessResult.Denied)
|
||||
return true;
|
||||
if (accessFlag == EnumBlockAccessFlags.Use && claim.AllowUseEveryone)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -113,6 +113,44 @@ public static class ClaimLinkChatCommand
|
||||
true,
|
||||
Kick
|
||||
),
|
||||
new(
|
||||
new[] { "allow" },
|
||||
"Grant a player access inside the claim link's buffer zone.",
|
||||
new ICommandArgumentParser[]
|
||||
{
|
||||
p.Word("playername"),
|
||||
p.WordRange("access", "use", "build", "all"),
|
||||
p.OptionalWord("groupname"),
|
||||
},
|
||||
true,
|
||||
Allow
|
||||
),
|
||||
new(
|
||||
new[] { "allowgroup" },
|
||||
"Grant a player group access inside the claim link's buffer zone.",
|
||||
new ICommandArgumentParser[]
|
||||
{
|
||||
p.Word("targetgroup"),
|
||||
p.WordRange("access", "use", "build", "all"),
|
||||
p.OptionalWord("groupname"),
|
||||
},
|
||||
true,
|
||||
AllowGroup
|
||||
),
|
||||
new(
|
||||
new[] { "deny" },
|
||||
"Revoke a player's buffer-zone access.",
|
||||
new ICommandArgumentParser[] { p.Word("groupname"), p.OptionalWord("playername") },
|
||||
true,
|
||||
Deny
|
||||
),
|
||||
new(
|
||||
new[] { "denygroup" },
|
||||
"Revoke a player group's buffer-zone access.",
|
||||
new ICommandArgumentParser[] { p.Word("groupname"), p.OptionalWord("targetgroup") },
|
||||
true,
|
||||
DenyGroup
|
||||
),
|
||||
new(
|
||||
new[] { "delete" },
|
||||
"Delete a claim link.",
|
||||
@@ -184,6 +222,44 @@ public static class ClaimLinkChatCommand
|
||||
false,
|
||||
AdminTransferOwnership
|
||||
),
|
||||
new(
|
||||
new[] { "allow" },
|
||||
"Grant a player access inside any claim link's buffer zone.",
|
||||
new ICommandArgumentParser[]
|
||||
{
|
||||
p.Word("playername"),
|
||||
p.WordRange("access", "use", "build", "all"),
|
||||
p.OptionalWord("groupname"),
|
||||
},
|
||||
false,
|
||||
AdminAllow
|
||||
),
|
||||
new(
|
||||
new[] { "allowgroup" },
|
||||
"Grant a player group access inside any claim link's buffer zone.",
|
||||
new ICommandArgumentParser[]
|
||||
{
|
||||
p.Word("targetgroup"),
|
||||
p.WordRange("access", "use", "build", "all"),
|
||||
p.OptionalWord("groupname"),
|
||||
},
|
||||
false,
|
||||
AdminAllowGroup
|
||||
),
|
||||
new(
|
||||
new[] { "deny" },
|
||||
"Revoke a player's buffer-zone access to any claim link.",
|
||||
new ICommandArgumentParser[] { p.Word("groupname"), p.OptionalWord("playername") },
|
||||
false,
|
||||
AdminDeny
|
||||
),
|
||||
new(
|
||||
new[] { "denygroup" },
|
||||
"Revoke a player group's buffer-zone access to any claim link.",
|
||||
new ICommandArgumentParser[] { p.Word("groupname"), p.OptionalWord("targetgroup") },
|
||||
false,
|
||||
AdminDenyGroup
|
||||
),
|
||||
};
|
||||
|
||||
foreach (var spec in adminCommands)
|
||||
@@ -532,6 +608,180 @@ public static class ClaimLinkChatCommand
|
||||
);
|
||||
}
|
||||
|
||||
private static EnumBlockAccessFlags ParseAccess(string word) =>
|
||||
word switch
|
||||
{
|
||||
"use" => EnumBlockAccessFlags.Use,
|
||||
"build" => EnumBlockAccessFlags.BuildOrBreak,
|
||||
_ => EnumBlockAccessFlags.Use | EnumBlockAccessFlags.BuildOrBreak,
|
||||
};
|
||||
|
||||
private static TextCommandResult ExecuteAllow(
|
||||
PlayerGroup group,
|
||||
string targetName,
|
||||
string accessWord
|
||||
)
|
||||
{
|
||||
string? targetUid = ClaimLinkModSystem
|
||||
.PlayerData.GetPlayerDataByLastKnownName(targetName)
|
||||
?.PlayerUID;
|
||||
if (targetUid == null)
|
||||
return TextCommandResult.Error($"No such player '{targetName}'.");
|
||||
|
||||
ClaimLinkModSystem.Registry.GrantPlayer(group.Uid, targetUid, ParseAccess(accessWord));
|
||||
return TextCommandResult.Success(
|
||||
$"Granted {targetName} {accessWord} access to '{group.Name}''s buffer."
|
||||
);
|
||||
}
|
||||
|
||||
private static TextCommandResult ExecuteDeny(PlayerGroup group, string targetName)
|
||||
{
|
||||
string? targetUid = ClaimLinkModSystem
|
||||
.PlayerData.GetPlayerDataByLastKnownName(targetName)
|
||||
?.PlayerUID;
|
||||
if (targetUid == null)
|
||||
return TextCommandResult.Error($"No such player '{targetName}'.");
|
||||
|
||||
return ClaimLinkModSystem.Registry.RevokePlayer(group.Uid, targetUid)
|
||||
? TextCommandResult.Success($"Revoked {targetName}'s buffer access to '{group.Name}'.")
|
||||
: TextCommandResult.Error($"{targetName} has no buffer access granted in '{group.Name}'.");
|
||||
}
|
||||
|
||||
private static TextCommandResult ExecuteAllowGroup(
|
||||
PlayerGroup group,
|
||||
string targetGroupName,
|
||||
string accessWord
|
||||
)
|
||||
{
|
||||
TextCommandResult? err = TryResolveGroup(targetGroupName, out PlayerGroup targetGroup);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
ClaimLinkModSystem.Registry.GrantGroup(group.Uid, targetGroup.Uid, ParseAccess(accessWord));
|
||||
return TextCommandResult.Success(
|
||||
$"Granted group '{targetGroup.Name}' {accessWord} access to '{group.Name}''s buffer."
|
||||
);
|
||||
}
|
||||
|
||||
private static TextCommandResult ExecuteDenyGroup(PlayerGroup group, string targetGroupName)
|
||||
{
|
||||
TextCommandResult? err = TryResolveGroup(targetGroupName, out PlayerGroup targetGroup);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
return ClaimLinkModSystem.Registry.RevokeGroup(group.Uid, targetGroup.Uid)
|
||||
? TextCommandResult.Success(
|
||||
$"Revoked group '{targetGroup.Name}''s buffer access to '{group.Name}'."
|
||||
)
|
||||
: TextCommandResult.Error(
|
||||
$"Group '{targetGroup.Name}' has no buffer access granted in '{group.Name}'."
|
||||
);
|
||||
}
|
||||
|
||||
private static TextCommandResult? ResolveClaimLinkFromWordPair(
|
||||
TextCommandCallingArgs args,
|
||||
out PlayerGroup group,
|
||||
out string targetName
|
||||
)
|
||||
{
|
||||
string word1 = (string)args[0];
|
||||
string? word2 = args.Parsers[1].IsMissing ? null : (string)args[1];
|
||||
|
||||
if (word2 != null)
|
||||
{
|
||||
TextCommandResult? groupErr = TryResolveGroup(word1, out group);
|
||||
targetName = word2;
|
||||
return groupErr;
|
||||
}
|
||||
|
||||
targetName = word1;
|
||||
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;
|
||||
}
|
||||
|
||||
public static TextCommandResult Allow(TextCommandCallingArgs args)
|
||||
{
|
||||
string targetName = (string)args[0];
|
||||
string accessWord = (string)args[1];
|
||||
|
||||
TextCommandResult? err = TryResolveGroupArg(args, 2, out PlayerGroup group);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
err = TryResolveClaimLink(group);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
err = RequireOpOrOwner(args.Caller.Player, group);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
return ExecuteAllow(group, targetName, accessWord);
|
||||
}
|
||||
|
||||
public static TextCommandResult AllowGroup(TextCommandCallingArgs args)
|
||||
{
|
||||
string targetGroupName = (string)args[0];
|
||||
string accessWord = (string)args[1];
|
||||
|
||||
TextCommandResult? err = TryResolveGroupArg(args, 2, out PlayerGroup group);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
err = TryResolveClaimLink(group);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
err = RequireOpOrOwner(args.Caller.Player, group);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
return ExecuteAllowGroup(group, targetGroupName, accessWord);
|
||||
}
|
||||
|
||||
public static TextCommandResult Deny(TextCommandCallingArgs args)
|
||||
{
|
||||
TextCommandResult? err = ResolveClaimLinkFromWordPair(args, out PlayerGroup group, out string targetName);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
err = TryResolveClaimLink(group);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
err = RequireOpOrOwner(args.Caller.Player, group);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
return ExecuteDeny(group, targetName);
|
||||
}
|
||||
|
||||
public static TextCommandResult DenyGroup(TextCommandCallingArgs args)
|
||||
{
|
||||
TextCommandResult? err = ResolveClaimLinkFromWordPair(
|
||||
args,
|
||||
out PlayerGroup group,
|
||||
out string targetGroupName
|
||||
);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
err = TryResolveClaimLink(group);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
err = RequireOpOrOwner(args.Caller.Player, group);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
return ExecuteDenyGroup(group, targetGroupName);
|
||||
}
|
||||
|
||||
public static TextCommandResult Delete(TextCommandCallingArgs args)
|
||||
{
|
||||
string playerUid = args.Caller.Player.PlayerUID;
|
||||
@@ -803,9 +1053,45 @@ public static class ClaimLinkChatCommand
|
||||
sb.AppendLine($" {name}: [{string.Join(", ", claims)}]");
|
||||
}
|
||||
|
||||
if (!showDetails)
|
||||
return sb.ToString();
|
||||
|
||||
var permittedPlayers = ClaimLinkModSystem.Registry.PermittedPlayersForGroup(groupId);
|
||||
var permittedGroups = ClaimLinkModSystem.Registry.PermittedGroupsForGroup(groupId);
|
||||
if (permittedPlayers.Count == 0 && permittedGroups.Count == 0)
|
||||
return sb.ToString();
|
||||
|
||||
sb.AppendLine("Buffer access granted:");
|
||||
foreach (var (uid, flags) in permittedPlayers)
|
||||
{
|
||||
string name = ClaimLinkModSystem.World.PlayerByUid(uid)?.PlayerName ?? uid;
|
||||
sb.AppendLine($" {name}: {DescribeAccess(flags)}");
|
||||
}
|
||||
foreach (var (targetGroupId, flags) in permittedGroups)
|
||||
{
|
||||
string groupLabel = ClaimLinkModSystem.Groups.PlayerGroupsById.TryGetValue(
|
||||
targetGroupId,
|
||||
out PlayerGroup? targetGroup
|
||||
)
|
||||
? targetGroup!.Name
|
||||
: $"group {targetGroupId}";
|
||||
sb.AppendLine($" {groupLabel} (group): {DescribeAccess(flags)}");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string DescribeAccess(EnumBlockAccessFlags flags)
|
||||
{
|
||||
bool use = (flags & EnumBlockAccessFlags.Use) != 0;
|
||||
bool buildOrBreak = (flags & EnumBlockAccessFlags.BuildOrBreak) != 0;
|
||||
if (use && buildOrBreak)
|
||||
return "all";
|
||||
if (buildOrBreak)
|
||||
return "build";
|
||||
return "use";
|
||||
}
|
||||
|
||||
public static TextCommandResult AdminDelete(TextCommandCallingArgs args)
|
||||
{
|
||||
TextCommandResult? err = TryResolveGroupArg(args, 0, out PlayerGroup group);
|
||||
@@ -850,6 +1136,68 @@ public static class ClaimLinkChatCommand
|
||||
);
|
||||
}
|
||||
|
||||
public static TextCommandResult AdminAllow(TextCommandCallingArgs args)
|
||||
{
|
||||
string targetName = (string)args[0];
|
||||
string accessWord = (string)args[1];
|
||||
|
||||
TextCommandResult? err = TryResolveGroupArg(args, 2, out PlayerGroup group);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
err = TryResolveClaimLink(group);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
return ExecuteAllow(group, targetName, accessWord);
|
||||
}
|
||||
|
||||
public static TextCommandResult AdminAllowGroup(TextCommandCallingArgs args)
|
||||
{
|
||||
string targetGroupName = (string)args[0];
|
||||
string accessWord = (string)args[1];
|
||||
|
||||
TextCommandResult? err = TryResolveGroupArg(args, 2, out PlayerGroup group);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
err = TryResolveClaimLink(group);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
return ExecuteAllowGroup(group, targetGroupName, accessWord);
|
||||
}
|
||||
|
||||
public static TextCommandResult AdminDeny(TextCommandCallingArgs args)
|
||||
{
|
||||
TextCommandResult? err = ResolveClaimLinkFromWordPair(args, out PlayerGroup group, out string targetName);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
err = TryResolveClaimLink(group);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
return ExecuteDeny(group, targetName);
|
||||
}
|
||||
|
||||
public static TextCommandResult AdminDenyGroup(TextCommandCallingArgs args)
|
||||
{
|
||||
TextCommandResult? err = ResolveClaimLinkFromWordPair(
|
||||
args,
|
||||
out PlayerGroup group,
|
||||
out string targetGroupName
|
||||
);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
err = TryResolveClaimLink(group);
|
||||
if (err != null)
|
||||
return err;
|
||||
|
||||
return ExecuteDenyGroup(group, targetGroupName);
|
||||
}
|
||||
|
||||
public static TextCommandResult AdminKick(TextCommandCallingArgs args)
|
||||
{
|
||||
string word1 = (string)args[0];
|
||||
|
||||
@@ -12,6 +12,7 @@ public class ClaimLinkModSystem : ModSystem
|
||||
internal static ClaimLinkRegistry Registry = null!;
|
||||
internal static IGroupManager Groups = null!;
|
||||
internal static IWorldAccessor World = null!;
|
||||
internal static IWorldManagerAPI WorldManager = null!;
|
||||
internal static IPlayerDataManager PlayerData = null!;
|
||||
internal static ClaimLinkConfig Config = null!;
|
||||
internal CommandListener? CmdListener;
|
||||
@@ -23,12 +24,15 @@ public class ClaimLinkModSystem : ModSystem
|
||||
{
|
||||
LandClaimAPI = api.World.Claims;
|
||||
World = api.World;
|
||||
WorldManager = api.WorldManager;
|
||||
Groups = api.Groups;
|
||||
Logger = api.Logger;
|
||||
PlayerData = api.PlayerData;
|
||||
Config = api.LoadModConfig<ClaimLinkConfig>("claimlink.json") ?? new ClaimLinkConfig();
|
||||
api.StoreModConfig(Config, "claimlink.json");
|
||||
Registry = new ClaimLinkRegistry(api.WorldManager.SaveGame);
|
||||
ClaimLinkBufferIndex.Rebuild();
|
||||
api.Event.SaveGameLoaded += ClaimLinkBufferIndex.Rebuild;
|
||||
|
||||
CmdListener = new CommandListener();
|
||||
CommandHookModSystem.Register(CmdListener);
|
||||
@@ -36,6 +40,7 @@ public class ClaimLinkModSystem : ModSystem
|
||||
CommandHookModSystem.Register(GroupCmdListener);
|
||||
ClaimLinkChatCommand.Register(api);
|
||||
ClaimLinkVisualizerNetwork.Start(api);
|
||||
ClaimLinkBufferProtection.Register(api);
|
||||
|
||||
api.Event.PlayerDisconnect += CommandListener.OnPlayerDisconnect;
|
||||
api.Event.PlayerDisconnect += GroupCommandListener.OnPlayerDisconnect;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Vintagestory.API.Common;
|
||||
using Vintagestory.API.Server;
|
||||
|
||||
namespace ClaimLink;
|
||||
@@ -7,10 +8,17 @@ public class ClaimLinkRegistry
|
||||
{
|
||||
private const string SaveKey = "claimlink:claimlinkdata";
|
||||
|
||||
private static readonly Dictionary<string, EnumBlockAccessFlags> EmptyPlayerFlags = new();
|
||||
private static readonly Dictionary<int, EnumBlockAccessFlags> EmptyGroupFlags = new();
|
||||
|
||||
private readonly ISaveGame saveGame;
|
||||
|
||||
private readonly List<int> claimLinks = new();
|
||||
private readonly Dictionary<string, Dictionary<int, List<int>>> entries = new();
|
||||
private readonly Dictionary<int, Dictionary<string, EnumBlockAccessFlags>> permittedPlayerUids =
|
||||
new();
|
||||
private readonly Dictionary<int, Dictionary<int, EnumBlockAccessFlags>> permittedPlayerGroupIds =
|
||||
new();
|
||||
|
||||
public ClaimLinkRegistry(ISaveGame saveGame)
|
||||
{
|
||||
@@ -29,6 +37,14 @@ public class ClaimLinkRegistry
|
||||
|
||||
entries[entry.OwnerPlayerUid][entry.GroupId] = new(entry.ClaimIndicies);
|
||||
}
|
||||
|
||||
foreach (var permission in data.Permissions)
|
||||
{
|
||||
if (permission.PermittedPlayerUids.Count > 0)
|
||||
permittedPlayerUids[permission.GroupId] = new(permission.PermittedPlayerUids);
|
||||
if (permission.PermittedPlayerGroupIds.Count > 0)
|
||||
permittedPlayerGroupIds[permission.GroupId] = new(permission.PermittedPlayerGroupIds);
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyList<int> All => claimLinks;
|
||||
@@ -46,10 +62,96 @@ public class ClaimLinkRegistry
|
||||
claimLinks.Remove(groupId);
|
||||
foreach (var groups in entries.Values)
|
||||
groups.Remove(groupId);
|
||||
permittedPlayerUids.Remove(groupId);
|
||||
permittedPlayerGroupIds.Remove(groupId);
|
||||
Prune();
|
||||
Save();
|
||||
}
|
||||
|
||||
public void GrantPlayer(int groupId, string uid, EnumBlockAccessFlags flags)
|
||||
{
|
||||
if (!permittedPlayerUids.TryGetValue(groupId, out var uids))
|
||||
permittedPlayerUids[groupId] = uids = new();
|
||||
uids[uid] = flags;
|
||||
Save();
|
||||
}
|
||||
|
||||
public bool RevokePlayer(int groupId, string uid)
|
||||
{
|
||||
bool removed = permittedPlayerUids.TryGetValue(groupId, out var uids) && uids.Remove(uid);
|
||||
if (!removed)
|
||||
return false;
|
||||
if (uids!.Count == 0)
|
||||
permittedPlayerUids.Remove(groupId);
|
||||
Save();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void GrantGroup(int groupId, int targetGroupId, EnumBlockAccessFlags flags)
|
||||
{
|
||||
if (!permittedPlayerGroupIds.TryGetValue(groupId, out var groups))
|
||||
permittedPlayerGroupIds[groupId] = groups = new();
|
||||
groups[targetGroupId] = flags;
|
||||
Save();
|
||||
}
|
||||
|
||||
public bool RevokeGroup(int groupId, int targetGroupId)
|
||||
{
|
||||
bool removed =
|
||||
permittedPlayerGroupIds.TryGetValue(groupId, out var groups)
|
||||
&& groups.Remove(targetGroupId);
|
||||
if (!removed)
|
||||
return false;
|
||||
if (groups!.Count == 0)
|
||||
permittedPlayerGroupIds.Remove(groupId);
|
||||
Save();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool HasPermission(int groupId, IPlayer player, EnumBlockAccessFlags accessFlag)
|
||||
{
|
||||
if (
|
||||
permittedPlayerUids.TryGetValue(groupId, out var uids)
|
||||
&& uids.TryGetValue(player.PlayerUID, out EnumBlockAccessFlags flags)
|
||||
&& (flags & accessFlag) != 0
|
||||
)
|
||||
return true;
|
||||
|
||||
if (permittedPlayerGroupIds.TryGetValue(groupId, out var groups))
|
||||
foreach (PlayerGroupMembership membership in player.Groups)
|
||||
if (groups.TryGetValue(membership.GroupUid, out flags) && (flags & accessFlag) != 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<string, EnumBlockAccessFlags> PermittedPlayersForGroup(int groupId) =>
|
||||
permittedPlayerUids.TryGetValue(groupId, out var uids) ? uids : EmptyPlayerFlags;
|
||||
|
||||
public IReadOnlyDictionary<int, EnumBlockAccessFlags> PermittedGroupsForGroup(int groupId) =>
|
||||
permittedPlayerGroupIds.TryGetValue(groupId, out var groups) ? groups : EmptyGroupFlags;
|
||||
|
||||
public void RemoveGroupFromAllPermissions(int targetGroupId)
|
||||
{
|
||||
bool changed = false;
|
||||
foreach (var groups in permittedPlayerGroupIds.Values)
|
||||
if (groups.Remove(targetGroupId))
|
||||
changed = true;
|
||||
|
||||
if (!changed)
|
||||
return;
|
||||
|
||||
List<int>? emptyGroupIds = null;
|
||||
foreach (var (groupId, groups) in permittedPlayerGroupIds)
|
||||
if (groups.Count == 0)
|
||||
(emptyGroupIds ??= new()).Add(groupId);
|
||||
if (emptyGroupIds != null)
|
||||
foreach (int groupId in emptyGroupIds)
|
||||
permittedPlayerGroupIds.Remove(groupId);
|
||||
|
||||
Save();
|
||||
}
|
||||
|
||||
public bool IsClaimLinked(string uid, int claimIndex) =>
|
||||
FindGroupContaining(uid, claimIndex) != null;
|
||||
|
||||
@@ -193,9 +295,37 @@ public class ClaimLinkRegistry
|
||||
}
|
||||
);
|
||||
|
||||
var permissionGroupIds = new HashSet<int>();
|
||||
foreach (int groupId in permittedPlayerUids.Keys)
|
||||
permissionGroupIds.Add(groupId);
|
||||
foreach (int groupId in permittedPlayerGroupIds.Keys)
|
||||
permissionGroupIds.Add(groupId);
|
||||
|
||||
var permissionList = new List<ClaimLinkPermissionSaveData>();
|
||||
foreach (int groupId in permissionGroupIds)
|
||||
{
|
||||
permittedPlayerUids.TryGetValue(groupId, out var uids);
|
||||
permittedPlayerGroupIds.TryGetValue(groupId, out var groups);
|
||||
permissionList.Add(
|
||||
new ClaimLinkPermissionSaveData
|
||||
{
|
||||
GroupId = groupId,
|
||||
PermittedPlayerUids = uids != null ? new(uids) : new(),
|
||||
PermittedPlayerGroupIds = groups != null ? new(groups) : new(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
saveGame.StoreData(
|
||||
SaveKey,
|
||||
new ClaimLinkSaveData { Links = claimLinks, Entries = entryList }
|
||||
new ClaimLinkSaveData
|
||||
{
|
||||
Links = claimLinks,
|
||||
Entries = entryList,
|
||||
Permissions = permissionList,
|
||||
}
|
||||
);
|
||||
|
||||
ClaimLinkBufferIndex.Rebuild();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +113,10 @@ public class CommandListener : ICommandHookListener
|
||||
);
|
||||
|
||||
if (!violatesClaimLink && !violatesClaim)
|
||||
{
|
||||
ClaimLinkBufferIndex.Rebuild();
|
||||
return;
|
||||
}
|
||||
|
||||
ClaimLinkModSystem.LandClaimAPI.Remove(savedClaim);
|
||||
|
||||
@@ -387,6 +390,8 @@ public class GroupCommandListener : ICommandHookListener
|
||||
|
||||
if (ClaimLinkModSystem.Registry.Exists(disbandedGroupId))
|
||||
ClaimLinkModSystem.Registry.Remove(disbandedGroupId);
|
||||
|
||||
ClaimLinkModSystem.Registry.RemoveGroupFromAllPermissions(disbandedGroupId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"custommessage-claimlink-buffer-zone": "This area is a claim link buffer zone.",
|
||||
"ingameerror-noprivilege-buildbreak-claimlink-buffer-zone": "This area is a claim link buffer zone."
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
"anth64"
|
||||
],
|
||||
"description": "Link claims together with groups.",
|
||||
"version": "0.3.0",
|
||||
"version": "0.5.0",
|
||||
"dependencies": {
|
||||
"game": "1.22.5",
|
||||
"commandhook": "2.1.0"
|
||||
|
||||
Reference in New Issue
Block a user