コード例 #1
0
        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;
            }
コード例 #2
0
        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);
        }
コード例 #3
0
        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));
        }
コード例 #4
0
        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);
            }
        }
コード例 #5
0
        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);
        }
コード例 #6
0
        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}");
        }
コード例 #7
0
        /// <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;
            }
        }
コード例 #8
0
        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);
        }
コード例 #9
0
        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);
        }
コード例 #10
0
        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();
            }
        }
コード例 #11
0
        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}");
        }
コード例 #12
0
        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);
        }
コード例 #13
0
        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);
        }