private void ClientOnVehicleEnterExitButtonPress() { var character = ClientCurrentCharacterHelper.Character; if (character is null) { return; } var vehicle = ClientCurrentCharacterHelper.PublicState.CurrentVehicle; if (vehicle is not null) { // already inside a vehicle var vehiclePublicState = vehicle.GetPublicState <VehiclePublicState>(); vehiclePublicState.IsDismountRequested = true; this.CallServer(_ => _.ServerRemote_ExitVehicle(vehicle)); return; } if (InteractionCheckerSystem.SharedGetCurrentInteraction(character) is IDynamicWorldObject currentlyInteractingWithDynamicWorldObject && currentlyInteractingWithDynamicWorldObject.ProtoGameObject is IProtoVehicle) { vehicle = currentlyInteractingWithDynamicWorldObject; }
private void ServerRemote_TransferLandClaimToFactionOwnership(ILogicObject area) { var character = ServerRemoteContext.Character; var areasGroup = SharedGetLandClaimAreasGroup(area); if (LandClaimAreasGroup.GetPublicState(areasGroup).ServerFaction is not null) { // already has a faction (and it's not possible to change the faction) Logger.Warning("The land claim areas group is already transferred to a faction."); return; } FactionSystem.ServerValidateHasAccessRights(character, FactionMemberAccessRights.LandClaimManagement, out var faction); var factionOwnedAreas = SharedEnumerateAllFactionAreas(FactionSystem.SharedGetClanTag(faction)); var claimLimitRemains = FactionConstants.SharedGetFactionLandClaimsLimit( Faction.GetPublicState(faction).Level) - factionOwnedAreas.Count(); claimLimitRemains -= LandClaimAreasGroup.GetPrivateState(areasGroup).ServerLandClaimsAreas.Count; if (claimLimitRemains < 0) { Logger.Warning( "Cannot transfer land claims to the faction as it will exceed the land claims number limit"); return; } Logger.Important("Will transfer land claims to the faction: after upgrade the remaining limit will be " + claimLimitRemains); // verify user has access to the land claim var owner = ServerRemoteContext.Character; if (!Server.World.IsInPrivateScope(area, owner)) { throw new Exception( "Cannot interact with the land claim object as the area is not in private scope: " + area); } if (!LandClaimArea.GetPrivateState(area).ServerGetLandOwners() .Contains(owner.Name)) { throw new Exception("Player is not an owner of the land claim area"); } ServerTransferAreasGroupToFactionOwnership(faction, character, areasGroup); var worldObject = InteractionCheckerSystem.SharedGetCurrentInteraction(character); InteractableWorldObjectHelper.ServerTryAbortInteraction(character, worldObject); }
private IReadOnlyList <GarageVehicleEntry> ServerRemote_GetVehiclesList() { var character = ServerRemoteContext.Character; var currentInteractionObject = InteractionCheckerSystem.SharedGetCurrentInteraction(character); if (!(currentInteractionObject?.ProtoWorldObject is IProtoVehicleAssemblyBay)) { Logger.Warning(character + " is not interacting with any vehicle assembly bay"); return(Array.Empty <GarageVehicleEntry>()); } var onlyVehiclesInGarage = !PveSystem.ServerIsPvE; return(ServerGetCharacterVehicles(character, onlyVehiclesInGarage)); }
public static async void ClientPutCurrentVehicle() { if (!PveSystem.ClientIsPve(logErrorIfDataIsNotYetAvailable: true)) { // this feature is available only in PvE return; } var vehicleAssemblyBay = InteractionCheckerSystem.SharedGetCurrentInteraction( ClientCurrentCharacterHelper.Character); var isSuccess = await Instance.CallServer(_ => _.ServerRemote_PutCurrentVehicle()); if (isSuccess) { Client.Audio.PlayOneShot(SoundResourcePutVehicle, vehicleAssemblyBay); } }
private bool ServerRemote_PutCurrentVehicle() { if (!PveSystem.ServerIsPvE) { throw new Exception("This feature is available only in PvE"); } var character = ServerRemoteContext.Character; var currentInteractionObject = InteractionCheckerSystem.SharedGetCurrentInteraction(character); if (!(currentInteractionObject?.ProtoWorldObject is IProtoVehicleAssemblyBay protoVehicleAssemblyBay)) { throw new Exception("Player is not interacting with an vehicle assembly bay"); } using var tempVehiclesList = Api.Shared.GetTempList <IDynamicWorldObject>(); protoVehicleAssemblyBay.SharedGetVehiclesOnPlatform( vehicleAssemblyBay: (IStaticWorldObject)currentInteractionObject, tempVehiclesList); var isPutAtLeastOne = false; foreach (var vehicle in tempVehiclesList.AsList()) { if (ServerCanCharacterPutVehicleIntoGarage(vehicle, byCharacter: character)) { ServerPutIntoGarage(vehicle); isPutAtLeastOne = true; } } if (isPutAtLeastOne) { // notify other players in scope var soundPosition = currentInteractionObject.TilePosition.ToVector2D() + protoVehicleAssemblyBay.PlatformCenterWorldOffset; using var tempPlayers = Api.Shared.GetTempList <ICharacter>(); Server.World.GetScopedByPlayers(currentInteractionObject, tempPlayers); tempPlayers.Remove(character); Instance.CallClient(tempPlayers.AsList(), _ => _.ClientRemote_OnVehiclePutToGarageByOtherPlayer(soundPosition)); } return(isPutAtLeastOne); }
private void ServerRemote_Repair() { var character = ServerRemoteContext.Character; var tinkerTableObject = InteractionCheckerSystem.SharedGetCurrentInteraction(character) as IStaticWorldObject; this.VerifyGameObject(tinkerTableObject); var worldObjectPrivateState = GetPrivateState(tinkerTableObject); var containerInput = worldObjectPrivateState.ContainerInput; var containerOutput = worldObjectPrivateState.ContainerOutput; var inputItem1 = containerInput.GetItemAtSlot(0); var inputItem2 = containerInput.GetItemAtSlot(1); if (!ValidateCanRepair(character, tinkerTableObject, out var error)) { Logger.Warning(tinkerTableObject + " cannot repair: " + error, character); return; } if (!CreativeModeSystem.SharedIsInCreativeMode(character)) { InputItemsHelper.ServerDestroyItems(character, RequiredRepairComponentItems); } var resultDurabilityFraction = SharedCalculateResultDurabilityFraction(inputItem1, inputItem2, character); Server.Items.DestroyItem(inputItem2); Server.Items.MoveOrSwapItem(inputItem1, containerOutput, out _); var resultItemProto = (IProtoItemWithDurablity)inputItem1.ProtoGameObject; var resultItemPrivateState = inputItem1.GetPrivateState <IItemWithDurabilityPrivateState>(); resultItemPrivateState.DurabilityCurrent = (uint)Math.Round( resultDurabilityFraction * resultItemProto.DurabilityMax, MidpointRounding.AwayFromZero); character.ServerAddSkillExperience <SkillMaintenance>( SkillMaintenance.ExperiencePerItemRepaired); Logger.Info( $"Item repaired: {inputItem1}. Second item was destroyed to use for repair components: {inputItem2}"); }
/// <summary> /// Init on component enabled. /// </summary> public override void Start(ClientComponent parentComponent) { base.Start(parentComponent); // Check if there an action in progress. if (PrivateState.CurrentActionState != null) { readyForInteraction = false; lastActionState = PrivateState.CurrentActionState; } // Check if we opened loot container before enabling component. var currentInteractionObject = InteractionCheckerSystem.SharedGetCurrentInteraction(CurrentCharacter); if (currentInteractionObject?.ProtoWorldObject is ProtoObjectLootContainer) { readyForInteraction = false; } }
public static async void ClientTakeVehicle(uint vehicleGameObjectId) { var vehicleAssemblyBay = InteractionCheckerSystem.SharedGetCurrentInteraction( ClientCurrentCharacterHelper.Character); var result = await Instance.CallServer(_ => _.ServerRemote_TakeVehicle(vehicleGameObjectId)); if (result == TakeVehicleResult.Success) { Client.Audio.PlayOneShot(SoundResourceTakeVehicle, vehicleAssemblyBay); WindowObjectVehicleAssemblyBay.CloseActiveMenu(); return; } if (result == TakeVehicleResult.BaseUnderRaidblock) { LandClaimSystem.SharedSendNotificationActionForbiddenUnderRaidblock( ClientCurrentCharacterHelper.Character); return; } var error = result.GetDescription(); if (string.IsNullOrEmpty(error)) { return; } var currentInteractionObject = InteractionCheckerSystem.SharedGetCurrentInteraction(ClientCurrentCharacterHelper.Character); if (!(currentInteractionObject?.ProtoWorldObject is IProtoVehicleAssemblyBay protoVehicleAssemblyBay)) { return; } NotificationSystem.ClientShowNotification( Notification_CannotTakeVehicle_Title, error, NotificationColor.Bad, protoVehicleAssemblyBay.Icon); }
private TakeVehicleResult ServerRemote_TakeVehicle(uint vehicleGameObjectId) { var character = ServerRemoteContext.Character; var currentInteractionObject = InteractionCheckerSystem.SharedGetCurrentInteraction(character); if (!(currentInteractionObject?.ProtoWorldObject is IProtoVehicleAssemblyBay protoVehicleAssemblyBay)) { Logger.Warning("Player is not interacting with an vehicle assembly bay", character); return(TakeVehicleResult.Unknown); } var vehicleAssemblyBay = (IStaticWorldObject)currentInteractionObject; var vehicle = Server.World.GetGameObjectById <IDynamicWorldObject>(GameObjectType.DynamicObject, vehicleGameObjectId); if (vehicle == null) { Logger.Warning("Vehicle is not found", character); return(TakeVehicleResult.Unknown); } if (!WorldObjectOwnersSystem.SharedIsOwner(character, vehicle)) { Logger.Warning("Not an owner of the vehicle: " + vehicle, character); return(TakeVehicleResult.NotOwner); } var status = ServerGetVehicleStatus(vehicle, forCharacter: character); switch (status) { case VehicleStatus.InGarage: // allow to take break; case VehicleStatus.InWorld: if (!PveSystem.ServerIsPvE) { Logger.Warning("Cannot take a vehicle from world on a PvP server", character); return(TakeVehicleResult.Unknown); } // allow to take a vehicle from world in PvE only break; case VehicleStatus.InUse: return(TakeVehicleResult.Error_InUse); case VehicleStatus.Docked: return(TakeVehicleResult.Error_Docked); default: return(TakeVehicleResult.Unknown); } if (IsServer && LandClaimSystem.SharedIsUnderRaidBlock(character, vehicleAssemblyBay)) { return(TakeVehicleResult.BaseUnderRaidblock); } if (protoVehicleAssemblyBay.SharedIsBaySpaceBlocked( vehicleAssemblyBay: vehicleAssemblyBay)) { return(TakeVehicleResult.SpaceBlocked); } var position = currentInteractionObject.TilePosition.ToVector2D() + protoVehicleAssemblyBay.PlatformCenterWorldOffset; var vehiclePrivateState = vehicle.GetPrivateState <VehiclePrivateState>(); vehiclePrivateState.IsInGarage = false; vehiclePrivateState.ServerTimeSincePilotOffline = 0; vehiclePrivateState.ServerTimeSinceLastUse = ThresholdNoPilotSeconds + 1; Server.World.SetPosition(vehicle, position, writeToLog: false); vehicle.ProtoWorldObject.SharedCreatePhysics(vehicle); Logger.Important("Vehicle taken out of the garage: " + vehicle, character); // notify other players in scope var soundPosition = currentInteractionObject.TilePosition.ToVector2D() + protoVehicleAssemblyBay.PlatformCenterWorldOffset; using var tempPlayers = Api.Shared.GetTempList <ICharacter>(); Server.World.GetScopedByPlayers(currentInteractionObject, tempPlayers); tempPlayers.Remove(character); Instance.CallClient(tempPlayers.AsList(), _ => _.ClientRemote_OnVehicleTakenFromGarageByOtherPlayer(soundPosition)); return(TakeVehicleResult.Success); }
private async void ClientInteractStartAsync(IWorldObject worldObject) { if (this.isAwaitingServerInteraction) { return; } var character = Client.Characters.CurrentPlayerCharacter; if (InteractionCheckerSystem.SharedGetCurrentInteraction(character) == worldObject) { // already interacting with this object return; } this.isAwaitingServerInteraction = true; try { var requestId = ++lastRequestId; var isOpened = await this.CallServer(_ => _.ServerRemote_OnClientInteractStart(worldObject)); if (!isOpened || requestId != lastRequestId) { return; } } finally { this.isAwaitingServerInteraction = false; } var objectWindow = SharedGetProto(worldObject).ClientOpenUI(worldObject); if (objectWindow is null) { Logger.Info("Cannot open menu for object interaction with " + worldObject); this.CallServer(_ => _.ServerRemote_OnClientInteractFinish(worldObject)); return; } Api.SafeInvoke(() => ClientMenuCreated?.Invoke(worldObject, objectWindow)); if (!(objectWindow is IMenu)) { ClientCurrentInteractionMenu.RegisterMenuWindow(objectWindow); } else { ClientCurrentInteractionMenu.TryCloseCurrentMenu(); } InteractionCheckerSystem.SharedRegister( character, worldObject, finishAction: _ => objectWindow.CloseWindow()); ClientInteractionUISystem.Register( worldObject, objectWindow, onMenuClosedByClient: () => { InteractionCheckerSystem.SharedUnregister(character, worldObject, isAbort: false); if (!worldObject.IsDestroyed) { ++lastRequestId; this.CallServer(_ => _.ServerRemote_OnClientInteractFinish(worldObject)); } }); Logger.Info("Started object interaction with " + worldObject); if (objectWindow is IMenu objectMenu) { if (!objectMenu.IsOpened) { objectMenu.Toggle(); } } else { ClientCurrentInteractionMenu.Open(); } }
private void ServerRemote_Repair() { var character = ServerRemoteContext.Character; var tinkerTableObject = InteractionCheckerSystem.SharedGetCurrentInteraction(character) as IStaticWorldObject; this.VerifyGameObject(tinkerTableObject); var worldObjectPrivateState = GetPrivateState(tinkerTableObject); var containerInput = worldObjectPrivateState.ContainerInput; var containerOutput = worldObjectPrivateState.ContainerOutput; var inputItem1 = containerInput.GetItemAtSlot(0); var inputItem2 = containerInput.GetItemAtSlot(1); if (!ValidateCanRepair(character, tinkerTableObject, out var error)) { Logger.Warning(tinkerTableObject + " cannot repair: " + error, character); return; } if (!CreativeModeSystem.SharedIsInCreativeMode(character)) { InputItemsHelper.ServerDestroyItems(character, RequiredRepairComponentItems); } var resultItemProto = (IProtoItemWithDurability)inputItem1.ProtoGameObject; var resultDurabilityFraction = SharedCalculateResultDurabilityFraction(inputItem1, inputItem2, character); // break the second input item (it will force spawning ammo in this slot if it's a loaded weapon) ItemDurabilitySystem.ServerModifyDurability(inputItem2, -(double)resultItemProto.DurabilityMax, roundUp: false); if (!inputItem2.IsDestroyed) { // ensure the second input item is destroyed Server.Items.DestroyItem(inputItem2); } Server.Items.MoveOrSwapItem(inputItem1, containerOutput, out _); var resultItemPrivateState = inputItem1.GetPrivateState <IItemWithDurabilityPrivateState>(); if (resultDurabilityFraction < 1 && character.SharedHasSkillFlag(SkillMaintenance.Flags.ChanceToRepairCompletely) && RandomHelper.RollWithProbability(0.05)) { // 5% chance to repair item completely rolled successfully resultDurabilityFraction = 1; this.CallClient(character, _ => _.ClientRemote_ItemRepairedCompletely(inputItem1.ProtoItem)); } resultItemPrivateState.DurabilityCurrent = (uint)Math.Round( resultDurabilityFraction * resultItemProto.DurabilityMax, MidpointRounding.AwayFromZero); character.ServerAddSkillExperience <SkillMaintenance>( SkillMaintenance.ExperiencePerItemRepaired); Logger.Info( $"Item repaired: {inputItem1}. Second item was destroyed to use for repair components: {inputItem2}"); }
private void ServerRemote_Uninstall(byte slotId) { var character = ServerRemoteContext.Character; var worldObject = InteractionCheckerSystem.SharedGetCurrentInteraction(character); this.VerifyGameObject((IStaticWorldObject)worldObject); var itemToUninstall = character.SharedGetPlayerContainerEquipment() .GetItemAtSlot(slotId); if (itemToUninstall == null) { throw new Exception("No implant installed"); } var itemToUninstallProto = (IProtoItemEquipmentImplant)itemToUninstall.ProtoItem; var biomaterialRequiredAmount = CreativeModeSystem.SharedIsInCreativeMode(character) ? (ushort)0 : itemToUninstallProto.BiomaterialAmountRequiredToUninstall; if (!character.ContainsItemsOfType(ProtoItemBiomaterialVial.Value, requiredCount: biomaterialRequiredAmount) && !CreativeModeSystem.SharedIsInCreativeMode(character)) { throw new Exception("Not enough biomaterial vials"); } // move to inventory (please note, we're not providing byCharacter arg here to allow this container action) if (!Server.Items.MoveOrSwapItem(itemToUninstall, character.SharedGetPlayerContainerInventory(), out _)) { NotificationSystem.ServerSendNotificationNoSpaceInInventory(character); return; } if (biomaterialRequiredAmount > 0) { // destroy vials Server.Items.DestroyItemsOfType(character, ProtoItemBiomaterialVial.Value, countToDestroy: biomaterialRequiredAmount, out _); NotificationSystem.ServerSendItemsNotification( character, ProtoItemBiomaterialVial.Value, -biomaterialRequiredAmount); } if (itemToUninstallProto is ItemImplantBroken) { // broken implant destroys on uninstall Server.Items.DestroyItem(itemToUninstall); NotificationSystem.ServerSendItemsNotification( character, itemToUninstallProto, -1); } character.ServerAddSkillExperience <SkillCyberneticAffinity>( SkillCyberneticAffinity.ExperienceAddedPerImplantUninstalled); Logger.Info("Implant uninstalled: " + itemToUninstall); }
private void ServerRemote_Install(IItem itemToInstall, byte slotId) { var character = ServerRemoteContext.Character; var worldObject = InteractionCheckerSystem.SharedGetCurrentInteraction(character); this.VerifyGameObject((IStaticWorldObject)worldObject); var containerEquipment = character.SharedGetPlayerContainerEquipment(); var currentInstalledItem = containerEquipment.GetItemAtSlot(slotId); if (currentInstalledItem != null) { if (currentInstalledItem == itemToInstall) { Logger.Info("The implant is already installed"); return; } throw new Exception("Please uninstall installed implant"); } if (itemToInstall.Container.OwnerAsCharacter != character || itemToInstall.Container == containerEquipment) { throw new Exception("The item to install must be in character containers (except equipment)"); } if (!containerEquipment.ProtoItemsContainer.CanAddItem( new CanAddItemContext(containerEquipment, itemToInstall, slotId, byCharacter: null, isExploratoryCheck: false))) { throw new Exception("Cannot install implant item there"); } var itemToInstallProto = (IProtoItemEquipmentImplant)itemToInstall.ProtoItem; if (itemToInstallProto is ItemImplantBroken) { throw new Exception("Cannot install broken implant"); } foreach (var equippedItem in containerEquipment.Items) { if (equippedItem.ProtoItem == itemToInstallProto) { throw new Exception("Another implant of this type is already installed: " + itemToInstallProto); } } var biomaterialRequiredAmount = CreativeModeSystem.SharedIsInCreativeMode(character) ? (ushort)0 : itemToInstallProto.BiomaterialAmountRequiredToInstall; if (!character.ContainsItemsOfType(ProtoItemBiomaterialVial.Value, requiredCount: biomaterialRequiredAmount)) { throw new Exception("Not enough biomaterial vials"); } // move to an implant slot in the equipment container // please note, we're not providing byCharacter arg here to allow this container action if (!Server.Items.MoveOrSwapItem(itemToInstall, containerEquipment, out _, slotId: slotId)) { throw new Exception("Unknown error - cannot move implant item to the player equipment"); } if (biomaterialRequiredAmount > 0) { // destroy vials Server.Items.DestroyItemsOfType(character, ProtoItemBiomaterialVial.Value, countToDestroy: biomaterialRequiredAmount, out _); NotificationSystem.ServerSendItemsNotification( character, ProtoItemBiomaterialVial.Value, -biomaterialRequiredAmount); } character.ServerAddSkillExperience <SkillCyberneticAffinity>( SkillCyberneticAffinity.ExperienceAddedPerImplantInstalled); Logger.Info("Implant installed: " + itemToInstall); }