예제 #1
0
        // "Graveyard" is a technical area in the bottom right corner of the map.
        private static void TeleportDeadPlayerCharacterToGraveyard(ICharacter character)
        {
            if (character.IsNpc)
            {
                // only player characters are teleported to graveyard
                return;
            }

            var publicState = character.GetPublicState <ICharacterPublicState>();

            if (!publicState.IsDead)
            {
                // player has been respawned
                return;
            }

            VehicleSystem.ServerCharacterExitCurrentVehicle(character, force: true);

            // disable the visual scope so the player cannot not see anyone and nobody could see the player
            Api.Server.Characters.SetViewScopeMode(character, isEnabled: false);
            var graveyardPosition = ServerGetGraveyardPosition();

            if (character.TilePosition != graveyardPosition)
            {
                ServerWorld.SetPosition(character, (Vector2D)graveyardPosition);
            }

            CharacterRespawnSystem.ServerRemoveInvalidStatusEffects(character);
        }
예제 #2
0
        /// <summary>
        /// Moves the character to the "graveyard" so a respawn will be required on login.
        /// No penalty in items or "weakened" status effect.
        /// </summary>
        public static void DespawnCharacter(ICharacter character)
        {
            var publicState = character.GetPublicState <ICharacterPublicState>();

            if (publicState.IsDead)
            {
                return;
            }

            VehicleSystem.ServerCharacterExitCurrentVehicle(character, force: true);

            var privateState = PlayerCharacter.GetPrivateState(character);

            CharacterDamageTrackingSystem.ServerClearStats(character);
            privateState.IsDespawned = true;
            Api.Logger.Important("Character despawned", character);

            // we have to set the dead flag to stop game mechanics from working
            // but on the respawn player should not lose anything
            publicState.IsDead = true;
            // recreate physics (as dead/despawned character doesn't have any physics)
            character.ProtoCharacter.SharedCreatePhysics(character);

            TeleportDeadPlayerCharacterToGraveyard(character);

            privateState.LastDeathPosition = Vector2Ushort.Zero;
            privateState.LastDeathTime     = null;
        }
예제 #3
0
        public void ServerRemote_SwitchToEditorMode()
        {
            var character = ServerRemoteContext.Character;

            VehicleSystem.ServerCharacterExitCurrentVehicle(character, force: true);
            // the order of calls is important here
            Server.Characters.SetSpectatorMode(character, isSpectator: true, reinitialize: false);
            Server.Characters.SetProto(character, GetProtoEntity <PlayerCharacterEditorMode>());
            character.ServerRemoveAllStatusEffects();
        }
예제 #4
0
 public override void ServerOnPilotDamage(
     WeaponFinalCache weaponCache,
     IDynamicWorldObject vehicle,
     ICharacter pilotCharacter,
     double damageApplied)
 {
     if (damageApplied > 0)
     {
         // drop from hoverboard on any damage
         VehicleSystem.ServerCharacterExitCurrentVehicle(pilotCharacter, force: true);
     }
 }
예제 #5
0
        public static void ServerPutIntoGarage(IDynamicWorldObject vehicle)
        {
            var position = ServerCharacterDeathMechanic.ServerGetGraveyardPosition().ToVector2D();

            var vehiclePrivateState = vehicle.GetPrivateState <VehiclePrivateState>();

            if (vehiclePrivateState.IsInGarage &&
                vehicle.Position == position)
            {
                // already in garage
                return;
            }

            var vehicleCurrentPilot = vehicle.GetPublicState <VehiclePublicState>().PilotCharacter;

            if (vehicleCurrentPilot != null)
            {
                VehicleSystem.ServerCharacterExitCurrentVehicle(vehicleCurrentPilot, force: true);
            }

            vehiclePrivateState.IsInGarage = true;

            Server.World.SetPosition(vehicle,
                                     position,
                                     writeToLog: false);

            VehicleSystem.ServerResetLastVehicleMapMark(vehiclePrivateState);

            vehicle.ProtoWorldObject.SharedCreatePhysics(vehicle);
            Logger.Important("Vehicle put into the garage: " + vehicle,
                             characterRelated: ServerRemoteContext.IsRemoteCall
                                                   ? ServerRemoteContext.Character
                                                   : null);

            if (ServerRemoteContext.IsRemoteCall)
            {
                // this action is done by player
                return;
            }

            // server put vehicle into garage - notify owners
            foreach (var owner in vehiclePrivateState.Owners)
            {
                var player = Server.Characters.GetPlayerCharacter(owner);
                if (player == null)
                {
                    continue;
                }

                var protoVehicle = (IProtoVehicle)vehicle.ProtoGameObject;
                Instance.CallClient(player, _ => _.ClientRemote_VehicleInGarage(protoVehicle));
            }
        }
예제 #6
0
        private void ServerRemote_CreateUnstuckRequest()
        {
            var character = ServerRemoteContext.Character;

            if (serverRequests.ContainsKey(character))
            {
                this.CallClient(character, _ => _.ClientRemote_UnstuckAlreadyQueued());
                return;
            }

            if (PlayerCharacter.GetPublicState(character).IsDead ||
                PlayerCharacter.GetPrivateState(character).IsDespawned)
            {
                // character is dead/despawned
                this.CallClient(character, _ => _.ClientRemote_UnstuckFailedDead());
                return;
            }

            var vehicle = character.SharedGetCurrentVehicle();

            if (vehicle is not null)
            {
                VehicleSystem.ServerCharacterExitCurrentVehicle(character, force: true);

                if (vehicle.GetPublicState <VehiclePublicState>().PilotCharacter is not null)
                {
                    // cannot quit vehicle here, cannot unstuck
                    this.CallClient(character, _ => _.ClientRemote_UnstuckImpossible());
                    return;
                }
            }

            var delay = LandClaimSystem.SharedIsPositionInsideOwnedOrFreeArea(character.TilePosition,
                                                                              character,
                                                                              requireFactionPermission: false)
                            ? UnstuckDelaySecondsTotal
                            : UnstuckDelaySecondsOnEnemyBaseTotal;

            var unstuckTime = Server.Game.FrameTime + delay;

            PlayerCharacter.GetPublicState(character).UnstuckExecutionTime = unstuckTime;

            serverRequests.Add(character,
                               new CharacterUnstuckRequest(
                                   unstuckAfter: unstuckTime,
                                   initialPosition: character.Position));
        }
예제 #7
0
        /// <summary>
        /// Moves the character to service area so a respawn will be required on login.
        /// There will be no penalties (such as loot drop or "weakened" status effect).
        /// </summary>
        public static void DespawnCharacter(ICharacter character)
        {
            var privateState = PlayerCharacter.GetPrivateState(character);

            if (privateState.IsDespawned)
            {
                return;
            }

            VehicleSystem.ServerCharacterExitCurrentVehicle(character, force: true);
            CharacterDamageTrackingSystem.ServerClearStats(character);

            ServerTeleportPlayerCharacterToServiceArea(character);

            privateState.LastDeathPosition = Vector2Ushort.Zero;
            privateState.LastDeathTime     = null;
        }
예제 #8
0
        public static void ServerSwitchToSpectatorMode(ICharacter character)
        {
            if (character.ProtoCharacter.GetType() == typeof(PlayerCharacterSpectator))
            {
                return;
            }

            VehicleSystem.ServerCharacterExitCurrentVehicle(character, force: true);

            // restore stamina so the spectator can "run"
            var stats = character.GetPublicState <PlayerCharacterPublicState>()
                        .CurrentStatsExtended;

            stats.SharedSetStaminaCurrent(stats.StaminaMax);

            // the order of calls is important here
            Server.Characters.SetSpectatorMode(character, isSpectator: false, reinitialize: false);
            Server.Characters.SetProto(character, GetProtoEntity <PlayerCharacterSpectator>());
            character.ServerRemoveAllStatusEffects();
        }
예제 #9
0
        protected override void ServerUpdate(ServerUpdateData data)
        {
            var character    = data.GameObject;
            var publicState  = data.PublicState;
            var privateState = data.PrivateState;

            publicState.IsOnline = character.ServerIsOnline;

            // update selected hotbar item
            SharedRefreshSelectedHotbarItem(character, privateState);

            if (publicState.IsDead)
            {
                VehicleSystem.ServerCharacterExitCurrentVehicle(character, force: true);

                // dead - stops processing character
                var world = Server.World;
                world.SetDynamicObjectMoveSpeed(character, 0);
                world.SetDynamicObjectPhysicsMovement(character,
                                                      accelerationVector: Vector2D.Zero,
                                                      targetVelocity: 0);
                character.PhysicsBody.Friction = 100000;
                world.StopPhysicsBody(character.PhysicsBody);
                return;
            }

            // character is alive
            this.ServerRebuildFinalCacheIfNeeded(privateState, publicState);
            this.SharedApplyInput(character, privateState, publicState);

            // update weapon state (fires the weapon if needed)
            WeaponSystem.SharedUpdateCurrentWeapon(character, privateState.WeaponState, data.DeltaTime);
            // update current action state (if any)
            privateState.CurrentActionState?.SharedUpdate(data.DeltaTime);
            // update crafting queue
            CraftingMechanics.ServerUpdate(privateState.CraftingQueue, data.DeltaTime);
            // consumes/restores stamina
            CharacterStaminaSystem.SharedUpdate(character, publicState, privateState, data.DeltaTime);
        }
예제 #10
0
        /// <summary>
        /// Service area (aka "graveyard") is an area in the bottom right corner of the map.
        /// </summary>
        public static void ServerTeleportPlayerCharacterToServiceArea(ICharacter character)
        {
            if (character.IsNpc)
            {
                return;
            }

            // disable the visual scope so the player cannot see anyone and nobody could see the player
            Api.Server.Characters.SetViewScopeMode(character, isEnabled: false);

            var privateState = PlayerCharacter.GetPrivateState(character);

            if (privateState.IsDespawned)
            {
                // already despawned, only fix the position
                MoveToServiceArea();
                return;
            }

            privateState.IsDespawned = true;
            VehicleSystem.ServerCharacterExitCurrentVehicle(character, force: true);
            MoveToServiceArea();

            Api.Logger.Important("Character despawned", character);

            // recreate physics (as despawned character doesn't have any physics)
            character.ProtoCharacter.SharedCreatePhysics(character);

            void MoveToServiceArea()
            {
                var serviceAreaPosition = ServerGetServiceAreaPosition();

                if (character.TilePosition != serviceAreaPosition)
                {
                    Server.World.SetPosition(character, (Vector2D)serviceAreaPosition);
                }
            }
        }
예제 #11
0
        private static void TeleportToBed(ICharacter character, IStaticWorldObject bedObject)
        {
            var bedPosition = bedObject.TilePosition.ToVector2D()
                              + bedObject.ProtoStaticWorldObject.Layout.Center;

            var neighborTiles = bedObject.OccupiedTiles
                                .SelectMany(t => t.EightNeighborTiles)
                                .Concat(bedObject.OccupiedTiles)
                                .Distinct()
                                .ToList();

            neighborTiles.Shuffle();

            var bedTileHeight = bedObject.OccupiedTile.Height;

            neighborTiles.SortBy(t => t.Position.ToVector2D()
                                 .DistanceSquaredTo(bedPosition));
            var physicsSpace = Server.World.GetPhysicsSpace();

            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;
                    }
                }

                if (!LandClaimSystem.SharedIsPositionInsideOwnedOrFreeArea(neighborTile.Position,
                                                                           character,
                                                                           requireFactionPermission: false))
                {
                    // invalid tile - it's claimed by another player
                    continue;
                }

                // valid tile found - respawn here
                // ensure the character has quit the current vehicle
                VehicleSystem.ServerCharacterExitCurrentVehicle(character, force: true);
                if (PlayerCharacter.GetPublicState(character).CurrentVehicle is not null)
                {
                    Logger.Important($"{character} cannot be teleported to bed as it cannot exit the current vehicle");
                    return;
                }

                Server.World.SetPosition(character, spawnPosition);
                Logger.Important($"{character} teleported to bed {bedObject}");
                return;
            }

            Logger.Important($"{character} cannot be teleported to bed {bedObject}");
        }
예제 #12
0
 private static void ExecuteCommandQuitVehicle()
 {
     VehicleSystem.ClientOnVehicleEnterOrExitRequest();
 }