Files
OpenRA/OpenRA.Mods.Common/Traits/World/ClearMapGenerator.cs
Ashley Newson 25571df2b6 Refactor ExperimentalMapGenerator into reusable methods
This change lifts large portions of ExperimentalMapGenerator's logic
into a new "Terraformer" class with highly documented methods that can
theoretically be used by alternative map generator classes. Some
additional refactoring may occur in future, subject to the practical
needs of additional map generators. ClearMapGenerator is also
simplified.

This is not a pure refactor and contains some algorithmic and
behavioral changes, as well as few minor bug fixes. Notably:

- The logic for obstructing unreachable water has been somewhat
  replaced.

- In CnC, where water is already unplayable, EMG no longer obstructs
  water. (RA still does, as water is playable there.)

- Mountain (cliff) generation is now somewhat more effective. This
  increases the number of cliffs seen on many presets. Settings should
  no longer use "Mountains: 1000".

- PlayableSpace logic has been consolidated into Terraformer.

- PlayableSpace.Playability no longer exists as PartiallyPlayable
  became redundant. Its uses have been replaced with a simple
  boolean. Consequently, some defunct code and configuration has been
  removed.

- Adjust MultiBrush replaceability contract painting behavior to be
  more intuitive.

- Fix off-by-one error in map bounds computation.

- Fix some usages of mixed up MersenneTwisters.
2025-07-14 20:09:10 +03:00

103 lines
3.2 KiB
C#

#region Copyright & License Information
/*
* Copyright (c) The OpenRA Developers and Contributors
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Mods.Common.MapGenerator;
using OpenRA.Support;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
[TraitLocation(SystemActors.EditorWorld)]
[Desc("A map generator that clears a map.")]
public sealed class ClearMapGeneratorInfo : TraitInfo<ClearMapGenerator>, IEditorMapGeneratorInfo, IEditorToolInfo
{
[FieldLoader.Require]
[Desc("Human-readable name this generator uses.")]
[FluentReference]
public readonly string Name = null;
[FieldLoader.Require]
[Desc("Internal id for this map generator.")]
public readonly string Type = null;
[FieldLoader.Require]
[Desc("Tilesets that are compatible with this map generator.")]
public readonly string[] Tilesets = null;
[FluentReference]
[Desc("The title to use for generated maps.")]
public readonly string MapTitle = "label-random-map";
[Desc("The widget tree to open when the tool is selected.")]
public readonly string PanelWidget = "MAP_GENERATOR_TOOL_PANEL";
// This is purely of interest to the linter.
[FieldLoader.LoadUsing(nameof(FluentReferencesLoader))]
[FluentReference]
public readonly List<string> FluentReferences = null;
[FieldLoader.LoadUsing(nameof(SettingsLoader))]
public readonly MiniYaml Settings;
string IMapGeneratorInfo.Type => Type;
string IMapGeneratorInfo.Name => Name;
string IMapGeneratorInfo.MapTitle => MapTitle;
static MiniYaml SettingsLoader(MiniYaml my)
{
return my.NodeWithKey("Settings").Value;
}
static List<string> FluentReferencesLoader(MiniYaml my)
{
return new MapGeneratorSettings(null, my.NodeWithKey("Settings").Value)
.Options.SelectMany(o => o.GetFluentReferences()).ToList();
}
public IMapGeneratorSettings GetSettings()
{
return new MapGeneratorSettings(this, Settings);
}
public Map Generate(ModData modData, MapGenerationArgs args)
{
var random = new MersenneTwister();
var terrainInfo = modData.DefaultTerrainInfo[args.Tileset];
if (!Exts.TryParseUshortInvariant(args.Settings.NodeWithKey("Tile").Value.Value, out var tileType))
throw new YamlException("Illegal tile type");
if (!terrainInfo.TryGetTerrainInfo(new TerrainTile(tileType, 0), out var _))
throw new MapGenerationException("Illegal tile type");
var map = new Map(modData, terrainInfo, args.Size);
var terraformer = new Terraformer(args, map, modData, [], Symmetry.Mirror.None, 1);
terraformer.InitMap();
foreach (var mpos in map.AllCells.MapCoords)
map.Tiles[mpos] = terraformer.PickTile(random, tileType);
terraformer.BakeMap();
return map;
}
string IEditorToolInfo.Label => Name;
string IEditorToolInfo.PanelWidget => PanelWidget;
string[] IEditorMapGeneratorInfo.Tilesets => Tilesets;
}
public class ClearMapGenerator { /* we're only interested in the Info */ }
}