public static string ServerSetOwner(ushort x, ushort y, string newOwnerName) { using var tempList = Api.Shared.GetTempList <ILogicObject>(); LandClaimSystem.SharedGetAreasInBounds(new RectangleInt(x, y, 1, 1), tempList, addGracePadding: false); var landClaimsModified = 0; foreach (var area in tempList.AsList()) { var areasGroup = LandClaimSystem.SharedGetLandClaimAreasGroup(area); if (LandClaimAreasGroup.GetPublicState(areasGroup).ServerFaction is not null) { // cannot change an owner of the faction land claim continue; } var privateState = LandClaimArea.GetPrivateState(area); privateState.LandClaimFounder = newOwnerName; privateState.DirectLandOwners.Clear(); privateState.DirectLandOwners.Add(newOwnerName); landClaimsModified++; } return($"Modified {landClaimsModified} land claims"); }
public static void ServerOnObjectLandClaimBuilt( ICharacter byCharacter, IStaticWorldObject landClaimStructure) { if (!(landClaimStructure?.ProtoStaticWorldObject is IProtoObjectLandClaim)) { throw new Exception("Not a land claim structure: " + landClaimStructure); } // create new area for this land claim structure var area = Api.Server.World.CreateLogicObject <LandClaimArea>(); var areaPrivateState = LandClaimArea.GetPrivateState(area); var areaPublicState = LandClaimArea.GetPublicState(area); var founderName = byCharacter.Name; // setup it areaPrivateState.ServerLandClaimWorldObject = landClaimStructure; areaPrivateState.LandClaimFounder = founderName; areaPrivateState.LandOwners = new NetworkSyncList <string>() { founderName }; areaPublicState.Title = founderName; areaPublicState.SetupAreaProperties(areaPrivateState); // set this area to the structure public state landClaimStructure.GetPublicState <ObjectLandClaimPublicState>() .LandClaimAreaObject = area; ServerOnAddLandOwner(area, byCharacter, notify: false); Logger.Important("Land claim area added: " + area); }
private static void ServerResetDecayTimerForLandClaimAreasGroup(ILogicObject areasGroup) { var areasGroupPrivateState = LandClaimAreasGroup.GetPrivateState(areasGroup); var areasGroupPublicState = LandClaimAreasGroup.GetPublicState(areasGroup); var areas = areasGroupPrivateState.ServerLandClaimsAreas; // TODO: it's better to move this code to another place as this property is used in several other places areasGroupPublicState.IsFounderDemoPlayer = ServerGetIsFounderDemoPlayer(areas); // reset the decay timer for all land claim buildings inside this areas group var decayDelayDuration = LandClaimSystem.ServerGetDecayDelayDurationForLandClaimAreas( areas, areasGroupPublicState.IsFounderDemoPlayer, out _); foreach (var area in areas) { var worldObject = LandClaimArea.GetPrivateState(area) .ServerLandClaimWorldObject; StructureDecaySystem.ServerResetDecayTimer( worldObject.GetPrivateState <StructurePrivateState>(), decayDelayDuration); } }
private static bool ServerGetIsFounderDemoPlayer(List <ILogicObject> areas) { var isFounderDemoPlayer = false; foreach (var area in areas) { var areaPrivateState = LandClaimArea.GetPrivateState(area); var landClaimFounder = areaPrivateState.LandClaimFounder; if (string.IsNullOrEmpty(landClaimFounder)) { // there is no founder (transferred to the faction) return(false); } var founder = ServerCharacters.GetPlayerCharacter(landClaimFounder); if (founder.ServerIsDemoVersion) { isFounderDemoPlayer = true; } else { // one of the areas' founder is not a demo player return(false); } } return(isFounderDemoPlayer); }
private static void ServerLoadSystem() { const string key = nameof(LandClaimAreaManager); if (Server.Database.TryGet(key, key, out ILogicObject savedManager)) { Server.World.DestroyObject(savedManager); } serverLandClaimManagerInstance = Server.World.CreateLogicObject <LandClaimAreaManager>(); var publicState = LandClaimAreaManager.GetPublicState(serverLandClaimManagerInstance); publicState.LandClaimAreas = new NetworkSyncList <ILogicObject>(); Server.Database.Set(key, key, serverLandClaimManagerInstance); sharedLandClaimAreas = LandClaimAreaManager.GetPublicState(serverLandClaimManagerInstance) .LandClaimAreas; foreach (var area in sharedLandClaimAreas) { var areaPrivateState = LandClaimArea.GetPrivateState(area); var areaPublicState = LandClaimArea.GetPublicState(area); areaPublicState.SetupAreaProperties(areaPrivateState); } }
public static bool ServerIsVehicleInsideOwnerBase(IDynamicWorldObject vehicle) { var vehicleCurrentBase = LandClaimSystem.SharedGetLandClaimAreasGroup(vehicle.TilePosition); if (vehicleCurrentBase == null) { return(false); } var vehicleOwners = vehicle.GetPrivateState <VehiclePrivateState>().Owners; foreach (var area in LandClaimAreasGroup.GetPrivateState(vehicleCurrentBase).ServerLandClaimsAreas) { var areaOwners = LandClaimArea.GetPrivateState(area).LandOwners; foreach (var ownerName in vehicleOwners) { if (areaOwners.Contains(ownerName, StringComparer.Ordinal)) { return(true); } } } return(false); }
public static bool ServerIsVehicleInsideOwnerBase(IDynamicWorldObject vehicle) { var vehicleCurrentBase = LandClaimSystem.SharedGetLandClaimAreasGroup(vehicle.TilePosition); if (vehicleCurrentBase is null) { return(false); } var vehicleOwners = vehicle.GetPrivateState <VehiclePrivateState>().Owners; foreach (var area in LandClaimAreasGroup.GetPrivateState(vehicleCurrentBase) .ServerLandClaimsAreas) { using var areaOwners = Api.Shared.WrapInTempList( LandClaimArea.GetPrivateState(area) .ServerGetLandOwners()); foreach (var ownerName in vehicleOwners) { if (areaOwners.Contains(ownerName)) { return(true); } } } return(false); }
private static void ServerOnRemoveLandOwner(ILogicObject area, ICharacter removedPlayer) { InteractableStaticWorldObjectHelper.ServerTryAbortInteraction( removedPlayer, LandClaimArea.GetPrivateState(area).ServerLandClaimWorldObject); ServerWorld.ExitPrivateScope(removedPlayer, area); Instance.CallClient(removedPlayer, _ => _.ClientRemote_OnLandOwnerStateChanged(area, false)); }
public ViewModelWindowLandClaim( IStaticWorldObject landClaimWorldObject, ILogicObject area) { this.landClaimWorldObject = landClaimWorldObject; this.privateState = LandClaimArea.GetPrivateState(area); var protoLandClaim = (IProtoObjectLandClaim)landClaimWorldObject.ProtoStaticWorldObject; var canEditOwners = protoLandClaim .SharedCanEditOwners(landClaimWorldObject, ClientCurrentCharacterHelper.Character); this.ViewModelOwnersEditor = new ViewModelWorldObjectOwnersEditor( this.privateState.LandOwners, callbackServerSetOwnersList: ownersList => LandClaimSystem.ClientSetAreaOwners( area, ownersList), title: AccessListTitle + ":", emptyListMessage: AccessListEmpty, canEditOwners: canEditOwners, // exclude founder name ownersListFilter: name => name != this.FounderName, maxOwnersListLength: LandClaimSystemConstants.SharedLandClaimOwnersMax, displayedOwnersNumberAdjustment: -1); this.protoObjectLandClaim = (IProtoObjectLandClaim)this.landClaimWorldObject.ProtoStaticWorldObject; var upgrade = this.protoObjectLandClaim.ConfigUpgrade.Entries.FirstOrDefault(); if (upgrade is not null) { this.ViewModelStructureUpgrade = new ViewModelStructureUpgrade(upgrade); this.ViewModelProtoLandClaimInfoUpgrade = new ViewModelProtoLandClaimInfo( (IProtoObjectLandClaim)upgrade.ProtoStructure); } var objectPublicState = landClaimWorldObject.GetPublicState <ObjectLandClaimPublicState>(); objectPublicState.ClientSubscribe( _ => _.LandClaimAreaObject, _ => this.RefreshSafeStorageAndPowerGrid(), this); this.RefreshSafeStorageAndPowerGrid(); this.ViewModelProtoLandClaimInfoCurrent = new ViewModelProtoLandClaimInfo(this.protoObjectLandClaim); ItemsContainerLandClaimSafeStorage.ClientSafeItemsSlotsCapacityChanged += this.SafeItemsSlotsCapacityChangedHandler; this.RequestDecayInfoTextAsync(); this.ViewModelShieldProtectionControl = new ViewModelShieldProtectionControl( LandClaimSystem.SharedGetLandClaimAreasGroup(area)); }
private void ServerRemote_TransferLandClaimToFactionOwnership(ILogicObject area) { var character = ServerRemoteContext.Character; var areasGroup = SharedGetLandClaimAreasGroup(area); if (LandClaimAreasGroup.GetPublicState(areasGroup).ServerFaction is not null) { // already has a faction (and it's not possible to change the faction) Logger.Warning("The land claim areas group is already transferred to a faction."); return; } FactionSystem.ServerValidateHasAccessRights(character, FactionMemberAccessRights.LandClaimManagement, out var faction); var factionOwnedAreas = SharedEnumerateAllFactionAreas(FactionSystem.SharedGetClanTag(faction)); var claimLimitRemains = FactionConstants.SharedGetFactionLandClaimsLimit( Faction.GetPublicState(faction).Level) - factionOwnedAreas.Count(); claimLimitRemains -= LandClaimAreasGroup.GetPrivateState(areasGroup).ServerLandClaimsAreas.Count; if (claimLimitRemains < 0) { Logger.Warning( "Cannot transfer land claims to the faction as it will exceed the land claims number limit"); return; } Logger.Important("Will transfer land claims to the faction: after upgrade the remaining limit will be " + claimLimitRemains); // verify user has access to the land claim var owner = ServerRemoteContext.Character; if (!Server.World.IsInPrivateScope(area, owner)) { throw new Exception( "Cannot interact with the land claim object as the area is not in private scope: " + area); } if (!LandClaimArea.GetPrivateState(area).ServerGetLandOwners() .Contains(owner.Name)) { throw new Exception("Player is not an owner of the land claim area"); } ServerTransferAreasGroupToFactionOwnership(faction, character, areasGroup); var worldObject = InteractionCheckerSystem.SharedGetCurrentInteraction(character); InteractableWorldObjectHelper.ServerTryAbortInteraction(character, worldObject); }
public static void ServerRefreshLandClaimObject(IStaticWorldObject worldObject) { if (worldObject.IsDestroyed) { return; } if (!(worldObject.ProtoStaticWorldObject is IProtoObjectLandClaim)) { // not a land claim structure return; } var area = LandClaimSystem.ServerGetLandClaimArea(worldObject); if (area == null) { // incorrect land claim - no area attached return; } var areaBounds = LandClaimSystem.SharedGetLandClaimAreaBounds(area); var owners = LandClaimArea.GetPrivateState(area).LandOwners; foreach (var owner in owners) { var character = Server.Characters.GetPlayerCharacter(owner); if (character == null || !character.IsOnline) { continue; } if (!areaBounds.Contains(character.TilePosition)) { continue; } // the land claim contains an online owner character // reset the decay timer for this land claim StructureDecaySystem.ServerResetDecayTimer( worldObject.GetPrivateState <StructurePrivateState>()); using (var tempVisitedAreas = Api.Shared.WrapObjectInTempList(area)) { ServerResetDecayTimerRecursively(tempVisitedAreas.AsList(), areaBounds, character); } return; } }
public static bool ServerIsOwnedArea(ILogicObject area, ICharacter character) { if (area == null) { Logger.Warning(nameof(ServerIsOwnedArea) + " - argument area is null"); return(false); } var privateState = LandClaimArea.GetPrivateState(area); return(privateState.LandOwners .Contains(character.Name)); }
public string Execute(byte minOwnersNumber = 1) { if (minOwnersNumber < 1) { minOwnersNumber = 1; } var result = new StringBuilder("List of all land claims with their access lists: (with at least ") .Append(minOwnersNumber) .Append(" owner(s))") .AppendLine(); var worldBoundsOffset = Server.World.WorldBounds.Offset; foreach (var area in LandClaimSystem.SharedEnumerateAllAreas()) { var privateState = LandClaimArea.GetPrivateState(area); var landClaimOwners = privateState.ServerGetLandOwners(); var ownersCount = landClaimOwners.Count(); if (ownersCount < minOwnersNumber) { continue; } var publicState = LandClaimArea.GetPublicState(area); result.AppendLine() .Append(publicState.ProtoObjectLandClaim.ShortId) .Append(" at ") .Append(publicState.LandClaimCenterTilePosition - worldBoundsOffset) .Append(" — "); var factionClanTag = LandClaimSystem.SharedGetAreaOwnerFactionClanTag(area); if (!string.IsNullOrEmpty(factionClanTag)) { result.AppendFormat("faction [{0}] — ", factionClanTag); } result.Append(ownersCount) .Append(" owner(s)"); foreach (var ownerName in landClaimOwners) { result.AppendLine() .Append(" * ") .Append(ownerName); } } return(result.ToString()); }
private static void ServerRaidBlockStartedOrExtendedHandler( ILogicObject area, ICharacter raiderCharacter, bool isNewRaidBlock, bool isStructureDestroyed) { if (!isNewRaidBlock) { return; } var areasGroup = LandClaimSystem.SharedGetLandClaimAreasGroup(area); if (ServerNotifiedCharactersForAreasGroups.ContainsKey( ServerAllyBaseUnderRaidMark.CreateKeyOnly(areasGroup))) { // notification for this areas group is already sent return; } ILogicObject faction; var clanTag = LandClaimSystem.SharedGetAreaOwnerFactionClanTag(area); if (!string.IsNullOrEmpty(clanTag)) { // owned by a faction, notify allies faction = FactionSystem.ServerGetFactionByClanTag(clanTag); ServerNotifyFactionAllies(faction, area, areasGroup); return; } // not owned by faction, // check whether its founder is a member of any faction and notify its members var founderName = LandClaimArea.GetPrivateState(area) .LandClaimFounder; var founderCharacter = Server.Characters.GetPlayerCharacter(founderName); if (founderCharacter is null) { return; } faction = FactionSystem.ServerGetFaction(founderCharacter); if (faction is not null) { ServerNotifyFactionMembers(faction, founderCharacter, area, areasGroup); } }
private static void ServerRefreshLandClaimAreasGroup(ILogicObject areasGroup) { var areas = LandClaimAreasGroup.GetPrivateState(areasGroup).ServerLandClaimsAreas; foreach (var area in areas) { var areaBounds = LandClaimSystem.SharedGetLandClaimAreaBounds(area, addGracePadding: true); var owners = LandClaimArea.GetPrivateState(area).LandOwners; foreach (var owner in owners) { var character = Server.Characters.GetPlayerCharacter(owner); if (character == null || !character.ServerIsOnline) { continue; } if (!areaBounds.Contains(character.TilePosition)) { continue; } // the land claim area contains an online owner character ServerResetDecayTimer(); return; } } // helper method to reset the decay timer for all land claim buildings inside this areas group void ServerResetDecayTimer() { var decayDelayDuration = LandClaimSystem.ServerGetDecayDelayDurationForLandClaimAreas(areas); foreach (var area in areas) { var worldObject = LandClaimArea.GetPrivateState(area) .ServerLandClaimWorldObject; StructureDecaySystem.ServerResetDecayTimer( worldObject.GetPrivateState <StructurePrivateState>(), decayDelayDuration); } } }
public ViewModelWindowLandClaim( IStaticWorldObject landClaimWorldObject, ILogicObject area) { this.landClaimWorldObject = landClaimWorldObject; this.privateState = LandClaimArea.GetPrivateState(area); var protoStructureWithOwnersList = ((IProtoObjectWithOwnersList)landClaimWorldObject.ProtoStaticWorldObject); var canEditOwners = protoStructureWithOwnersList .SharedCanEditOwners(landClaimWorldObject, ClientCurrentCharacterHelper.Character); this.ViewModelOwnersEditor = new ViewModelWorldObjectOwnersEditor( this.privateState.LandOwners, callbackServerSetOwnersList: ownersList => LandClaimSystem.ClientSetAreaOwners( area, ownersList), title: AccessListTitle + ":", emptyListMessage: AccessListEmpty, canEditOwners: canEditOwners, // exclude founder name ownersListFilter: name => name != this.FounderName); this.protoObjectLandClaim = (IProtoObjectLandClaim)this.landClaimWorldObject.ProtoStaticWorldObject; var upgrade = this.protoObjectLandClaim.ConfigUpgrade.Entries.FirstOrDefault(); if (upgrade != null) { this.ViewModelStructureUpgrade = new ViewModelStructureUpgrade(upgrade); this.ViewModelProtoLandClaimInfoUpgrade = new ViewModelProtoLandClaimInfo( (IProtoObjectLandClaim)upgrade.ProtoStructure); } this.ViewModelItemsContainerExchange = new ViewModelItemsContainerExchange( landClaimWorldObject.GetPrivateState <ObjectLandClaimPrivateState>().ItemsContainer, callbackTakeAllItemsSuccess: () => { }) { IsContainerTitleVisible = false }; this.ViewModelProtoLandClaimInfoCurrent = new ViewModelProtoLandClaimInfo(this.protoObjectLandClaim); }
public static string ServerSetOwner(ushort x, ushort y, string newOwnerName) { using var tempList = Api.Shared.GetTempList <ILogicObject>(); LandClaimSystem.SharedGetAreasInBounds(new RectangleInt(x, y, 1, 1), tempList, addGracePadding: false); var landClaimsModified = 0; foreach (var area in tempList.AsList()) { var privateState = LandClaimArea.GetPrivateState(area); privateState.LandClaimFounder = newOwnerName; privateState.LandOwners.Clear(); privateState.LandOwners.Add(newOwnerName); landClaimsModified++; } return($"Modified {landClaimsModified} land claims"); }
public static bool SharedIsFoundedArea(ILogicObject area, ICharacter forCharacter) { if (area == null) { Logger.Warning(nameof(ServerIsOwnedArea) + " - argument area is null"); return(false); } if (IsClient && !area.ClientHasPrivateState) { // not an owner so not a founder for sure return(false); } var privateState = LandClaimArea.GetPrivateState(area); return(privateState.LandClaimFounder == forCharacter.Name); }
public static IStaticWorldObject ServerUpgrade( IStaticWorldObject oldStructure, IProtoObjectStructure upgradeStructure, ICharacter character) { if (!(oldStructure?.ProtoStaticWorldObject is IProtoObjectLandClaim)) { throw new Exception("Not a land claim structure: " + oldStructure); } var tilePosition = oldStructure.TilePosition; var area = ServerGetLandClaimArea(oldStructure); // release area oldStructure.GetPublicState <ObjectLandClaimPublicState>().LandClaimAreaObject = null; // destroy old structure ServerWorld.DestroyObject(oldStructure); // create new structure var upgradedObject = ServerWorld.CreateStaticWorldObject(upgradeStructure, tilePosition); // get area for the old land claim structure var areaPrivateState = LandClaimArea.GetPrivateState(area); var areaPublicState = LandClaimArea.GetPublicState(area); // update it to use upgraded land claim structure areaPrivateState.ServerLandClaimWorldObject = upgradedObject; areaPublicState.SetupAreaProperties(areaPrivateState); // set this area to the structure public state upgradedObject.GetPublicState <ObjectLandClaimPublicState>() .LandClaimAreaObject = area; Logger.Important($"Successfully upgraded: {oldStructure} to {upgradedObject}", character); Instance.CallClient( Server.Characters.EnumerateAllPlayerCharacters(onlyOnline: true), _ => _.ClientRemote_OnLandClaimUpgraded(area)); return(upgradedObject); }
private void AreaAddedHandler(ILogicObject area) { if (!LandClaimSystem.ClientIsOwnedArea(area)) { return; } if (this.visualizedAreas.ContainsKey(area)) { Api.Logger.Error("Land claim area already has the map visualizer: " + area); return; } var isFounder = string.Equals(LandClaimArea.GetPrivateState(area).LandClaimFounder, ClientCurrentCharacterHelper.Character.Name, StringComparison.Ordinal); this.visualizedAreas[area] = new LandClaimMapData(area, this.worldMapController, this.landClaimGroupVisualizer, isFounder: isFounder); }
private static bool ServerGetIsFounderDemoPlayer(List <ILogicObject> areas) { var isFounderDemoPlayer = false; foreach (var area in areas) { var areaPrivateState = LandClaimArea.GetPrivateState(area); var founder = ServerCharacters.GetPlayerCharacter(areaPrivateState.LandClaimFounder); if (founder.ServerIsDemoVersion) { isFounderDemoPlayer = true; } else { // one of the areas' founder is not a demo player return(false); } } return(isFounderDemoPlayer); }
public static ILogicObject ServerGetLandOwnerFactionOrFounderFaction(ILogicObject area) { ILogicObject faction = null; { var clanTag = SharedGetAreaOwnerFactionClanTag(area); if (!string.IsNullOrEmpty(clanTag)) { faction = FactionSystem.ServerGetFactionByClanTag(clanTag); } else { var founderName = LandClaimArea.GetPrivateState(area) .LandClaimFounder; var founderCharacter = Server.Characters.GetPlayerCharacter(founderName); if (founderCharacter is not null) { faction = FactionSystem.ServerGetFaction(founderCharacter); } } } return(faction); }
// refresh structures decay private async void ServerTimerTickCallback() { if (isUpdatingNow) { Logger.Warning( "Cannot process land claim reset decay system tick - not finished the previous update yet"); return; } if (!StructureConstants.IsStructureDecayEnabledInEditor && Api.IsEditor) { return; } // We will time-slice this update just in case there are too many areas. isUpdatingNow = true; try { TempList.AddRange(LandClaimSystem.ServerEnumerateAllAreas()); foreach (var area in TempList) { var worldObject = LandClaimArea.GetPrivateState(area) .ServerLandClaimWorldObject; ServerRefreshLandClaimObject(worldObject); await ServerCore.YieldIfOutOfTime(); } } finally { isUpdatingNow = false; TempList.Clear(); } }
private static void ServerRefreshLandClaimAreasGroup(ILogicObject areasGroup) { if (areasGroup.IsDestroyed) { return; } var areasGroupPrivateState = LandClaimAreasGroup.GetPrivateState(areasGroup); var areasGroupPublicState = LandClaimAreasGroup.GetPublicState(areasGroup); var areas = areasGroupPrivateState.ServerLandClaimsAreas; // TODO: it's better to move this code to another place as this property is used in several other places areasGroupPublicState.IsFounderDemoPlayer = ServerGetIsFounderDemoPlayer(areas); // check every area in the group // if any of them has an online owner, reset the decay timer foreach (var area in areas) { var areaBounds = LandClaimSystem.SharedGetLandClaimAreaBounds(area, addGracePadding: true); var areaPrivateState = LandClaimArea.GetPrivateState(area); var owners = areaPrivateState.LandOwners; foreach (var owner in owners) { var character = ServerCharacters.GetPlayerCharacter(owner); if (character is null || !character.ServerIsOnline) { continue; } if (!areaBounds.Contains(character.TilePosition)) { continue; } // the land claim area contains an online owner character ServerResetDecayTimer(); return; } } // helper method to reset the decay timer for all land claim buildings inside this areas group void ServerResetDecayTimer() { var decayDelayDuration = LandClaimSystem.ServerGetDecayDelayDurationForLandClaimAreas( areas, areasGroupPublicState.IsFounderDemoPlayer, out _); foreach (var area in areas) { var worldObject = LandClaimArea.GetPrivateState(area) .ServerLandClaimWorldObject; StructureDecaySystem.ServerResetDecayTimer( worldObject.GetPrivateState <StructurePrivateState>(), decayDelayDuration); } } }
private string ServerRemote_SetAreaOwners(ILogicObject area, List <string> newOwners) { var owner = ServerRemoteContext.Character; var privateState = LandClaimArea.GetPrivateState(area); var currentOwners = privateState.LandOwners; if (!currentOwners.Contains(owner.Name)) { return(WorldObjectOwnersSystem.DialogCannotSetOwners_MessageNotOwner); } if (!((IProtoObjectWithOwnersList)privateState.ServerLandClaimWorldObject.ProtoStaticWorldObject) .SharedCanEditOwners(privateState.ServerLandClaimWorldObject, owner)) { return(WorldObjectOwnersSystem.DialogCannotSetOwners_MessageCannotEdit); } currentOwners.GetDiff(newOwners, out var ownersToAdd, out var ownersToRemove); if (currentOwners.Count - ownersToRemove.Count <= 0) { return(WorldObjectOwnersSystem.DialogCannotSetOwners_MessageCannotRemoveLastOwner); } if (ownersToRemove.Contains(owner.Name)) { return(WorldObjectOwnersSystem.DialogCannotSetOwners_MessageCannotRemoveSelf); } foreach (var n in ownersToAdd) { var name = n; var playerToAdd = Server.Characters.GetPlayerCharacter(name); if (playerToAdd == null) { return(string.Format(WorldObjectOwnersSystem.DialogCannotSetOwners_MessageFormatPlayerNotFound, name)); } // get proper player name name = playerToAdd.Name; if (currentOwners.AddIfNotContains(name)) { Logger.Important($"Added land owner: {name}, land: {area}", characterRelated: owner); ServerOnAddLandOwner(area, playerToAdd, notify: true); } } foreach (var name in ownersToRemove) { if (!currentOwners.Remove(name)) { continue; } Logger.Important($"Removed land owner: {name}, land: {area}", characterRelated: owner); var removedPlayer = Server.Characters.GetPlayerCharacter(name); if (removedPlayer == null) { continue; } ServerOnRemoveLandOwner(area, removedPlayer); } return(null); }