/// <summary> /// Server spawn callback for static object. /// </summary> /// <param name="trigger">Trigger leading to this spawn.</param> /// <param name="zone">Server zone instance.</param> /// <param name="protoStaticWorldObject">Prototype of static object to spawn.</param> /// <param name="tilePosition">Position to try spawn at.</param> protected IGameObjectWithProto ServerSpawnStaticObject( IProtoTrigger trigger, IServerZone zone, IProtoStaticWorldObject protoStaticWorldObject, Vector2Ushort tilePosition) { foreach (var tileOffset in protoStaticWorldObject.Layout.TileOffsets) { // ensure that each tile in object layout is inside the zone if (tileOffset != Vector2Int.Zero && !zone.IsContainsPosition(tilePosition.AddAndClamp(tileOffset))) { // some tile is outside the zone return(null); } } if (!protoStaticWorldObject.CheckTileRequirements( tilePosition, character: null, logErrors: false)) { // cannot spawn static object there return(null); } var spawnedObject = ServerWorldService.CreateStaticWorldObject(protoStaticWorldObject, tilePosition); if (spawnedObject == null) { // cannot spawn static object there return(null); } // if spawned a vegetation - set random growth progress if (protoStaticWorldObject is IProtoObjectVegetation protoVegetation) { double growProgress; if (trigger == null || trigger is TriggerWorldInit) { // world initialization spawn growProgress = RandomHelper.RollWithProbability(0.6) ? 1 // 60% are spawned in full grown state : Random.Next(0, 11) / 10.0; // other are spawned with random growth progress } else { // spawn saplings growProgress = 0; } protoVegetation.ServerSetGrowthProgress(spawnedObject, growProgress); } ServerDecalsDestroyHelper.DestroyAllDecals(tilePosition, protoStaticWorldObject.Layout); return(spawnedObject); }
protected static bool ServerCheckNoEventsInZone(IServerZone zoneInstance, List <ILogicObject> events) { foreach (var activeEvent in events) { var publicState = activeEvent.GetPublicState <EventWithAreaPublicState>(); if (zoneInstance.IsContainsPosition(publicState.AreaEventOriginalPosition)) { // this event is in the same biome return(false); } } return(true); }
public Vector2Ushort GetRandomPositionInside(IServerZone zone, Random random) { var start = this.StartPosition; Vector2Ushort result; do { result = new Vector2Ushort( (ushort)random.Next(start.X, start.X + SpawnZoneAreaSize), (ushort)random.Next(start.Y, start.Y + SpawnZoneAreaSize)); }while (!zone.IsContainsPosition(result)); return(result); }
/// <summary> /// Get all (already populated) areas with their objects inside the zone /// </summary> private async Task ServerFillSpawnAreasInZoneAsync( IServerZone zone, IReadOnlyDictionary <Vector2Ushort, SpawnZoneArea> areas, Func <Task> callbackYieldIfOutOfTime) { // this is a heavy method so we will try to yield every 100 objects to reduce the load const int defaultCounterToYieldValue = 100; var counterToYield = defaultCounterToYieldValue; // this check has a problem - it returns only objects strictly inside the zone, // but we also need to consider objects nearby the zone for restriction presets //await zone.PopulateStaticObjectsInZone(tempList, callbackYieldIfOutOfTime); TempListAllStaticWorldObjects.Clear(); await Api.Server.World.GetStaticWorldObjectsAsync(TempListAllStaticWorldObjects); foreach (var staticObject in TempListAllStaticWorldObjects) { await YieldIfOutOfTime(); if (staticObject.IsDestroyed) { continue; } var position = staticObject.TilePosition; var area = GetArea(position, isMobTrackingEnumeration: false); if (area is null) { continue; } var protoStaticWorldObject = staticObject.ProtoStaticWorldObject; if (!(protoStaticWorldObject is ObjectGroundItemsContainer)) { if (protoStaticWorldObject.IsIgnoredBySpawnScripts) { // we don't consider padding to certain objects such as ground decals // (though they still might affect spawn during the tiles check) continue; } // create entry for regular static object var preset = this.FindPreset(protoStaticWorldObject); if (preset != null && preset.Density > 0 && !zone.IsContainsPosition(staticObject.TilePosition)) { // this object is a part of the preset spawn list but it's not present in the zone // don't consider this object // TODO: this might cause a problem if there is a padding to this object check continue; } area.Add(preset, position); continue; } // ground container object var itemsContainer = ObjectGroundItemsContainer.GetPublicState(staticObject).ItemsContainer; foreach (var item in itemsContainer.Items) { // create entry for each item in the ground container var preset = this.FindPreset(item.ProtoItem); if (preset != null && preset.Density > 0 && !zone.IsContainsPosition(staticObject.TilePosition)) { // this object is a part of the preset spawn list but it's not present in the zone // don't consider this object continue; } area.Add(preset, position); } } var mobsTrackingManager = SpawnedMobsTrackingManagersStore.Get(this, zone); foreach (var mob in mobsTrackingManager.EnumerateAll()) { await YieldIfOutOfTime(); var position = mob.TilePosition; var area = GetArea(position, isMobTrackingEnumeration: true); area?.Add(this.FindPreset(mob.ProtoCharacter), position); } return; SpawnZoneArea GetArea(Vector2Ushort tilePosition, bool isMobTrackingEnumeration) { var zoneChunkStartPosition = SpawnZoneArea.CalculateStartPosition(tilePosition); if (areas.TryGetValue(zoneChunkStartPosition, out var area)) { return(area); } if (isMobTrackingEnumeration) { return(null); } return(null); // throw new Exception("No zone area found for " + tilePosition); //var newArea = new SpawnZoneArea(zoneChunkStartPosition, zoneChunk); //areas.Add(newArea); //return newArea; } Task YieldIfOutOfTime() { if (--counterToYield > 0) { return(Task.CompletedTask); } counterToYield = defaultCounterToYieldValue; return(callbackYieldIfOutOfTime()); } }