Example #1
0
        // 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);
                }
            }
        }
Example #2
0
        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}");
        }
Example #3
0
        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);
        }
Example #4
0
        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));
            }
        }
Example #5
0
        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));
        }
Example #6
0
        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);
        }
Example #8
0
        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);
        }
Example #9
0
        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);
        }
Example #10
0
        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);
            }
Example #12
0
        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);
            }
            }
        }