示例#1
0
        private static bool IsAreaLocalDensityExceeded(
            SpawnRequest spawnRequest,
            ObjectSpawnPreset preset,
            SpawnZoneArea area,
            out double countToSpawnRemains)
        {
            var spawnedObjectsCount      = area.WorldObjectsByPreset.Find(preset)?.Count ?? 0;
            var desiredObjectsCountFloat = area.ZoneTilesCount * spawnRequest.Density;
            var desiredObjectsCount      = (int)Math.Round(desiredObjectsCountFloat, MidpointRounding.AwayFromZero);

            if (desiredObjectsCount == 0 &&
                preset.SpawnAtLeastOnePerSector &&
                preset.PresetUseSectorDensity &&
                desiredObjectsCountFloat > 0)
            {
                // spawn at least a single object
                desiredObjectsCount = 1;
            }

            countToSpawnRemains = desiredObjectsCount - spawnedObjectsCount;
            return(countToSpawnRemains <= 0);
        }
        private static bool ServerIsCanSpawn(
            SpawnRequest spawnRequest,
            ObjectSpawnPreset preset,
            IReadOnlyDictionary <Vector2Ushort, SpawnZoneArea> spawnZoneAreas,
            Vector2Ushort spawnPosition,
            IPhysicsSpace physicsSpace,
            out SpawnZoneArea resultSpawnArea,
            out bool isSectorDensityExceeded)
        {
            if (ServerWorldService.GetTile(spawnPosition)
                .IsCliffOrSlope)
            {
                // quick discard - don't spawn on cliff or slope
                resultSpawnArea         = null;
                isSectorDensityExceeded = false;
                return(false);
            }

            var presetPadding             = preset.Padding;
            var presetCustomObjectPadding = preset.CustomObjectPadding;

            resultSpawnArea = null;
            var resultSpawnAreaStartPosition = SpawnZoneArea.CalculateStartPosition(spawnPosition);

            foreach (var area in EnumerateAdjacentZoneAreas(resultSpawnAreaStartPosition, spawnZoneAreas))
            {
                foreach (var nearbyPreset in area.WorldObjectsByPreset)
                {
                    var    nearbyObjectPreset = nearbyPreset.Key;
                    double padding;

                    if (nearbyObjectPreset != null)
                    {
                        // preset found
                        if (presetCustomObjectPadding.TryGetValue(nearbyObjectPreset, out padding))
                        {
                            // use custom padding value
                        }
                        else
                        {
                            // don't have custom padding
                            padding = Math.Max(presetPadding, nearbyObjectPreset.Padding);
                        }
                    }
                    else
                    {
                        // preset of another object not defined in this spawn list - use default object spawn padding
                        padding = DefaultObjectSpawnPadding;
                    }

                    foreach (var nearbyObjectTilePosition in nearbyPreset.Value)
                    {
                        var distance = spawnPosition.TileSqrDistanceTo(nearbyObjectTilePosition);

                        // Actually using < will be more correct, but it will produce not so nice-looking result
                        // (objects could touch each other on each side).
                        // So we insist objects must don't even touch each other on their
                        // left/up/right/down edges (but the diagonal corners touch is ok).
                        if (distance <= padding * padding)
                        {
                            // too close
                            isSectorDensityExceeded = false;
                            return(false);
                        }
                    }
                }

                if (resultSpawnAreaStartPosition == area.StartPosition)
                {
                    resultSpawnArea = area;
                }
            }

            var needToCheckLandClaimPresence = true;

            if (preset.IsContainsOnlyStaticObjects)
            {
                needToCheckLandClaimPresence = !ServerWorldService.GetTile(spawnPosition)
                                               .ProtoTile
                                               .IsRestrictingConstruction;
            }

            if (needToCheckLandClaimPresence &&
                ServerCheckLandClaimAreaPresence(spawnPosition, preset.PaddingToLandClaimAreas))
            {
                // the land is claimed by players
                resultSpawnArea         = null;
                isSectorDensityExceeded = false;
                return(false);
            }

            if (preset.CustomCanSpawnCheckCallback != null &&
                !preset.CustomCanSpawnCheckCallback(physicsSpace, spawnPosition))
            {
                // custom spawn check failed
                resultSpawnArea         = null;
                isSectorDensityExceeded = false;
                return(false);
            }

            if (resultSpawnArea == null)
            {
                // no area exist (will be created)
                isSectorDensityExceeded = false;
                return(true);
            }

            if (!spawnRequest.UseSectorDensity)
            {
                isSectorDensityExceeded = false;
                return(true);
            }

            // ensure that the area/sector density is not exceeded for this spawn preset
            isSectorDensityExceeded = IsAreaLocalDensityExceeded(spawnRequest,
                                                                 preset,
                                                                 resultSpawnArea,
                                                                 out var countToSpawnRemains);
            if (isSectorDensityExceeded)
            {
                // already spawned too many objects of the required type in the area
                return(false);
            }

            if (countToSpawnRemains < 1)
            {
                // density allows to spawn an extra object of this type with some small probability
                if (!RandomHelper.RollWithProbability(countToSpawnRemains))
                {
                    return(false);
                }
            }

            return(true);
        }