private static bool SharedHasEnergyCharge(ITempList <IItem> tempItemsList, uint energyRequired)
        {
            var charge = SharedCalculateTotalEnergyCharge(tempItemsList,
                                                          stopIfEnergyExceeds: energyRequired);

            return(charge >= energyRequired);
        }
Exemple #2
0
        private void SelectRandomEntries(ITempList <Entry> result)
        {
            var countToSelect = this.Outputs + RandomHelper.Next(0, this.OutputsRandom + 1);

            if (countToSelect >= this.frozenEntries.Count)
            {
                // simply return all the entries
                foreach (var entry in this.entries)
                {
                    result.Add(entry.Value);
                }

                return;
            }

            if (countToSelect == 1)
            {
                // simply return a single random selected entry
                result.Add(this.frozenEntries.GetSingleRandomElement());
                return;
            }

            // need to select multiple random entries
            // ReSharper disable once SuspiciousTypeConversion.Global
            this.frozenEntries.SelectRandomElements((List <Entry>)result, countToSelect);
        }
        public virtual void SharedGetVehiclesOnPlatform(
            IStaticWorldObject vehicleAssemblyBay,
            ITempList <IDynamicWorldObject> result)
        {
            var noObstaclesBounds = this.BoundsNoObstaclesTest;

            noObstaclesBounds = new BoundsDouble(
                offset: noObstaclesBounds.Offset + vehicleAssemblyBay.PhysicsBody.Position,
                size: noObstaclesBounds.Size);

            // test with different collision zones (required to handle hoverboards which don't have physical colliders)
            var defaultCollisionGroup = CollisionGroups.Default;

            CollectVehicles(defaultCollisionGroup);
            CollectVehicles(CollisionGroups.HitboxMelee);

            void CollectVehicles(CollisionGroup collisionGroup)
            {
                foreach (var testResult in vehicleAssemblyBay.PhysicsBody.PhysicsSpace.TestRectangle(
                             position: noObstaclesBounds.Offset,
                             size: noObstaclesBounds.Size,
                             collisionGroup: collisionGroup).EnumerateAndDispose())
                {
                    if (testResult.PhysicsBody.AssociatedWorldObject is IDynamicWorldObject dynamicWorldObject &&
                        dynamicWorldObject.ProtoGameObject is IProtoVehicle)
                    {
                        result.AddIfNotContains(dynamicWorldObject);
                    }
                }
            }
        }
Exemple #4
0
        private static void ServerAddEnergyInternal(double energyAmountToAdd, ITempList <IItem> powerBanks)
        {
            foreach (var item in powerBanks)
            {
                if (item.IsDestroyed)
                {
                    continue;
                }

                var privateState = SharedGetPrivateState(item);
                var protoItem    = (IProtoItemPowerBank)item.ProtoItem;
                var capacity     = protoItem.EnergyCapacity;

                var charge = privateState.EnergyCharge;
                if (charge >= capacity)
                {
                    // cannot add charge there
                    continue;
                }

                var newCharge = charge + energyAmountToAdd;
                if (newCharge <= capacity)
                {
                    // this battery can take the whole remaining energyAmountToAdd
                    privateState.EnergyCharge = newCharge;
                    return;
                }

                // add as much energy to this item as possible and go to the next item
                privateState.EnergyCharge = capacity;
                var energyAdded = capacity - charge;
                energyAmountToAdd -= energyAdded;
            }
        }
        public static void SharedVisualizeTestResults(
            ITempList <TestResult> physicsTestResults,
            CollisionGroup collisionGroup)
        {
            if (IsClient)
            {
                using var testResults = Api.Shared.GetTempList <Vector2D>();
                AddTestResults(physicsTestResults.AsList(), testResults.AsList());
                ClientComponentPhysicsSpaceVisualizer.VisualizeTestResults(testResults.AsList(),
                                                                           collisionGroup,
                                                                           isClient: true);
            }
            else // if server
            {
                Api.Assert(Api.IsEditor, "This is Editor-only server code");
                var allPlayers = Server.Characters.EnumerateAllPlayerCharacters(onlyOnline: true,
                                                                                exceptSpectators: false);

                var testResults = new List <Vector2D>();
                AddTestResults(physicsTestResults.AsList(), testResults);

                var collisionGroupId = CollisionGroups.GetCollisionGroupId(collisionGroup);
                instance.CallClient(
                    allPlayers,
                    // ReSharper disable once AccessToDisposedClosure
                    _ => _.ClientRemote_ProcessServerTestResults(testResults, collisionGroupId));
            }
        }
 private static void SharedFindPowerBanks(IItemsContainer container, ITempList <IItem> tempList)
 {
     foreach (var item in container.Items)
     {
         if (item.ProtoItem is IProtoItemPowerBank)
         {
             tempList.Add(item);
         }
     }
 }
        private static async Task <ITextureResource> GenerateChunkProceduralTexture(
            ITempList <Tile> tiles,
            Vector2Ushort chunkStartPosition,
            ProceduralTextureRequest request)
        {
            var renderingService = Api.Client.Rendering;
            var renderingTag     = request.TextureName;

            var textureSize = new Vector2Ushort(WorldChunkMapTextureSize, WorldChunkMapTextureSize);

            // create camera and render texture
            var renderTexture = renderingService.CreateRenderTexture(renderingTag,
                                                                     textureSize.X,
                                                                     textureSize.Y);
            var cameraObject = Api.Client.Scene.CreateSceneObject(renderingTag);
            var camera       = renderingService.CreateCamera(cameraObject,
                                                             renderingTag,
                                                             drawOrder: -100);

            camera.RenderTarget = renderTexture;
            camera.ClearColor   = Colors.Magenta; // to make potential issues visible clear with magenta color
            camera.SetOrthographicProjection(textureSize.X, textureSize.Y);

            // create tile renderers
            foreach (var tile in tiles)
            {
                var drawPosition = tile.Position.ToVector2D() - chunkStartPosition.ToVector2D();
                drawPosition = (
                    drawPosition.X * WorldTileTextureSize,
                    // Y is reversed
                    (drawPosition.Y - ScriptingConstants.WorldChunkSize + 1) * WorldTileTextureSize);

                renderingService.CreateSpriteRenderer(
                    cameraObject,
                    tile.ProtoTile.GetWorldMapTexture(tile),
                    positionOffset: drawPosition,
                    // draw down
                    spritePivotPoint: (0, 1),
                    renderingTag: renderingTag);
            }

            tiles.Dispose();

            await camera.DrawAsync();

            cameraObject.Destroy();

            request.ThrowIfCancelled();

            var generatedTexture = await renderTexture.SaveToTexture(isTransparent : false);

            renderTexture.Dispose();
            request.ThrowIfCancelled();
            return(generatedTexture);
        }
Exemple #8
0
        private static uint SharedCalculateTotalEnergyCapacity(ITempList <IItem> tempItemsList)
        {
            uint result = 0;

            foreach (var item in tempItemsList)
            {
                var protoItem = (IProtoItemPowerBank)item.ProtoItem;
                result += protoItem.EnergyCapacity;
            }

            return(result);
        }
Exemple #9
0
            public FilePathsList(string sourceFolderPath, ITempList <string> filesInFolder)
            {
                this.SourceFolderPath = sourceFolderPath;
                this.tempList         = filesInFolder;

                foreach (var path in this.FilesInFolder)
                {
                    if (!path.EndsWith(".png"))
                    {
                        throw new Exception(
                                  "All loadable attachments must be a PNG-files: wrong file - " + path);
                    }
                }
            }
Exemple #10
0
        public static void SharedGetAreasInBounds(RectangleInt bounds, ITempList <ILogicObject> result)
        {
            if (result.Count > 0)
            {
                result.Clear();
            }

            // TODO: the lookup is really slow on the populated servers. Consider Grid or QuadTree optimization to locate areas quickly.
            foreach (var area in sharedLandClaimAreas)
            {
                var areaBounds = SharedGetLandClaimAreaBounds(area);
                if (areaBounds.IntersectsLoose(bounds))
                {
                    result.Add(area);
                }
            }
        }
Exemple #11
0
        private void SelectRandomEntries(ITempList <Entry> result, DropItemContext dropItemContext)
        {
            var countToSelect = this.Outputs + RandomHelper.Next(0, this.OutputsRandom + 1);

            if (countToSelect >= this.frozenEntries.Count)
            {
                // simply return all the entries
                foreach (var entry in this.entries)
                {
                    result.Add(entry.Value);
                }

                return;
            }

            if (countToSelect == 1)
            {
                // simply return a single random selected entry that is satisfying the condition
                Entry entry = default;
                for (var attempt = 0; attempt < 100; attempt++)
                {
                    entry = this.frozenEntries.GetSingleRandomElement();
                    if (entry.Condition is null)
                    {
                        break;
                    }

                    try
                    {
                        if (entry.Condition(dropItemContext))
                        {
                            break;
                        }

                        // condition not match, select another entry
                        continue;
                    }
                    catch (Exception ex)
                    {
                        Api.Logger.Exception(ex, "Exception during checking condition for droplist item " + entry);
                        break;
                    }
                }

                if (!entry.Equals(default))
        private static uint SharedCalculateTotalEnergyCharge(
            ITempList <IItem> tempItemsList,
            uint stopIfEnergyExceeds = uint.MaxValue)
        {
            ulong result = 0;

            foreach (var item in tempItemsList.AsList())
            {
                var privateState = SharedGetPrivateState(item);
                var charge       = privateState.DurabilityCurrent;
                result += charge;

                if (result >= stopIfEnergyExceeds)
                {
                    break;
                }
            }

            return((uint)Math.Min(uint.MaxValue, result));
        }
Exemple #13
0
        protected virtual void ClientFillSlotAttachmentSources(ITempList <string> folders)
        {
            var baseProtoItem = this.BaseProtoItem;

            if (baseProtoItem is not null)
            {
                folders.Add(
                    $"Characters/Equipment/{baseProtoItem.ShortId}/{this.ShortId.Substring(baseProtoItem.ShortId.Length)}");
                return;
            }

            var path = $"Characters/Equipment/{this.ShortId}/Default";

            if (Api.Shared.IsFolderExists(ContentPaths.Textures + path))
            {
                folders.Add(path);
                return;
            }

            folders.Add($"Characters/Equipment/{this.ShortId}");
        }
Exemple #14
0
        private static double SharedCalculateTotalEnergyCharge(
            ITempList <IItem> tempItemsList,
            double stopIfEnergyExceeds = double.NaN)
        {
            var result           = 0.0;
            var hasStopCondition = !double.IsNaN(stopIfEnergyExceeds);

            foreach (var item in tempItemsList)
            {
                var privateState = SharedGetPrivateState(item);
                var charge       = privateState.EnergyCharge;
                result += charge;

                if (hasStopCondition &&
                    result >= stopIfEnergyExceeds)
                {
                    return(result);
                }
            }

            return(result);
        }
 protected virtual void ClientFillSlotAttachmentSources(ITempList <string> folders)
 {
     folders.Add("Characters/Equipment/" + this.ShortId);
 }
 public void Dispose()
 {
     this.Overlay?.Dispose();
     this.Overlay = null;
 }
 public WallChunkWithOverlays(WallPattern primary, ITempList <WallPattern> overlay)
 {
     this.Primary = primary;
     this.Overlay = overlay;
 }
 protected override void ClientFillSlotAttachmentSources(ITempList <string> folders)
 {
     base.ClientFillSlotAttachmentSources(folders);
     // add generic pants
     folders.Add("Characters/Equipment/GenericPants");
 }
Exemple #19
0
        private static void SharedGatherOccupiedAndNeighborTiles(IStaticWorldObject structure, ITempList <Tile> tempList)
        {
            // gather the occupied tiles and theirs direct neighbors
            foreach (var tile in structure.OccupiedTiles)
            {
                if (!tile.IsValidTile)
                {
                    continue;
                }

                tempList.AddIfNotContains(tile);

                foreach (var neighborTile in tile.EightNeighborTiles)
                {
                    if (neighborTile.IsValidTile)
                    {
                        tempList.AddIfNotContains(neighborTile);
                    }
                }
            }
        }
Exemple #20
0
        private static void SharedShotWeaponHitscan(
            ICharacter character,
            IProtoItemWeapon protoWeapon,
            Vector2D fromPosition,
            WeaponFinalCache weaponCache,
            Vector2D?customTargetPosition,
            IProtoCharacterCore characterProtoCharacter,
            double fireSpreadAngleOffsetDeg,
            CollisionGroup collisionGroup,
            bool isMeleeWeapon,
            IDynamicWorldObject characterCurrentVehicle,
            ProtoSkillWeapons protoWeaponSkill,
            PlayerCharacterSkills playerCharacterSkills,
            ITempList <IWorldObject> allHitObjects)
        {
            Vector2D toPosition;
            var      rangeMax = weaponCache.RangeMax;

            if (customTargetPosition.HasValue)
            {
                var direction = customTargetPosition.Value - fromPosition;
                // ensure the max range is not exceeded
                direction  = direction.ClampMagnitude(rangeMax);
                toPosition = fromPosition + direction;
            }
            else
            {
                toPosition = fromPosition
                             + new Vector2D(rangeMax, 0)
                             .RotateRad(characterProtoCharacter.SharedGetRotationAngleRad(character)
                                        + fireSpreadAngleOffsetDeg * Math.PI / 180.0);
            }

            using var lineTestResults = character.PhysicsBody.PhysicsSpace.TestLine(
                      fromPosition: fromPosition,
                      toPosition: toPosition,
                      collisionGroup: collisionGroup);
            var damageMultiplier    = 1d;
            var hitObjects          = new List <WeaponHitData>(isMeleeWeapon ? 1 : lineTestResults.Count);
            var characterTileHeight = character.Tile.Height;

            if (IsClient ||
                Api.IsEditor)
            {
                SharedEditorPhysicsDebugger.SharedVisualizeTestResults(lineTestResults, collisionGroup);
            }

            var isDamageRayStopped = false;

            foreach (var testResult in lineTestResults.AsList())
            {
                var testResultPhysicsBody = testResult.PhysicsBody;
                var attackedProtoTile     = testResultPhysicsBody.AssociatedProtoTile;
                if (attackedProtoTile != null)
                {
                    if (attackedProtoTile.Kind != TileKind.Solid)
                    {
                        // non-solid obstacle - skip
                        continue;
                    }

                    var attackedTile = IsServer
                                           ? Server.World.GetTile((Vector2Ushort)testResultPhysicsBody.Position)
                                           : Client.World.GetTile((Vector2Ushort)testResultPhysicsBody.Position);

                    if (attackedTile.Height < characterTileHeight)
                    {
                        // attacked tile is below - ignore it
                        continue;
                    }

                    // tile on the way - blocking damage ray
                    isDamageRayStopped = true;
                    var hitData = new WeaponHitData(testResult.PhysicsBody.Position
                                                    + SharedOffsetHitWorldPositionCloserToTileHitboxCenter(
                                                        testResultPhysicsBody,
                                                        testResult.Penetration,
                                                        isRangedWeapon: !isMeleeWeapon));
                    hitObjects.Add(hitData);

                    weaponCache.ProtoWeapon
                    .SharedOnHit(weaponCache,
                                 null,
                                 0,
                                 hitData,
                                 out _);
                    break;
                }

                var damagedObject = testResultPhysicsBody.AssociatedWorldObject;
                if (ReferenceEquals(damagedObject, character) ||
                    ReferenceEquals(damagedObject, characterCurrentVehicle))
                {
                    // ignore collision with self
                    continue;
                }

                if (!(damagedObject.ProtoGameObject is IDamageableProtoWorldObject damageableProto))
                {
                    // shoot through this object
                    continue;
                }

                // don't allow damage is there is no direct line of sight on physical colliders layer between the two objects
                if (SharedHasTileObstacle(character.Position,
                                          characterTileHeight,
                                          damagedObject,
                                          targetPosition: testResult.PhysicsBody.Position
                                          + testResult.PhysicsBody.CenterOffset))
                {
                    continue;
                }

                using (CharacterDamageContext.Create(attackerCharacter: character,
                                                     damagedObject as ICharacter,
                                                     protoWeaponSkill))
                {
                    if (!damageableProto.SharedOnDamage(
                            weaponCache,
                            damagedObject,
                            damageMultiplier,
                            damagePostMultiplier: 1.0,
                            out var obstacleBlockDamageCoef,
                            out var damageApplied))
                    {
                        // not hit
                        continue;
                    }

                    var hitData = new WeaponHitData(damagedObject,
                                                    testResult.Penetration.ToVector2F());
                    weaponCache.ProtoWeapon
                    .SharedOnHit(weaponCache,
                                 damagedObject,
                                 damageApplied,
                                 hitData,
                                 out var isDamageStop);

                    if (isDamageStop)
                    {
                        obstacleBlockDamageCoef = 1;
                    }

                    if (IsServer)
                    {
                        if (damageApplied > 0 &&
                            damagedObject is ICharacter damagedCharacter)
                        {
                            CharacterUnstuckSystem.ServerTryCancelUnstuckRequest(damagedCharacter);
                        }

                        if (damageApplied > 0)
                        {
                            // give experience for damage
                            protoWeaponSkill?.ServerOnDamageApplied(playerCharacterSkills,
                                                                    damagedObject,
                                                                    damageApplied);
                        }
                    }

                    if (obstacleBlockDamageCoef < 0 ||
                        obstacleBlockDamageCoef > 1)
                    {
                        Logger.Error(
                            "Obstacle block damage coefficient should be >= 0 and <= 1 - wrong calculation by "
                            + damageableProto);
                        break;
                    }

                    hitObjects.Add(hitData);

                    if (isMeleeWeapon)
                    {
                        // currently melee weapon could attack only one object on the ray
                        isDamageRayStopped = true;
                        break;
                    }

                    damageMultiplier *= 1.0 - obstacleBlockDamageCoef;
                    if (damageMultiplier <= 0)
                    {
                        // target blocked the damage ray
                        isDamageRayStopped = true;
                        break;
                    }
                }
            }

            var shotEndPosition = GetShotEndPosition(isDamageRayStopped,
                                                     hitObjects,
                                                     toPosition,
                                                     isRangedWeapon: !isMeleeWeapon);

            if (hitObjects.Count == 0)
            {
                protoWeapon.SharedOnMiss(weaponCache,
                                         shotEndPosition);
            }

            SharedCallOnWeaponHitOrTrace(character,
                                         protoWeapon,
                                         weaponCache.ProtoAmmo,
                                         shotEndPosition,
                                         hitObjects,
                                         endsWithHit: isDamageRayStopped);

            foreach (var entry in hitObjects)
            {
                if (!entry.IsCliffsHit &&
                    !allHitObjects.Contains(entry.WorldObject))
                {
                    allHitObjects.Add(entry.WorldObject);
                }
            }
        }