Patch 2.5 (#136)
* derelicts-base * WonderBox update v0.7 * White MapPool * ~45-90 generated, 30 mapped * radio receive sounds * default: * add wonderbox to mappool * added tags to cargo airlocks * MORE MORE MORE MORE
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Worldgen.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class BlueprintPlacerComponent : Component
|
||||
{
|
||||
[DataField("blueprint", required: true, customTypeSerializer: typeof(ResPathSerializer))]
|
||||
public ResPath Blueprint = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The components that get added to the target grid.
|
||||
/// </summary>
|
||||
[DataField("components", required: true)]
|
||||
public ComponentRegistry Components { get; } = default!;
|
||||
|
||||
//TODO: Get someone to make this a method on componentregistry that does it Correctly.
|
||||
/// <summary>
|
||||
/// Applies the worldgen config to the given target (presumably a grid.)
|
||||
/// </summary>
|
||||
public void Apply(EntityUid target, ISerializationManager serialization, IEntityManager entityManager, IComponentFactory componentFactory)
|
||||
{
|
||||
// Add all components required by the prototype. Engine update for this whenst.
|
||||
foreach (var data in Components.Values)
|
||||
{
|
||||
var comp = (Component) serialization.CreateCopy(data.Component, notNullableOverride: true);
|
||||
comp.Owner = target;
|
||||
entityManager.AddComponent(target, comp);
|
||||
}
|
||||
}
|
||||
}
|
||||
35
Content.Server/Worldgen/StructurePlacementComponent.cs
Normal file
35
Content.Server/Worldgen/StructurePlacementComponent.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
namespace Content.Server.Worldgen;
|
||||
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class StructurePlacementComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The structures to place into the world.
|
||||
/// </summary>
|
||||
[DataField("structures")] public List<StructureConfig> Structures = new();
|
||||
|
||||
/// <summary>
|
||||
/// Radius around which there should be no objects for placement to succeed.
|
||||
/// </summary>
|
||||
[DataField("safetyRadius")] public int SafetyRadius = 128;
|
||||
|
||||
[DataField("placementRadius")] public int PlacementRadius = 4096;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A single structure's placement config.
|
||||
/// </summary>
|
||||
[DataDefinition]
|
||||
public sealed class StructureConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// The entity to spawn into the world.
|
||||
/// </summary>
|
||||
[DataField("entity", required: true)] public string Entity = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of that entity to spawn.
|
||||
/// </summary>
|
||||
[DataField("amountRange")] public Vector2i AmountRange = Vector2i.One;
|
||||
}
|
||||
37
Content.Server/Worldgen/Systems/BlueprintPlacerSystem.cs
Normal file
37
Content.Server/Worldgen/Systems/BlueprintPlacerSystem.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Content.Server.Worldgen.Components;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Maps;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
|
||||
namespace Content.Server.Worldgen.Systems;
|
||||
|
||||
public sealed class BlueprintPlacerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly MapLoaderSystem _mapLoader = default!;
|
||||
[Dependency] private readonly IComponentFactory _componentFactory = default!;
|
||||
[Dependency] private readonly ISerializationManager _serialization = default!;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<BlueprintPlacerComponent, MapInitEvent>(OnMapInit);
|
||||
}
|
||||
|
||||
private void OnMapInit(EntityUid uid, BlueprintPlacerComponent component, MapInitEvent args)
|
||||
{
|
||||
var xform = Transform(uid);
|
||||
var options = new MapLoadOptions()
|
||||
{
|
||||
LoadMap = false,
|
||||
Offset = xform.WorldPosition,
|
||||
Rotation = xform.LocalRotation,
|
||||
};
|
||||
|
||||
_mapLoader.TryLoad(xform.MapID, component.Blueprint.ToString(), out var root, options);
|
||||
|
||||
if (root is null)
|
||||
return;
|
||||
|
||||
component.Apply(root[0], _serialization, EntityManager, _componentFactory);
|
||||
}
|
||||
}
|
||||
79
Content.Server/Worldgen/Systems/StructurePlacementSystem.cs
Normal file
79
Content.Server/Worldgen/Systems/StructurePlacementSystem.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Worldgen.Components;
|
||||
using Content.Server.Worldgen.Tools;
|
||||
using Content.Shared.Database;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Worldgen.Systems;
|
||||
|
||||
public sealed class StructurePlacementSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly PoissonDiskSampler _sampler = default!;
|
||||
[Dependency] private readonly IAdminLogManager _log = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
[Dependency] private readonly IMapManager _map = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
private ISawmill _sawmill = default!;
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<StructurePlacementComponent, MapInitEvent>(OnMapInit);
|
||||
_sawmill = _logManager.GetSawmill("worldgen.structures");
|
||||
}
|
||||
|
||||
private void OnMapInit(EntityUid uid, StructurePlacementComponent component, MapInitEvent args)
|
||||
{
|
||||
if (!HasComp<WorldControllerComponent>(uid))
|
||||
return;
|
||||
|
||||
var totalLocations = (int)(component.Structures.Sum(x => x.AmountRange.Y) * 2f);
|
||||
|
||||
var locations = GetRandomValidPoints(uid, component, totalLocations);
|
||||
var mapId = Comp<MapComponent>(uid).MapId;
|
||||
var safetyBox = Box2.UnitCentered.Enlarged(component.SafetyRadius);
|
||||
|
||||
foreach (var config in component.Structures)
|
||||
{
|
||||
var toPlace = _random.Next(config.AmountRange.X, config.AmountRange.Y);
|
||||
|
||||
while (toPlace != 0)
|
||||
{
|
||||
var point = _random.PickAndTake(locations);
|
||||
var fail = _map.FindGridsIntersecting(mapId, safetyBox.Translated(point)).Any();
|
||||
if (fail)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var ent = Spawn(config.Entity, new MapCoordinates(point, mapId));
|
||||
_log.Add(LogType.EntitySpawn, LogImpact.Medium, $"Spawned {ToPrettyString(ent)} at {new MapCoordinates(point, mapId)} for {ToPrettyString(uid)}.");
|
||||
toPlace--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Vector2> GetRandomValidPoints(EntityUid uid, StructurePlacementComponent component, int amount)
|
||||
{
|
||||
var points = new List<Vector2>();
|
||||
|
||||
var sample = _sampler.SampleCircle(Vector2.Zero, component.PlacementRadius, component.SafetyRadius);
|
||||
|
||||
while (sample.MoveNext(out var point))
|
||||
{
|
||||
points.Add(point.Value);
|
||||
}
|
||||
|
||||
if (points.Count < amount)
|
||||
{
|
||||
_sawmill.Error($"Failed to place {amount} points as {ToPrettyString(uid)}, attempting to continue anyways!");
|
||||
}
|
||||
|
||||
_sawmill.Info($"Placing {amount} debris at {points.Count} locations as {ToPrettyString(uid)}.");
|
||||
|
||||
return points;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user