// "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); }
/// <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; }
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(); }
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); } }
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)); } }
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)); }
/// <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; }
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(); }
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); }
/// <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); } } }
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}"); }
private static void ExecuteCommandQuitVehicle() { VehicleSystem.ClientOnVehicleEnterOrExitRequest(); }