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