Exemple #1
0
            private static void ServerLoadSystem()
            {
                ServerPrivateChatRoomsCache.Clear();

                var database = Server.Database;

                if (!database.TryGet(nameof(ChatSystem),
                                     DatabaseKeyGlobalChatRoomHolder,
                                     out sharedGlobalChatRoomHolder) ||
                    !IsValidChatRoomHolder(sharedGlobalChatRoomHolder))
                {
                    sharedGlobalChatRoomHolder = ServerCreateChatRoom(new ChatRoomGlobal());
                    database.Set(nameof(ChatSystem), DatabaseKeyGlobalChatRoomHolder, sharedGlobalChatRoomHolder);
                }

                if (!database.TryGet(nameof(ChatSystem),
                                     DatabaseKeyTradeChatRoomHolder,
                                     out sharedTradeChatRoomHolder) ||
                    !IsValidChatRoomHolder(sharedTradeChatRoomHolder))
                {
                    sharedTradeChatRoomHolder = ServerCreateChatRoom(new ChatRoomTrade());
                    database.Set(nameof(ChatSystem), DatabaseKeyTradeChatRoomHolder, sharedTradeChatRoomHolder);
                }

                if (!database.TryGet(nameof(ChatSystem),
                                     DatabaseKeyLocalChatRoomHolder,
                                     out sharedLocalChatRoomHolder))
                {
                    sharedLocalChatRoomHolder = ServerCreateChatRoom(new ChatRoomLocal());
                    database.Set(nameof(ChatSystem), DatabaseKeyLocalChatRoomHolder, sharedLocalChatRoomHolder);
                }

                // right now it's not possible to enumerate all the existing chat rooms as this is a bootstrapper
                // schedule a delayed initialization
                ServerTimersSystem.AddAction(
                    0.1,
                    () =>
                {
                    foreach (var chatRoomHolder in ServerWorld
                             .GetGameObjectsOfProto <ILogicObject, ChatRoomHolder>()
                             .ToList())
                    {
                        if (SharedGetChatRoom(chatRoomHolder) is not ChatRoomPrivate privateChatRoom)
                        {
                            continue;
                        }

                        var characterA = Server.Characters.GetPlayerCharacter(privateChatRoom.CharacterA);
                        var characterB = Server.Characters.GetPlayerCharacter(privateChatRoom.CharacterB);

                        if (characterA is null ||
                            characterB is null)
                        {
                            // incorrect private chat room
                            ServerWorld.DestroyObject(chatRoomHolder);
                            continue;
                        }

                        ServerAddPrivateChatRoomToCharacterCache(characterA, chatRoomHolder);
                        ServerAddPrivateChatRoomToCharacterCache(characterB, chatRoomHolder);
                    }
Exemple #2
0
        private void ServerExplodeAt(WeaponFinalCache weaponCache, Vector2D endPosition, bool isHit)
        {
            var character   = weaponCache.Character;
            var protoWeapon = (IProtoItemWeaponRanged)weaponCache.ProtoWeapon;

            var shotSourcePosition = WeaponSystemClientDisplay.SharedCalculateWeaponShotWorldPositon(
                character,
                protoWeapon,
                character.ProtoCharacter,
                character.Position,
                hasTrace: true);

            if (isHit)
            {
                // offset end position a bit towards the source position
                // this way the explosion will definitely happen outside the hit object
                endPosition -= 0.1 * (endPosition - shotSourcePosition).Normalized;
            }

            var timeToHit = WeaponSystemClientDisplay.SharedCalculateTimeToHit(
                protoWeapon.FireTracePreset
                ?? this.FireTracePreset,
                shotSourcePosition,
                endPosition);

            // We're using a check here similar to the one in WeaponSystem.
            // Ensure that player can hit objects only on the same height level
            // and can fire through over the pits (the cliffs of the lower heights).
            var anyCliffIsAnObstacle = character.Tile.Height
                                       != Server.World.GetTile(endPosition.ToVector2Ushort()).Height;

            if (!WeaponSystem.SharedHasTileObstacle(
                    character.Position,
                    character.Tile.Height,
                    endPosition,
                    character.PhysicsBody.PhysicsSpace,
                    anyCliffIsAnObstacle: anyCliffIsAnObstacle))
            {
                ServerTimersSystem.AddAction(
                    timeToHit,
                    () =>
                {
                    ExplosionHelper.ServerExplode(
                        character: character,
                        protoExplosive: this,
                        protoWeapon: protoWeapon,
                        explosionPreset: this.ExplosionPreset,
                        epicenterPosition: endPosition,
                        damageDescriptionCharacters: this.DamageDescription,
                        physicsSpace: Server.World.GetPhysicsSpace(),
                        executeExplosionCallback: this.ServerExecuteExplosion);
                });
            }

            // notify other characters about the explosion
            using var charactersObserving = Api.Shared.GetTempList <ICharacter>();
            var explosionEventRadius = Math.Max(protoWeapon.SoundPresetWeaponDistance.max,
                                                this.FireRangeMax)
                                       + this.DamageRadius;

            Server.World.GetCharactersInRadius(endPosition.ToVector2Ushort(),
                                               charactersObserving,
                                               radius: (byte)Math.Min(byte.MaxValue, explosionEventRadius),
                                               onlyPlayers: true);

            charactersObserving.Remove(character);

            this.CallClient(charactersObserving.AsList(),
                            _ => _.ClientRemote_OnExplosion(protoWeapon,
                                                            shotSourcePosition,
                                                            endPosition));
        }
        public static void ServerExplode(
            [CanBeNull] ICharacter character,
            [CanBeNull] IProtoObjectExplosive protoObjectExplosive,
            ExplosionPreset explosionPreset,
            Vector2D epicenterPosition,
            DamageDescription damageDescriptionCharacters,
            IPhysicsSpace physicsSpace,
            ExecuteExplosionDelegate executeExplosionCallback)
        {
            ValidateIsServer();

            // schedule explosion charred ground spawning
            ServerTimersSystem.AddAction(
                delaySeconds: explosionPreset.SpriteAnimationDuration * 0.5,
                () =>
            {
                var tilePosition = (Vector2Ushort)epicenterPosition;

                // remove existing charred ground objects at the same tile
                foreach (var staticWorldObject in Shared.WrapInTempList(
                             Server.World.GetTile(tilePosition).StaticObjects))
                {
                    if (staticWorldObject.ProtoStaticWorldObject is ObjectCharredGround)
                    {
                        Server.World.DestroyObject(staticWorldObject);
                    }
                }

                // spawn charred ground
                var objectCharredGround = Server.World
                                          .CreateStaticWorldObject <ObjectCharredGround>(tilePosition);
                var objectCharredGroundOffset = epicenterPosition - tilePosition.ToVector2D();
                if (objectCharredGroundOffset != Vector2D.Zero)
                {
                    ObjectCharredGround.ServerSetWorldOffset(objectCharredGround,
                                                             (Vector2F)objectCharredGroundOffset);
                }
            });

            // schedule explosion damage
            ServerTimersSystem.AddAction(
                delaySeconds: explosionPreset.ServerDamageApplyDelay,
                () =>
            {
                // prepare weapon caches
                var characterFinalStatsCache = character?.SharedGetFinalStatsCache()
                                               ?? FinalStatsCache.Empty;

                var weaponFinalCache = new WeaponFinalCache(character,
                                                            characterFinalStatsCache,
                                                            weapon: null,
                                                            protoWeapon: null,
                                                            protoObjectExplosive: protoObjectExplosive,
                                                            damageDescription: damageDescriptionCharacters);

                // execute explosion
                executeExplosionCallback(
                    positionEpicenter: epicenterPosition,
                    physicsSpace: physicsSpace,
                    weaponFinalCache: weaponFinalCache);
            });
        }
Exemple #4
0
        public static void ServerExplode(
            [CanBeNull] ICharacter character,
            [CanBeNull] IProtoExplosive protoExplosive,
            [CanBeNull] IProtoItemWeapon protoWeapon,
            ExplosionPreset explosionPreset,
            Vector2D epicenterPosition,
            DamageDescription damageDescriptionCharacters,
            IPhysicsSpace physicsSpace,
            ExecuteExplosionDelegate executeExplosionCallback)
        {
            ValidateIsServer();

            // schedule explosion charred ground spawning
            var protoObjectCharredGround = explosionPreset.ProtoObjectCharredGround;

            if (protoObjectCharredGround is not null)
            {
                ServerTimersSystem.AddAction(
                    delaySeconds: explosionPreset.SpriteAnimationDuration * 0.5,
                    () =>
                {
                    var tilePosition          = (Vector2Ushort)(epicenterPosition - protoObjectCharredGround.Layout.Center);
                    var canSpawnCharredGround = true;

                    var tile = Server.World.GetTile(tilePosition);
                    if (tile.ProtoTile.Kind != TileKind.Solid ||
                        tile.EightNeighborTiles.Any(t => t.ProtoTile.Kind != TileKind.Solid))
                    {
                        // allow charred ground only on solid ground
                        canSpawnCharredGround = false;
                    }

                    if (canSpawnCharredGround)
                    {
                        // remove existing charred ground objects at the same tile
                        foreach (var staticWorldObject in Shared.WrapInTempList(
                                     tile.StaticObjects)
                                 .EnumerateAndDispose())
                        {
                            switch (staticWorldObject.ProtoStaticWorldObject)
                            {
                            case ProtoObjectCharredGround _:
                                Server.World.DestroyObject(staticWorldObject);
                                break;

                            case IProtoObjectDeposit _:
                                // don't show charred ground over resource deposits (it looks wrong)
                                canSpawnCharredGround = false;
                                break;
                            }
                        }
                    }

                    if (canSpawnCharredGround &&
                        PveSystem.ServerIsPvE)
                    {
                        var bounds = protoObjectCharredGround.Layout.Bounds;
                        if (LandClaimSystem.SharedIsLandClaimedByAnyone(
                                new RectangleInt(tilePosition, bounds.Size + (1, 1))))
                        {
                            // ensure that it's not possible to create charred ground in a land claim area in PvE
                            canSpawnCharredGround = false;
                        }
                    }

                    if (canSpawnCharredGround)
                    {
                        // spawn charred ground
                        var objectCharredGround =
                            Server.World.CreateStaticWorldObject(protoObjectCharredGround,
                                                                 tilePosition);
                        var objectCharredGroundOffset = epicenterPosition - tilePosition.ToVector2D();
                        if (objectCharredGroundOffset != Vector2D.Zero)
                        {
                            ProtoObjectCharredGround.ServerSetWorldOffset(objectCharredGround,
                                                                          (Vector2F)objectCharredGroundOffset);
                        }
                    }
                });
            }

            // schedule explosion damage
            ServerTimersSystem.AddAction(
                delaySeconds: explosionPreset.ServerDamageApplyDelay,
                () =>
            {
                // prepare weapon caches
                var characterFinalStatsCache = character?.SharedGetFinalStatsCache()
                                               ?? FinalStatsCache.Empty;

                var weaponFinalCache = new WeaponFinalCache(character,
                                                            characterFinalStatsCache,
                                                            weapon: null,
                                                            protoWeapon: protoWeapon,
                                                            protoAmmo: null,
                                                            damageDescription: damageDescriptionCharacters,
                                                            protoExplosive: protoExplosive);

                // execute explosion
                executeExplosionCallback(
                    positionEpicenter: epicenterPosition,
                    physicsSpace: physicsSpace,
                    weaponFinalCache: weaponFinalCache);
            });
        }
Exemple #5
0
        private static void ServerAddMember(
            ICharacter character,
            ILogicObject faction,
            FactionMemberRole role)
        {
            Api.Assert(!character.IsNpc, "NPC cannot join a faction");

            if (!SharedIsValidRole(role))
            {
                throw new Exception("Invalid role: " + role);
            }

            var currentFaction = ServerGetFaction(character);

            if (currentFaction == faction)
            {
                // already in faction
                return;
            }

            if (currentFaction is not null)
            {
                throw new Exception($"Player already has a faction: {character} in {faction}");
            }

            // faction members cannot have a newbie protection
            NewbieProtectionSystem.ServerDisableNewbieProtection(character);

            var members            = ServerGetFactionMembersEditable(faction);
            var factionPublicState = Faction.GetPublicState(faction);
            var maxMembers         = FactionConstants.SharedGetFactionMembersMax(factionPublicState.Kind);

            if (members.Count >= maxMembers)
            {
                throw new Exception("Faction size exceeded - max " + maxMembers);
            }

            if (role == FactionMemberRole.Leader)
            {
                foreach (var otherMember in members)
                {
                    if (otherMember.Role == FactionMemberRole.Leader)
                    {
                        throw new Exception("Faction can have only a single leader");
                    }
                }
            }

            members.Add(new FactionMemberEntry(character.Name, role));
            ServerCharacterFactionDictionary[character]       = faction;
            PlayerCharacter.GetPublicState(character).ClanTag = factionPublicState.ClanTag;
            factionPublicState.PlayersNumberCurrent++;

            Logger.Important($"Player joined faction: {character} in {faction} - role: {role}",
                             character);

            ServerInvitations.RemoveAllInvitationsFor(character);

            Api.SafeInvoke(
                () => ServerCharacterJoinedOrLeftFaction?.Invoke(character,
                                                                 faction,
                                                                 isJoined: true));

            // add this with some delay to prevent from the bug when the player name listed twice due to the late delta-replication
            ServerTimersSystem.AddAction(delaySeconds: 0.1,
                                         () => ServerSendCurrentFaction(character));
        }
Exemple #6
0
 /// <summary>
 /// This method will expand the container capacity to max and schedule its trimming.
 /// </summary>
 private static void ServerExpandContainerAndScheduleProcessing(IItemsContainer itemsContainer)
 {
     ServerItems.SetSlotsCount(itemsContainer, slotsCount: byte.MaxValue);
     ServerTimersSystem.AddAction(0, () => ServerTrimSlotsNumber(itemsContainer));
 }
        public static void ServerAddMark(IStaticWorldObject staticWorldObject, double serverSpawnTime)
        {
            Api.ValidateIsServer();

            ushort searchAreaCircleRadius   = 0;
            var    searchAreaCirclePosition = Vector2Ushort.Zero;
            var    timeToClaimRemains       = SharedCalculateTimeToClaimLimitRemovalSeconds(serverSpawnTime);

            var biome    = staticWorldObject.OccupiedTile.ProtoTile;
            var position = SharedGetObjectCenterPosition(staticWorldObject);

            if (IsResourceDepositCoordinatesHiddenUntilCapturePossible &&
                timeToClaimRemains > 0)
            {
                var stopwatch = Stopwatch.StartNew();
                searchAreaCircleRadius = DepositSearchAreaCircleRadius;

                try
                {
                    if (!ServerSearchAreaHelper.GenerateSearchArea(position,
                                                                   biome,
                                                                   searchAreaCircleRadius,
                                                                   out searchAreaCirclePosition,
                                                                   maxAttempts: 100))
                    {
                        Logger.Warning(
                            "Unable to calculate an approximate search area for the resource deposit location, will use the center area: "
                            + staticWorldObject);

                        searchAreaCirclePosition = position;
                    }
                }
                finally
                {
                    Logger.Important(
                        $"Calculating a resource deposit search area took {stopwatch.ElapsedMilliseconds}ms (for {staticWorldObject} in {biome.ShortId} biome)");
                }

                // hide position
                position = Vector2Ushort.Zero;
            }

            sharedResourceMarksList.Add(
                new WorldMapResourceMark(staticWorldObject.Id,
                                         position,
                                         staticWorldObject.ProtoStaticWorldObject,
                                         serverSpawnTime,
                                         biome: biome,
                                         searchAreaCirclePosition: searchAreaCirclePosition,
                                         searchAreaCircleRadius: searchAreaCircleRadius));

            if (!IsResourceDepositCoordinatesHiddenUntilCapturePossible)
            {
                return;
            }

            if (timeToClaimRemains <= 0)
            {
                return;
            }

            ServerTimersSystem.AddAction(
                timeToClaimRemains + 1,
                () =>
            {
                if (staticWorldObject.IsDestroyed)
                {
                    return;
                }

                Logger.Important("It's possible to capture the resource deposit now, adding a mark on the map: "
                                 + staticWorldObject);
                ServerRemoveMark(staticWorldObject);

                // add on the next frame (give to for the network replication system)
                ServerTimersSystem.AddAction(
                    0.1,
                    () =>
                {
                    if (staticWorldObject.IsDestroyed)
                    {
                        return;
                    }

                    ServerAddMark(staticWorldObject, serverSpawnTime);
                });
            });
        }
Exemple #8
0
        private void UpdateDisplayedTimeNoTimer()
        {
            if (this.publicState.HasHarvest)
            {
                this.HarvestInTimePercent = 100;
                this.HarvestInTimeText    = null; // not used
            }
            else
            {
                // update harvest time
                var fraction = ServerTimersSystem.SharedGetTimeRemainingFraction(
                    this.nextHarvestOrSpoilTime,
                    this.totalHarvestDuration,
                    out var timeRemainingSeconds);

                this.HarvestInTimeText    = ClientTimeFormatHelper.FormatTimeDuration(Math.Max(0, timeRemainingSeconds));
                this.HarvestInTimePercent = (float)(100 * fraction);
            }

            if (this.publicState.IsSpoiled)
            {
                this.SpoiledInTimePercent = 100;
                this.SpoiledInTimeText    = null; // not used
                this.IsSpoiling           = true;
            }
            else if (this.publicState.HasHarvest)
            {
                // update rotten time
                var fraction = ServerTimersSystem.SharedGetTimeRemainingFraction(
                    this.nextHarvestOrSpoilTime,
                    this.protoPlant.TimeToHarvestSpoilTotalSeconds / FarmingConstants.SharedFarmPlantsSpoilSpeedMultiplier,
                    out var timeRemainingSeconds);

                this.SpoiledInTimeText    = ClientTimeFormatHelper.FormatTimeDuration(Math.Max(0, timeRemainingSeconds));
                this.SpoiledInTimePercent = (float)(100 * fraction);
                this.IsSpoiling           = true;
            }
            else
            {
                this.IsSpoiling = false;
            }

            if (this.VisibilityWatered == Visibility.Visible)
            {
                // update watering time
                var totalDuration = this.wateringDuration;
                if (totalDuration < double.MaxValue)
                {
                    var fraction = ServerTimersSystem.SharedGetTimeRemainingFraction(
                        this.wateringEndsTime,
                        totalDuration,
                        out var timeRemainingSeconds);
                    this.WateringEndsTimeText    = ClientTimeFormatHelper.FormatTimeDuration(timeRemainingSeconds);
                    this.WateringEndsTimePercent = (float)(100 * fraction);
                }
                else
                {
                    this.WateringEndsTimeText    = TitlePermanent;
                    this.WateringEndsTimePercent = 100;
                }
            }
            else
            {
                this.WateringEndsTimePercent = 0;
            }
        }
        public override void ServerOnDeath(ICharacter character)
        {
            this.ServerSendDeathSoundEvent(character);

            ServerTimersSystem.AddAction(
                delaySeconds: 3,
                () =>
            {
                var bossPosition = character.Position;
                using var tempListPlayersNearby = Api.Shared.GetTempList <ICharacter>();
                Server.World.GetScopedByPlayers(character, tempListPlayersNearby);

                foreach (var player in tempListPlayersNearby.AsList())
                {
                    if (player.Position.DistanceSquaredTo(bossPosition)
                        <= VictoryLearningPointsBonusMaxDistance * VictoryLearningPointsBonusMaxDistance)
                    {
                        player.SharedGetTechnologies()
                        .ServerAddLearningPoints(VictoryLearningPointsBonusToEachAlivePlayer,
                                                 allowModifyingByStat: false);
                    }
                }

                // explode
                var protoExplosion = Api.GetProtoEntity <ObjectPragmiumQueenDeathExplosion>();
                Server.World.CreateStaticWorldObject(protoExplosion,
                                                     (bossPosition - protoExplosion.Layout.Center)
                                                     .ToVector2Ushort());

                var privateState  = GetPrivateState(character);
                var damageTracker = privateState.DamageTracker;

                // spawn loot and minions on death
                ServerTimersSystem.AddAction(
                    delaySeconds: protoExplosion.ExplosionDelay.TotalSeconds
                    + protoExplosion.ExplosionPreset.ServerDamageApplyDelay * 1.01,
                    () =>
                {
                    try
                    {
                        ServerBossLootSystem.ServerCreateBossLoot(
                            epicenterPosition: bossPosition.ToVector2Ushort(),
                            protoCharacterBoss: this,
                            damageTracker: damageTracker,
                            bossDifficultyCoef: ServerBossDifficultyCoef,
                            lootObjectProto: ProtoLootObjectLazy.Value,
                            lootObjectsDefaultCount: DeathSpawnLootObjectsDefaultCount,
                            lootObjectsRadius: DeathSpawnLootObjectsRadius,
                            maxLootWinners: MaxLootWinners);
                    }
                    finally
                    {
                        ServerBossLootSystem.ServerSpawnBossMinionsOnDeath(
                            epicenterPosition: bossPosition.ToVector2Ushort(),
                            bossDifficultyCoef: ServerBossDifficultyCoef,
                            minionProto: ProtoMinionObjectDeathLazy.Value,
                            minionsDefaultCount: DeathSpawnMinionsDefaultCount,
                            minionsRadius: DeathSpawnMinionsRadius);
                    }
                });

                // destroy the character object after the explosion
                ServerTimersSystem.AddAction(
                    delaySeconds: protoExplosion.ExplosionDelay.TotalSeconds + 0.5,
                    () => Server.World.DestroyObject(character));
            });
        }
        protected override void ServerUpdate(ServerUpdateData data)
        {
            var item         = data.GameObject;
            var privateState = data.PrivateState;

            var character = item.Container.OwnerAsCharacter;

            if (!IsItemSelectedByPlayer(character, item))
            {
                // not a selected player item
                this.ServerSetUpdateRate(item, isRare: true);
                return;
            }

            privateState.ServerTimeToPing -= data.DeltaTime;
            if (privateState.ServerTimeToPing > 0)
            {
                return;
            }

            privateState.ServerTimeToPing = ServerScanInterval;

            if (!CharacterEnergySystem.ServerDeductEnergyCharge(
                    character,
                    requiredEnergyAmount: this.EnergyConsumptionPerSecond * ServerScanInterval))

            {
                // no power
                this.CallClient(character, _ => _.ClientRemote_NoPower());
                return;
            }

            ItemDurabilitySystem.ServerModifyDurability(
                item,
                delta: -(int)Math.Round(this.DurabilityDecreasePerSecond * ServerScanInterval));

            if (item.IsDestroyed)
            {
                // zero durability reached
                return;
            }

            // update signal strength
            using var tempSignalStrength = Api.Shared.GetTempList <byte>();
            this.ServerCalculateStrengthToTheClosestPragmiumSpires(character,
                                                                   tempSignalStrength.AsList(),
                                                                   MaxNumberOfPongsPerScan);

            var previousSignalStrength = -1;

            foreach (var signalStrength in tempSignalStrength.AsList())
            {
                if (signalStrength == previousSignalStrength)
                {
                    // don't send multiple pongs for the signals of the same strength
                    continue;
                }

                previousSignalStrength = signalStrength;

                var serverTimeToPong = SharedCalculateTimeToPong(signalStrength);
                ServerTimersSystem.AddAction(
                    serverTimeToPong,
                    () =>
                {
                    var currentCharacter = item.Container.OwnerAsCharacter;
                    if (IsItemSelectedByPlayer(currentCharacter, item))
                    {
                        this.CallClient(currentCharacter,
                                        _ => _.ClientRemote_OnSignal(item,
                                                                     PragmiumSensorSignalKind.Pong));
                    }
                });

                //Logger.Dev(string.Format("Pragmium scanner signal: {0} strength. Time to send pong: {1} ms.",
                //                         signalStrength,
                //                         (int)(serverTimeToPong * 1000)));
            }

            this.CallClient(character, _ => _.ClientRemote_OnSignal(item, PragmiumSensorSignalKind.Ping));

            bool IsItemSelectedByPlayer(ICharacter c, IItem i)
            => c is not null &&
            ReferenceEquals(i, c.SharedGetPlayerSelectedHotbarItem());
        }