// Iterate over all not-visited neighbor areas of this owner and reset their decay timers, recursively. private static void ServerResetDecayTimerRecursively( List <ILogicObject> visitedAreas, RectangleInt currentAreaBounds, ICharacter character) { using (var tempList = Api.Shared.GetTempList <ILogicObject>()) { LandClaimSystem.SharedGetAreasInBounds(currentAreaBounds.Inflate(1, 1), tempList); foreach (var otherArea in tempList) { if (visitedAreas.Contains(otherArea)) { continue; } visitedAreas.Add(otherArea); if (!LandClaimSystem.ServerIsOwnedArea(otherArea, character)) { continue; } var worldObject = otherArea.GetPrivateState <LandClaimAreaPrivateState>().ServerLandClaimWorldObject; StructureDecaySystem.ServerResetDecayTimer( worldObject.GetPrivateState <StructurePrivateState>()); var otherAreaBounds = LandClaimSystem.SharedGetLandClaimAreaBounds(otherArea); ServerResetDecayTimerRecursively(visitedAreas, otherAreaBounds, character); } } }
protected override void ServerOnStaticObjectZeroStructurePoints( WeaponFinalCache weaponCache, ICharacter byCharacter, IWorldObject targetObject) { // do not use default implementation because it will destroy the object automatically //base.ServerOnStaticObjectZeroStructurePoints(weaponCache, targetObject); var publicState = GetPublicState((IStaticWorldObject)targetObject); if (byCharacter != null && LandClaimSystem.ServerIsOwnedArea(publicState.LandClaimAreaObject, byCharacter)) { // this is the owner of the area if (byCharacter.SharedGetPlayerSelectedHotbarItemProto() is ProtoItemToolCrowbar) { publicState.ServerTimeForDestruction = 0; Logger.Important( $"Land claim object {targetObject} destroyed by the owner with a crowbar - no destruction timer", byCharacter); return; } } if (publicState.ServerTimeForDestruction.HasValue) { // destruction timer is already set return; } // the land claim structure points is zero - it's broken now - set timer for destruction publicState.ServerTimeForDestruction = Server.Game.FrameTime + this.DestructionTimeout.TotalSeconds; Logger.Important($"Timer for destruction set: {targetObject}. Timeout: {this.DestructionTimeout}"); }
public override bool SharedCanInteract(ICharacter character, IStaticWorldObject worldObject, bool writeToLog) { if (!base.SharedCanInteract(character, worldObject, writeToLog)) { return(false); } if (IsClient) { return(true); } var publicState = GetPublicState(worldObject); if (LandClaimSystem.ServerIsOwnedArea(publicState.LandClaimAreaObject, character)) { return(true); } // not the land owner if (writeToLog) { Logger.Warning( $"Character cannot interact with {worldObject} - not the land owner.", character); this.CallClient( character, _ => _.ClientRemote_OnCannotInteract( worldObject, LandClaimMenuOpenResult.FailPlayerIsNotOwner)); } return(false); }
private static void ServerPlayerOnlineStateChangedHandler(ICharacter character, bool isOnline) { if (!isOnline) { return; } // notify about the ongoing raids on ally bases foreach (var pair in ServerNotifiedCharactersForAreasGroups) { if (!pair.Value.Contains(character)) { // this character was not notified for that mark continue; } var mark = pair.Key; var areasGroup = mark.AreasGroup; var mapPosition = LandClaimSystem.SharedGetLandClaimGroupCenterPosition(areasGroup); var areas = LandClaimAreasGroup.GetPrivateState(areasGroup) .ServerLandClaimsAreas; var faction = areas .Select(LandClaimSystem.ServerGetLandOwnerFactionOrFounderFaction) .FirstOrDefault(f => f is not null); if (faction is null) { continue; } var isOwner = false; foreach (var area in areas) { if (LandClaimSystem.ServerIsOwnedArea(area, character, requireFactionPermission: false)) { isOwner = true; break; } } if (isOwner) { // no need to notify continue; } Instance.CallClient(character, _ => _.ClientRemote_AllyBaseUnderRaid( areasGroup.Id, mark.FactionMemberName, mark.ClanTag, mapPosition)); } }
private static void ServerNotifyFactionAllies( ILogicObject faction, ILogicObject area, ILogicObject areasGroup) { var allyFactions = Faction.GetPrivateState(faction) .FactionDiplomacyStatuses .Where(p => p.Value == FactionDiplomacyStatus.Ally) .Select(p => FactionSystem.ServerGetFactionByClanTag(p.Key)) .ToArray(); if (allyFactions.Length == 0) { return; } var charactersToNotify = allyFactions.SelectMany(FactionSystem.ServerGetFactionMembersReadOnly) .ToArray(); var playerCharactersToNotify = new List <ICharacter>(); foreach (var memberEntry in charactersToNotify) { var character = Server.Characters.GetPlayerCharacter(memberEntry.Name); if (character is not null && !LandClaimSystem.ServerIsOwnedArea(area, character, requireFactionPermission: false)) { playerCharactersToNotify.Add(character); } } if (playerCharactersToNotify.Count == 0) { return; } var clanTag = FactionSystem.SharedGetClanTag(faction); var mark = new ServerAllyBaseUnderRaidMark(areasGroup, factionMemberName: null, clanTag); ServerNotifiedCharactersForAreasGroups[mark] = playerCharactersToNotify; var mapPosition = LandClaimSystem.SharedGetLandClaimGroupCenterPosition(areasGroup); Instance.CallClient(playerCharactersToNotify, _ => _.ClientRemote_AllyBaseUnderRaid( areasGroup.Id, mark.FactionMemberName, mark.ClanTag, mapPosition)); }
protected override void ServerOnStaticObjectZeroStructurePoints( WeaponFinalCache weaponCache, ICharacter byCharacter, IWorldObject targetObject) { // do not use default implementation because it will destroy the object automatically //base.ServerOnStaticObjectZeroStructurePoints(weaponCache, targetObject); var worldObject = (IStaticWorldObject)targetObject; var publicState = GetPublicState(worldObject); if (byCharacter != null && (LandClaimSystem.ServerIsOwnedArea(publicState.LandClaimAreaObject, byCharacter) || CreativeModeSystem.SharedIsInCreativeMode(byCharacter))) { // this is the owner of the area or the player is in a creative mode if (byCharacter.SharedGetPlayerSelectedHotbarItemProto() is ProtoItemToolCrowbar) { publicState.ServerTimeForDestruction = 0; Logger.Important( $"Land claim object {targetObject} destroyed by the owner with a crowbar - no destruction timer", byCharacter); this.ServerForceUpdate(worldObject, publicState); return; } } if (byCharacter != null) { var areaPrivateState = LandClaimArea.GetPrivateState(publicState.LandClaimAreaObject); areaPrivateState.IsDestroyedByPlayers = true; } if (publicState.ServerTimeForDestruction.HasValue) { // destruction timer is already set return; } // the land claim structure points is zero - it's broken now - set timer for destruction var timeout = PveSystem.ServerIsPvE ? 0 : this.DestructionTimeout.TotalSeconds; publicState.ServerTimeForDestruction = Server.Game.FrameTime + timeout; Logger.Important($"Timer for destruction set: {targetObject}. Timeout: {timeout}"); this.ServerForceUpdate(worldObject, publicState); }
private static Vector2Ushort?TryFindZoneSpawnPosition( ICharacter character, IServerZone spawnZone, Random random, bool isRespawn) { var characterDeathPosition = Vector2Ushort.Zero; if (isRespawn && character.ProtoCharacter is PlayerCharacter) { characterDeathPosition = PlayerCharacter.GetPrivateState(character) .LastDeathPosition; } for (var attempt = 0; attempt < SpawnInZoneAttempts; attempt++) { var randomPosition = spawnZone.GetRandomPosition(random); if (isRespawn) { var sqrDistance = randomPosition.TileSqrDistanceTo(characterDeathPosition); if (sqrDistance > MaxDistanceWhenRespawnSqr || sqrDistance < MinDistanceWhenRespawnSqr) { // too close or too far for the respawn continue; } } if (LandClaimSystem.SharedGetAreaAtPosition(randomPosition) is ILogicObject area && !LandClaimSystem.ServerIsOwnedArea(area, character)) { // the land is claimed by another player continue; } if (ServerCharacterSpawnHelper.IsPositionValidForCharacterSpawn(randomPosition.ToVector2D(), isPlayer: true)) { // valid position found return(randomPosition); } } return(null); }
void IInteractableProtoStaticWorldObject.ServerOnMenuClosed(ICharacter who, IStaticWorldObject worldObject) { var area = LandClaimSystem.ServerGetLandClaimArea(worldObject); if (area == null) { // area could be null in the Editor for the land claim without owners return; } var areasGroup = LandClaimArea.GetPublicState(area).LandClaimAreasGroup; if (CreativeModeSystem.SharedIsInCreativeMode(who) && !LandClaimSystem.ServerIsOwnedArea(area, who)) { Server.World.ExitPrivateScope(who, area); } Server.World.ExitPrivateScope(who, areasGroup); }
void IInteractableProtoWorldObject.ServerOnClientInteract(ICharacter who, IWorldObject worldObject) { var area = LandClaimSystem.ServerGetLandClaimArea((IStaticWorldObject)worldObject); if (area == null) { // area could be null in the Editor for the land claim without owners return; } var areasGroup = LandClaimArea.GetPublicState(area).LandClaimAreasGroup; if (!LandClaimSystem.ServerIsOwnedArea(area, who) && (PlayerCharacterSpectator.SharedIsSpectator(who) || CreativeModeSystem.SharedIsInCreativeMode(who))) { Server.World.EnterPrivateScope(who, area); } Server.World.EnterPrivateScope(who, areasGroup); }
private static void ServerNotifyFactionMembers( ILogicObject faction, ICharacter founderCharacter, ILogicObject area, ILogicObject areasGroup) { var charactersToNotify = FactionSystem.ServerGetFactionMembersReadOnly(faction); var playerCharactersToNotify = new List <ICharacter>(); foreach (var memberEntry in charactersToNotify) { var character = Server.Characters.GetPlayerCharacter(memberEntry.Name); if (character is not null && !LandClaimSystem.ServerIsOwnedArea(area, character, requireFactionPermission: false)) { playerCharactersToNotify.Add(character); } } if (playerCharactersToNotify.Count == 0) { return; } var founderCharacterName = founderCharacter.Name; var mark = new ServerAllyBaseUnderRaidMark(areasGroup, founderCharacterName, clanTag: null); ServerNotifiedCharactersForAreasGroups[mark] = playerCharactersToNotify; var mapPosition = LandClaimSystem.SharedGetLandClaimGroupCenterPosition(areasGroup); Instance.CallClient(playerCharactersToNotify, _ => _.ClientRemote_AllyBaseUnderRaid( areasGroup.Id, mark.FactionMemberName, mark.ClanTag, mapPosition)); }
private static bool ServerTryRespawnAtBed(ICharacter character, bool respawnOnlyNearby) { if (!ServerCheckIsHasBed(character, out var bedObject)) { Instance.CallClient(character, _ => _.ClientRemote_CannotRespawnDontHaveBed()); return(false); } var cooldownRemainsSeconds = ServerCalculateBedRespawnCooldownSecondsRemaining( character, bedObject); if (cooldownRemainsSeconds >= 1) { Instance.CallClient(character, _ => _.ClientRemote_CannotRespawnInBedCooldown(cooldownRemainsSeconds)); return(false); } var bedPosition = bedObject.TilePosition; var physicsSpace = bedObject.PhysicsBody.PhysicsSpace; return(respawnOnlyNearby ? RespawnNearbyBed() : RespawnAtBed()); bool RespawnAtBed() { var neighborTiles = bedObject.OccupiedTiles .SelectMany(t => t.EightNeighborTiles) .Distinct() .ToList(); neighborTiles.Shuffle(); var bedTileHeight = bedObject.OccupiedTile.Height; neighborTiles.SortBy(t => t.Position.TileSqrDistanceTo(bedPosition)); foreach (var neighborTile in neighborTiles) { if (neighborTile.Height != bedTileHeight) { continue; } var spawnPosition = neighborTile.Position.ToVector2D() + (0.5, 0.5); using (var objectsNearby = physicsSpace.TestCircle( spawnPosition, radius: 0.5, collisionGroup: CollisionGroups.Default)) { if (objectsNearby.Count > 0) { // invalid tile - obstacles continue; } } var landClaimArea = LandClaimSystem.SharedGetAreaAtPosition(neighborTile.Position); if (landClaimArea != null && !LandClaimSystem.ServerIsOwnedArea(landClaimArea, character)) { // invalid tile - it's claimed by another player continue; } // valid tile found - respawn here Server.World.SetPosition(character, spawnPosition); Logger.Important($"{character} respawned at bed {bedObject}"); ServerLastRespawnTime[character.Name] = Server.Game.FrameTime; return(true); } Logger.Warning($"{character} cannot be spawned at bed {bedObject}"); Instance.CallClient(character, _ => _.ClientRemote_CannotRespawnInBedNoPlace()); return(false); } bool RespawnNearbyBed() { var attemptsRemains = 200; var bedPositionCenterTile = bedPosition.ToVector2D() + (0.5, 0.5); var radiuses = new[] { (min : 25, max : 50), (min : 50, max : 60), (min : 60, max : 70) }; var restrictedZone = ZoneSpecialConstructionRestricted.Instance.ServerZoneInstance; foreach (var radius in radiuses) { do { var offset = RandomHelper.Next(radius.min, radius.max); var angle = RandomHelper.NextDouble(); var offsetX = offset * Math.Sin(angle); var offsetY = offset * Math.Cos(angle); var spawnPosition = bedPositionCenterTile + (offsetX, offsetY); using (var objectsNearby = physicsSpace.TestCircle( spawnPosition, radius: 0.5, collisionGroup: CollisionGroups.Default)) { if (objectsNearby.Count > 0) { // invalid tile - obstacles continue; } } var landClaimArea = LandClaimSystem.SharedGetAreaAtPosition(spawnPosition.ToVector2Ushort()); if (landClaimArea != null) { // there is a land claim area - don't respawn there continue; } // ensure that the tile is valid var isValidTile = true; var spawnTile = Server.World.GetTile(spawnPosition.ToVector2Ushort()); foreach (var neighborTile in spawnTile.EightNeighborTiles.ConcatOne(spawnTile)) { if (!neighborTile.IsValidTile || neighborTile.ProtoTile.Kind != TileKind.Solid || restrictedZone.IsContainsPosition(neighborTile.Position)) { isValidTile = false; break; } } if (!isValidTile) { continue; } // valid tile found - respawn here Server.World.SetPosition(character, spawnPosition); Logger.Important($"{character} respawned near bed {bedObject}"); ServerLastRespawnTime[character.Name] = Server.Game.FrameTime; return(true); }while (attemptsRemains-- > 0); } Logger.Warning($"{character} cannot be spawned near bed {bedObject}"); Instance.CallClient(character, _ => _.ClientRemote_CannotRespawnNearBedNoPlace()); return(false); }
public static bool ServerHasAccess( IStaticWorldObject worldObject, ICharacter character, WorldObjectAccessMode currentAccessMode, bool writeToLog) { if (CreativeModeSystem.SharedIsInCreativeMode(character)) { return(true); } switch (currentAccessMode) { case WorldObjectAccessMode.Closed: default: if (writeToLog) { Logger.Warning( $"Character cannot interact with {worldObject} - no access.", character); Instance.CallClient( character, _ => _.ClientRemote_OnCannotInteractNoAccess(worldObject)); } return(false); case WorldObjectAccessMode.OpensToEveryone: return(true); case WorldObjectAccessMode.OpensToObjectOwners: case WorldObjectAccessMode.OpensToObjectOwnersOrAreaOwners: { if (WorldObjectOwnersSystem.SharedIsOwner(character, worldObject)) { // an object owner return(true); } // not an object owner if (currentAccessMode == WorldObjectAccessMode.OpensToObjectOwnersOrAreaOwners) { // check if player is the area owner var area = LandClaimSystem.SharedGetAreaAtPosition(worldObject.TilePosition); if (area != null && LandClaimSystem.ServerIsOwnedArea(area, character)) { // an the area owner return(true); } } // not an object owner and not an area owner if (writeToLog) { WorldObjectOwnersSystem.ServerNotifyNotOwner(character, worldObject); } return(false); } } }