Enemy Loadout Generation

Modified zone generator to scale the radius and mass of a zone according to galaxy density
Added loadout generator which procedurally generates ships and turrets
Generating 3 randomized ships in each occupied zone
Fixed DatabaseCache.GetAll for parent types
Fixed wormhole traversal bug for returning to previous zone (ZoneRenderer subscriptions not being properly disposed)
This commit is contained in:
Reinier Vens 2021-03-18 00:36:34 +00:00
commit ebde23a64d
25 changed files with 5421 additions and 148 deletions

View file

@ -38,7 +38,7 @@
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Presets\Default Work Unit.wwu" DateLow="1614440366" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Modulators\Default Work Unit.wwu" DateLow="1615759855" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Mixing Sessions\Default Work Unit.wwu" DateLow="1614440366" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Master-Mixer Hierarchy\Default Work Unit.wwu" DateLow="1614440366" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Master-Mixer Hierarchy\Default Work Unit.wwu" DateLow="1615918589" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Interactive Music Hierarchy\Default Work Unit.wwu" DateLow="1614440366" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Game Parameters\test_paramenters.wwu" DateLow="1615582814" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Game Parameters\item_properties.wwu" DateLow="1615908789" DateHigh="0"/>
@ -53,9 +53,9 @@
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Conversion Settings\Default Work Unit.wwu" DateLow="1614440366" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Control Surface Sessions\Default Work Unit.wwu" DateLow="1614449286" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Audio Devices\Default Work Unit.wwu" DateLow="1614440366" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Attenuations\Default Work Unit.wwu" DateLow="1614440366" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Attenuations\Default Work Unit.wwu" DateLow="1615918589" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Aetheria-Economy_WwiseProject.wproj" DateLow="1615891381" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Aetheria-Economy_WwiseProject.rwvens.wsettings" DateLow="1615912046" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Actor-Mixer Hierarchy\Default Work Unit.wwu" DateLow="1615908590" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Aetheria-Economy_WwiseProject.rwvens.wsettings" DateLow="1615983944" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Actor-Mixer Hierarchy\Default Work Unit.wwu" DateLow="1615918589" DateHigh="0"/>
<ValidationCacheItem File="E:\Projects\Aetheria-Economy\Aetheria-Economy_WwiseProject\Actor-Mixer Hierarchy\copy_Unit.wwu" DateLow="1615582814" DateHigh="0"/>
</ValidationCache>

View file

@ -53,7 +53,7 @@
<Property Name="GenerateSoundBanks\x64_SelectedPlatforms" Type="string" Value="74wppGGLGUKocCTUjliE6atk2Ww+IVRJs5fEQCA5KRI="/>
<Property Name="GenerateSoundBanks\x64_SelectedSoundBanks" Type="string" Value="pECI+qlGXkW/iNcjni5tciEME4bdgbhNkCrxcszXlmY="/>
<Property Name="HardwareController\CurrentSession" Type="string" Value="{2451DD2E-A7B2-45E6-B93B-6F49B9B887AD}"/>
<Property Name="HardwareController\{2451DD2E-A7B2-45E6-B93B-6F49B9B887AD}\x64_ActiveGroups" Type="string" Value="sahohopAK0WRE4XvXPYF/QGOFFX/////+lZlPDTFnUSwqLpTpFltuQGOFFX/////"/>
<Property Name="HardwareController\{2451DD2E-A7B2-45E6-B93B-6F49B9B887AD}\x64_ActiveGroups" Type="string" Value="sahohopAK0WRE4XvXPYF/QGO2GH/////+lZlPDTFnUSwqLpTpFltuQGO2GH/////"/>
<Property Name="MeterView\LastObject1" Type="string" Value="{1514A4D8-1DA6-412A-A17E-75CA0C2149F3}"/>
<Property Name="MeterView\MeterMode1" Type="int32" Value="1"/>
<Property Name="MeterView\MeterMode1Viewpoint0" Type="int32" Value="1"/>
@ -84,7 +84,7 @@
<Property Name="ProjectExplorer\x64_Expanded_1_1" Type="string" Value=""/>
<Property Name="ProjectExplorer\x64_Expanded_20_1" Type="string" Value=""/>
<Property Name="ProjectExplorer\x64_Expanded_21_1" Type="string" Value=""/>
<Property Name="ProjectExplorer\x64_Expanded_2_1" Type="string" Value="LUxWNckbu0CzZdnEpHrl8Y6W+RB4AExBtz0hqhzQnTgfm2wHRlXaQ4qS5KHJs/1C1NZhQsO9I0S6a6kt4hgaITa76TSSfTFGmW+S7kaWjHFKMlj1jt3QRrmn5BzObd7fOy3OxixQxUyBWrAdEcFX7g=="/>
<Property Name="ProjectExplorer\x64_Expanded_2_1" Type="string" Value="LUxWNckbu0CzZdnEpHrl8Y6W+RB4AExBtz0hqhzQnTjU1mFCw70jRLprqS3iGBohNrvpNJJ9MUaZb5LuRpaMcUoyWPWO3dBGuafkHM5t3t87Lc7GLFDFTIFasB0RwVfu"/>
<Property Name="ProjectExplorer\x64_Expanded_3_1" Type="string" Value="Bu5AEWkklUeSUAxyv/rvG7MXcgrHUgxKmWb1r37MmPA="/>
<Property Name="ProjectExplorer\x64_Expanded_4_1" Type="string" Value="AlekTQhF7EqFkQdJV+6xTg=="/>
<Property Name="ProjectExplorer\x64_Expanded_5_1" Type="string" Value=""/>
@ -96,7 +96,7 @@
<Property Name="RTPC\GameParameterSimValue\{778F5836-B82F-46F8-936A-E8581E9DA7A9}" Type="Real64" Value="1"/>
<Property Name="RTPC\GameParameterSimValue\{B907BE30-367C-4955-AF3B-AF6B2806F9D5}" Type="Real64" Value="100"/>
<Property Name="RTPC\GameParameterSimValue\{BFC68604-C477-4B9B-B488-F5B4A9ADEAA4}" Type="Real64" Value="1"/>
<Property Name="RTPC\GameParameterSimValue\{FC156F43-A577-4DCB-B6E8-84E4072A38C9}" Type="Real64" Value="2.1"/>
<Property Name="RTPC\GameParameterSimValue\{FC156F43-A577-4DCB-B6E8-84E4072A38C9}" Type="Real64" Value="10"/>
<Property Name="SoundBank Manager\x64_Expand States" Type="string" Value="PdunN+1Z302GveAHIPhfIw=="/>
<Property Name="SoundBankHeaderFilePath" Type="string" Value="GeneratedSoundBanks\"/>
<Property Name="SoundBankPaths" Type="string">

View file

@ -86,7 +86,7 @@ Material:
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _Scale: 6.029707
- _Scale: 2.0349123
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7d28d5171875a404684a7909ee631808
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/Resources/Settings.asset (Stored with Git LFS)

Binary file not shown.

View file

@ -14929,7 +14929,7 @@ RectTransform:
m_GameObject: {fileID: 1005841431}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_LocalScale: {x: 1.75, y: 1.75, z: 1}
m_Children:
- {fileID: 2124945556}
- {fileID: 445770198}
@ -15880,8 +15880,8 @@ MonoBehaviour:
m_Calls: []
m_text: Executive
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: f65e20c70af9671428dd62c7c635e417, type: 2}
m_sharedMaterial: {fileID: 21790448164444372, guid: f65e20c70af9671428dd62c7c635e417,
m_fontAsset: {fileID: 11400000, guid: 53555f7a2d5e745428813f1b1118734f, type: 2}
m_sharedMaterial: {fileID: -2804126062856497447, guid: 53555f7a2d5e745428813f1b1118734f,
type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
@ -18252,8 +18252,8 @@ MonoBehaviour:
m_Calls: []
m_text: Start
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: f65e20c70af9671428dd62c7c635e417, type: 2}
m_sharedMaterial: {fileID: 21790448164444372, guid: f65e20c70af9671428dd62c7c635e417,
m_fontAsset: {fileID: 11400000, guid: 53555f7a2d5e745428813f1b1118734f, type: 2}
m_sharedMaterial: {fileID: -2804126062856497447, guid: 53555f7a2d5e745428813f1b1118734f,
type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
@ -19180,8 +19180,8 @@ MonoBehaviour:
m_Calls: []
m_text: Terminus
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: f65e20c70af9671428dd62c7c635e417, type: 2}
m_sharedMaterial: {fileID: 21790448164444372, guid: f65e20c70af9671428dd62c7c635e417,
m_fontAsset: {fileID: 11400000, guid: 53555f7a2d5e745428813f1b1118734f, type: 2}
m_sharedMaterial: {fileID: -2804126062856497447, guid: 53555f7a2d5e745428813f1b1118734f,
type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
@ -19652,8 +19652,8 @@ MonoBehaviour:
m_Calls: []
m_text: Home Zone
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: f65e20c70af9671428dd62c7c635e417, type: 2}
m_sharedMaterial: {fileID: 21790448164444372, guid: f65e20c70af9671428dd62c7c635e417,
m_fontAsset: {fileID: 11400000, guid: 53555f7a2d5e745428813f1b1118734f, type: 2}
m_sharedMaterial: {fileID: -2804126062856497447, guid: 53555f7a2d5e745428813f1b1118734f,
type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
@ -23284,8 +23284,8 @@ MonoBehaviour:
m_Calls: []
m_text: Corporation
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: f65e20c70af9671428dd62c7c635e417, type: 2}
m_sharedMaterial: {fileID: 21790448164444372, guid: f65e20c70af9671428dd62c7c635e417,
m_fontAsset: {fileID: 11400000, guid: 53555f7a2d5e745428813f1b1118734f, type: 2}
m_sharedMaterial: {fileID: -2804126062856497447, guid: 53555f7a2d5e745428813f1b1118734f,
type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}

View file

@ -249,7 +249,7 @@ PrefabInstance:
- target: {fileID: 878382121558056004, guid: 2758dfa2744d7ad4d8877545189d116e,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 60.98
value: 0
objectReference: {fileID: 0}
- target: {fileID: 878382121558056004, guid: 2758dfa2744d7ad4d8877545189d116e,
type: 3}
@ -1302,8 +1302,8 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 741153267}
m_LocalRotation: {x: 0.015506897, y: 0.9502416, z: -0.30741316, w: 0.047933206}
m_LocalPosition: {x: -117.52, y: -77.08742, z: 149.09026}
m_LocalRotation: {x: 0.015506926, y: 0.9502416, z: -0.30741316, w: 0.047933295}
m_LocalPosition: {x: -117.52003, y: -77.08742, z: 149.09026}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 412917866}
@ -1773,8 +1773,8 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 965376321}
m_LocalRotation: {x: 0.015506897, y: 0.9502416, z: -0.30741316, w: 0.047933206}
m_LocalPosition: {x: -117.52, y: -77.08742, z: 149.09026}
m_LocalRotation: {x: 0.015506926, y: 0.9502416, z: -0.30741316, w: 0.047933295}
m_LocalPosition: {x: -117.52003, y: -77.08742, z: 149.09026}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
@ -2015,8 +2015,8 @@ MonoBehaviour:
ZoneCount: 128
NameGeneratorMinLength: 5
NameGeneratorMaxLength: 10
NameGeneratorOrder: 4
MegaCount: 6
NameGeneratorOrder: 3
MegaCount: 12
BossCount: 3
NoisePosition: 0
CloudExponent: 10
@ -2737,7 +2737,7 @@ PrefabInstance:
- target: {fileID: 878382121558056004, guid: 2758dfa2744d7ad4d8877545189d116e,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 55.675
value: 0
objectReference: {fileID: 0}
- target: {fileID: 878382121558056004, guid: 2758dfa2744d7ad4d8877545189d116e,
type: 3}

View file

@ -19,6 +19,7 @@ using UnityEngine.UI;
using Unity.Mathematics;
using static Unity.Mathematics.math;
using float2 = Unity.Mathematics.float2;
using float3 = Unity.Mathematics.float3;
using quaternion = Unity.Mathematics.quaternion;
using Random = UnityEngine.Random;
@ -262,7 +263,7 @@ public class ActionGameManager : MonoBehaviour
ship.OnEnteredWormhole += () =>
{
GenerateLevel(wormhole.Target);
ship.ExitWormhole(ZoneRenderer.WormholeInstances.Keys.First(w=>w.Target==Zone.SectorZone).Position,
ship.ExitWormhole(ZoneRenderer.WormholeInstances.Keys.First(w=>w.Target==oldZone.SectorZone).Position,
Settings.GameplaySettings.WormholeExitVelocity * ItemManager.Random.NextFloat2Direction());
CurrentEntity.Zone = Zone;
};
@ -448,37 +449,28 @@ public class ActionGameManager : MonoBehaviour
StartGame();
}
public void GenerateLevel(SectorZone sectorZone = null)
public void GenerateLevel(SectorZone sectorZone)
{
if (sectorZone != null)
if (sectorZone == null) throw new ArgumentNullException(nameof(sectorZone));
if (sectorZone.Contents == null)
{
if (sectorZone.Contents == null)
{
sectorZone.PackedContents ??= ZoneGenerator.GenerateZone(
settings: Settings.ZoneSettings,
mass: Settings.DefaultZoneMass,
radius: Settings.DefaultZoneRadius
);
sectorZone.Contents = new Zone(ItemManager, Settings.PlanetSettings, sectorZone.PackedContents, sectorZone);
}
Zone = sectorZone.Contents;
}
else
{
var zonePack = ZoneGenerator.GenerateZone(
settings: Settings.ZoneSettings,
mass: Settings.DefaultZoneMass,
radius: Settings.DefaultZoneRadius
sectorZone.PackedContents ??= ZoneGenerator.GenerateZone(
ItemManager,
Settings.ZoneSettings,
CurrentSector,
sectorZone
);
Zone = new Zone(ItemManager, Settings.PlanetSettings, zonePack, sectorZone);
sectorZone.Contents = new Zone(ItemManager, Settings.PlanetSettings, sectorZone.PackedContents, sectorZone);
}
Zone = sectorZone.Contents;
Zone.Log = s => Debug.Log($"Zone: {s}");
if (CurrentEntity != null)
{
CurrentEntity.Deactivate();
CurrentEntity.Zone?.Entities.Remove(CurrentEntity);
CurrentEntity.Zone.Entities.Remove(CurrentEntity);
CurrentEntity.Zone = Zone;
Zone.Entities.Add(CurrentEntity);
CurrentEntity.Activate();
@ -525,15 +517,6 @@ public class ActionGameManager : MonoBehaviour
// zone.Agents.Add(CreateAgent(enemyShip));
}
private Agent CreateAgent(Ship ship)
{
var agent = new Minion(ship);
var task = new PatrolOrbitsTask();
task.Circuit = Zone.Orbits.OrderBy(_ => Random.value).Take(4).Select(x => x.Key).ToArray();
agent.Task = task;
return agent;
}
private void StartGame()
{
if (CurrentSector != null)
@ -542,6 +525,7 @@ public class ActionGameManager : MonoBehaviour
{
GenerateLevel(CurrentSector.Entrance);
var ship = EntitySerializer.Unpack(ItemManager, Zone, Loadouts.First(x => x.Name == StarterShipTemplate), true);
ship.Position = float3.zero;
ship.Zone = Zone;
Zone.Entities.Add(ship);
ship.Activate();
@ -557,7 +541,6 @@ public class ActionGameManager : MonoBehaviour
BindToEntity(targetEntity);
}
}
else GenerateLevel();
// var stationType = Database.GetAll<HullData>().First(x=>x.HullType==HullType.Station);
// var stationHull = ItemManager.CreateInstance(stationType) as EquippableItem;

View file

@ -13,8 +13,6 @@ public class GameSettings : ScriptableObject
public float HeatstrokePhasingFloor = 0;
public float HeatstrokePhasingFrequency = 5;
public float WormholeDistanceRatio;
public float DefaultZoneRadius;
public float DefaultZoneMass;
public float DefaultViewDistance;
public float MinimapZoneGravityRange;
public float[] MinimapZoomLevels;

View file

@ -76,6 +76,7 @@ public class ZoneRenderer : MonoBehaviour
private bool _rootFound;
private Entity _perspectiveEntity;
private IDisposable[] _perspectiveSubscriptions = new IDisposable[2];
private List<IDisposable> _zoneSubscriptions = new List<IDisposable>();
public Dictionary<Wormhole, GameObject> WormholeInstances = new Dictionary<Wormhole, GameObject>();
@ -184,9 +185,20 @@ public class ZoneRenderer : MonoBehaviour
}
foreach(var entity in zone.Entities)
{
Debug.Log($"Loading entity {entity.Name} from existing zone entity collection");
LoadEntity(entity);
zone.Entities.ObserveAdd().Subscribe(e => LoadEntity(e.Value));
zone.Entities.ObserveRemove().Subscribe(e => UnloadEntity(e.Value));
}
_zoneSubscriptions.Add(zone.Entities.ObserveAdd().Subscribe(e =>
{
//Debug.Log($"Loading entity {e.Value.Name} from zone add event");
LoadEntity(e.Value);
}));
_zoneSubscriptions.Add(zone.Entities.ObserveRemove().Subscribe(e =>
{
//Debug.Log($"Unloading entity {e.Value.Name} from zone remove event");
UnloadEntity(e.Value);
}));
if(zone.SectorZone != null)
{
@ -196,7 +208,7 @@ public class ZoneRenderer : MonoBehaviour
AddWormhole(new Wormhole
{
Target = adjacentZone,
Position = dir * Settings.DefaultZoneRadius * Settings.WormholeDistanceRatio
Position = dir * zone.Pack.Radius * Settings.WormholeDistanceRatio
});
}
}
@ -214,9 +226,14 @@ public class ZoneRenderer : MonoBehaviour
if (Zone == null) return;
foreach (var wormhole in WormholeInstances.Values) Destroy(wormhole);
WormholeInstances.Clear();
foreach(var subscription in _zoneSubscriptions)
subscription.Dispose();
_zoneSubscriptions.Clear();
foreach (var entity in Zone.Entities)
{
Debug.Log($"Unloading entity {entity.Name} from entities remaining during clear!");
UnloadEntity(entity);
}

View file

@ -107,6 +107,11 @@ public class DatabaseCache
{
_entries[entry.ID] = entry;
_types[type].Add(entry);
foreach (var parentType in type.GetParentTypes())
{
if(_types.ContainsKey(parentType))
_types[parentType].Add(entry);
}
if (remote)
{

View file

@ -405,7 +405,7 @@ public abstract class Entity
var itemShapeInset = hullData.Shape.Inset(itemData.Shape, hullCoord, item.Rotation);
var hardpointShapeInset = hullData.Shape.Inset(hardpoint.Shape, hardpoint.Position);
// Check every cell of the hardpoint shape
// Check every cell of the hardpoint shape for existing items
foreach(var v in hardpointShapeInset.Coordinates)
if (GearOccupancy[v.x, v.y] != null)
return false;

View file

@ -32,31 +32,32 @@ public static class Extensions
public static T[] WeightedRandomElements<T>(this IEnumerable<T> collection, ref Random random, Func<T, float> weightFunction, int count)
{
var weights = new Dictionary<T, float>(collection.Count());
var elements = collection as T[] ?? collection.ToArray();
var weights = new Dictionary<T, float>(elements.Length);
var totalWeight = 0f;
foreach (var x in collection)
foreach (var x in elements)
{
weights[x] = weightFunction(x);
totalWeight += weights[x];
}
var elements = new T[count];
var randomElements = new T[count];
for (int i = 0; i < count; i++)
{
var targetWeight = random.NextFloat(totalWeight);
var accumWeight = 0f;
foreach (var x in collection)
foreach (var x in elements)
{
accumWeight += weights[x];
if (accumWeight > targetWeight)
{
elements[i] = x;
randomElements[i] = x;
break;
}
}
}
return elements;
return randomElements;
}
// Thanks, https://stackoverflow.com/a/48599119

View file

@ -175,6 +175,50 @@ public class Shape
);
return shape;
}
// TODO: Use the power of math to optimize this function!
// Try to find a rotation and position with which a shape can be placed to fit within another shape
public bool FitsWithin(Shape other, out ItemRotation rotation, out int2 position)
{
// Try every item orientation
foreach(var rot in (ItemRotation[])Enum.GetValues(typeof(ItemRotation)))
{
rotation = rot;
if (FitsWithin(other, rot, out var pos))
{
position = pos;
return true;
}
}
rotation = ItemRotation.None;
position = int2.zero;
return false;
}
// Try to find a position with which a shape can be placed to fit within another shape
public bool FitsWithin(Shape other, ItemRotation rotation, out int2 position)
{
// Try every item position that could possibly fit
for(int x = 0; x < other.Width - Width + 1; x++)
{
for (int y = 0; y < other.Height - Height + 1; y++)
{
position = int2(x, y);
var fits = true;
foreach (var v in Coordinates)
{
fits = fits && other[Rotate(v, rotation) + position];
if (!fits) break;
}
if (fits) return true;
}
}
position = int2.zero;
return false;
}
}
[MessagePackObject,

View file

@ -0,0 +1,155 @@
using System;
using System.Linq;
using Unity.Mathematics;
using static Unity.Mathematics.math;
using Random = Unity.Mathematics.Random;
public class LoadoutGenerator
{
public Random Random;
public ItemManager ItemManager { get; }
public Sector Sector { get; }
public SectorZone Zone { get; }
public MegaCorporation Faction { get; }
public float PriceExponent { get; }
public LoadoutGenerator(
ref Random random,
ItemManager itemManager,
Sector sector,
SectorZone zone,
MegaCorporation faction,
float priceExponent)
{
Random = random;
ItemManager = itemManager;
Sector = sector;
Zone = zone;
Faction = faction;
PriceExponent = priceExponent;
}
public EntityPack GenerateShipLoadout()
{
var hull = ItemManager.CreateInstance(RandomHull(HullType.Ship)) as EquippableItem;
var entity = new Ship(ItemManager, null, hull, ItemManager.GameplaySettings.DefaultEntitySettings);
entity.Faction = Faction;
OutfitEntity(entity);
return EntitySerializer.Pack(entity);
}
public EntityPack GenerateTurretLoadout()
{
var hull = ItemManager.CreateInstance(RandomHull(HullType.Turret)) as EquippableItem;
var entity = new OrbitalEntity(ItemManager, null, hull, Guid.Empty, ItemManager.GameplaySettings.DefaultEntitySettings);
entity.Faction = Faction;
OutfitEntity(entity);
return EntitySerializer.Pack(entity);
}
public HullData RandomHull(HullType type)
{
return ItemManager.ItemData.GetAll<HullData>()
.Where(item => item.HullType == type && (item.Manufacturer == Faction.ID || Faction.Allegiance.ContainsKey(item.Manufacturer)))
.WeightedRandomElements(ref Random,
item =>
(item.Manufacturer == Faction.ID ? 1 : Faction.Allegiance[item.Manufacturer]) / // Prioritize items from allied manufacturers
Zone.Distance[Sector.HomeZones[ItemManager.ItemData.Get<MegaCorporation>(item.Manufacturer)]] / // Penalize distance to manufacturer headquarters
pow(item.Price, PriceExponent), // Penalize item price to a controllable degree
1
).FirstOrDefault();
}
public T RandomItem<T>(Predicate<T> filter = null) where T : EquippableItemData
{
return ItemManager.ItemData.GetAll<T>()
.Where(item => Sector.ContainsFaction(item.Manufacturer) &&
(item.Manufacturer == Faction.ID || Faction.Allegiance.ContainsKey(item.Manufacturer)) &&
(filter?.Invoke(item) ?? true))
.WeightedRandomElements(ref Random, item =>
(item.Manufacturer == Faction.ID ? 1 : Faction.Allegiance[item.Manufacturer]) * // Prioritize items from allied manufacturers
item.Shape.Coordinates.Length / // Prioritize items that fill more of the hardpoint's slots
Zone.Distance[Sector.HomeZones[ItemManager.ItemData.Get<MegaCorporation>(item.Manufacturer)]] / // Penalize distance to manufacturer headquarters
pow(item.Price, PriceExponent), // Penalize item price to a controllable degree
1
).FirstOrDefault();
}
public T RandomItem<T>(HardpointData hardpoint, Predicate<T> filter = null) where T : EquippableItemData
{
return RandomItem<T>(item => item.HardpointType == hardpoint.Type &&
(filter?.Invoke(item) ?? true) &&
item.Shape.FitsWithin(hardpoint.Shape, hardpoint.Rotation, out _));
}
private void OutfitEntity(Entity entity)
{
var hullData = ItemManager.GetData(entity.Hull) as HullData;
foreach (var hardpoint in hullData.Hardpoints)
{
if (hardpoint.Type == HardpointType.ControlModule)
{
var controllerData = RandomItem<GearData>(hardpoint,
item => item.Behaviors.Any(b => entity is Ship && b is CockpitData || entity is OrbitalEntity && b is TurretControllerData));
if (controllerData == null) throw new InvalidLoadoutException("No compatible controller found for entity!");
var controller = ItemManager.CreateInstance(controllerData) as EquippableItem;
if (!entity.TryEquip(controller))
{
throw new InvalidLoadoutException($"Failed to equip selected {Enum.GetName(typeof(HardpointType), hardpoint.Type)}!");
}
}
else
{
var itemData = RandomItem<GearData>(hardpoint);
if (itemData == null) ItemManager.Log($"No compatible item found for entity {Enum.GetName(typeof(HardpointType), hardpoint.Type)} hardpoint!");
else
{
//throw new InvalidLoadoutException($"No compatible item found for entity {Enum.GetName(typeof(HardpointType), hardpoint.Type)} hardpoint!");
var item = ItemManager.CreateInstance(itemData) as EquippableItem;
if (!entity.TryEquip(item))
{
throw new InvalidLoadoutException($"Failed to equip selected {Enum.GetName(typeof(HardpointType), hardpoint.Type)}!");
}
}
}
}
var emptyShape = new Shape(hullData.Shape.Width, hullData.Shape.Height);
foreach (var v in hullData.Shape.Coordinates)
{
if (hullData.InteriorCells[v] && entity.Hardpoints[v.x, v.y] == null)
emptyShape[v] = true;
}
var capacitorData = RandomItem<GearData>(item =>
item.Behaviors.Any(b => b is CapacitorData) &&
item.Shape.FitsWithin(emptyShape, out _, out _));
if (capacitorData == null) throw new InvalidLoadoutException("No compatible capacitor found for entity!");
if(!capacitorData.Shape.FitsWithin(emptyShape, out var capacitorRotation, out var capacitorPosition))
throw new InvalidLoadoutException("Failed to equip selected capacitor!");
var capacitor = ItemManager.CreateInstance(capacitorData) as EquippableItem;
capacitor.Rotation = capacitorRotation;
if (!entity.TryEquip(capacitor, capacitorPosition))
{
throw new InvalidLoadoutException("Failed to equip selected capacitor!");
}
}
}
public class InvalidLoadoutException : Exception
{
public InvalidLoadoutException()
{
}
public InvalidLoadoutException(string message)
: base(message)
{
}
public InvalidLoadoutException(string message, Exception inner)
: base(message, inner)
{
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bbaf437585db46c9986f0a4f2c778444
timeCreated: 1615957107

View file

@ -21,6 +21,7 @@ public class Sector
public SectorZone Entrance { get; }
public SectorZone Exit { get; }
private HashSet<Guid> _containedFactions;
private SectorZone[] _exitPath;
private Dictionary<MegaCorporation, MarkovNameGenerator> _nameGenerators = new Dictionary<MegaCorporation, MarkovNameGenerator>();
@ -249,9 +250,10 @@ public class Sector
if(progressCallback!=null) Thread.Sleep(500); // Inserting Delay to make it seem like it's doing more work lmao
}
private void GenerateSector()
public bool ContainsFaction(Guid factionID)
{
_containedFactions ??= new HashSet<Guid>(Factions.Select(f => f.ID));
return _containedFactions.Contains(factionID);
}
// Cache distance matrix and calculate isolation for every zone (used extensively for placing stuff)

View file

@ -87,8 +87,6 @@ public class SectorGenerationSettings
[Serializable, MessagePackObject(keyAsPropertyName:true), JsonObject]
public class ZoneGenerationSettings
{
public GalaxyShapeSettings ShapeSettings;
public ExponentialCurve PlanetSafetyRadius;
public float MassFloor = 1;
@ -104,6 +102,8 @@ public class ZoneGenerationSettings
public ExponentialLerp ZoneRadius;
public ExponentialLerp ZoneMass;
public ExponentialLerp SubZoneCount;
public float ZoneBoundaryRadius;
public float BeltProbability = .05f;
public float BeltMassCeiling = 500f;

View file

@ -74,11 +74,26 @@ public class Zone
var entity = EntitySerializer.Unpack(_itemManager, this, entityPack);
Entities.Add(entity);
entity.Activate();
if (entity is Ship {IsPlayerShip: false} ship)
{
Agents.Add(CreateAgent(ship));
if (lengthsq(ship.Position) < 1)
ship.Position = _itemManager.Random.NextFloat3(float3(-pack.Radius * .5f), float3(pack.Radius * .5f));
}
}
// TODO: Associate planets with stored entities for planetary colonies
}
private Agent CreateAgent(Ship ship)
{
var agent = new Minion(ship);
var task = new PatrolOrbitsTask();
task.Circuit = Orbits.OrderBy(_ => _itemManager.Random.NextFloat()).Take(4).Select(x => x.Key).ToArray();
agent.Task = task;
return agent;
}
public ZonePack PackZone()
{
return new ZonePack

View file

@ -14,36 +14,8 @@ using static Unity.Mathematics.math;
using float2 = Unity.Mathematics.float2;
using Random = Unity.Mathematics.Random;
public class ZoneGenerator
public static class ZoneGenerator
{
// public static ZonePack GenerateZone(
// ZoneGenerationSettings settings,
// Dictionary<string,GalaxyMapLayerData> mapLayers,
// IEnumerable<SimpleCommodityData> resources,
// string name,
// float2 position)
// {
// var random = new Random(Convert.ToUInt32(abs(name.GetHashCode())));
// var radius = settings.ZoneRadius.Evaluate(random.NextFloat() * mapLayers["Radius"].Evaluate(position, settings.ShapeSettings));
// var mass = settings.ZoneMass.Evaluate(random.NextFloat() * mapLayers["Mass"].Evaluate(position, settings.ShapeSettings));
//
// return GenerateZone(settings, mapLayers, resources, name, position, mass, radius, random);
// }
public static ZonePack GenerateZone(
ZoneGenerationSettings settings,
// Dictionary<string,GalaxyMapLayerData> mapLayers,
// IEnumerable<SimpleCommodityData> resources,
float mass,
float radius)
{
var name = Guid.NewGuid().ToString().Substring(0, 8);
var position = float2(0f);
var random = new Random(Convert.ToUInt32(abs(name.GetHashCode())));
return GenerateZone(settings, name, position, mass, radius, random, 6);
}
private class Circle
{
public float2 Center;
@ -62,35 +34,34 @@ public class ZoneGenerator
}
private const int MaximumPlacementSamples = 32;
private static ZonePack GenerateZone(
ZoneGenerationSettings settings,
// Dictionary<string,GalaxyMapLayerData> mapLayers,
// IEnumerable<SimpleCommodityData> resources,
string name,
float2 position,
float mass,
float radius,
Random random,
int targetSubzoneCount)
{
public static ZonePack GenerateZone(
ItemManager itemManager,
ZoneGenerationSettings zoneSettings,
Sector sector,
SectorZone sectorZone)
{
var pack = new ZonePack();
pack.Radius = radius;
pack.Mass = mass;
var random = new Random(unchecked((uint) sectorZone.Name.GetHashCode()) ^ hash(sectorZone.Position));
var density = saturate(sector.Settings.CloudDensity(sectorZone.Position));
pack.Radius = zoneSettings.ZoneRadius.Evaluate(density);
pack.Mass = zoneSettings.ZoneMass.Evaluate(density);
var targetSubzoneCount = zoneSettings.SubZoneCount.Evaluate(density);
//Debug.Log($"Generating zone at position {zone.Position} with radius {zoneRadius} and mass {zoneMass}");
var planets = new List<GeneratorPlanet>();
if (targetSubzoneCount > 1)
{
var zoneBoundary = new Circle(float2.zero, radius);
var zoneBoundary = new Circle(float2.zero, pack.Radius * zoneSettings.ZoneBoundaryRadius);
float boundaryTangentRadius(float2 point) => -zoneBoundary.DistanceTo(point);
var occupiedAreas = new List<Circle>();
float tangentRadius(float2 point) => min(boundaryTangentRadius(point), occupiedAreas.Min(circle => circle.DistanceTo(point)));
var startPosition = random.NextFloat(radius * .25f, radius * .75f) * random.NextFloat2Direction();
var startPosition = random.NextFloat(pack.Radius * .25f, pack.Radius * .5f) * random.NextFloat2Direction();
occupiedAreas.Add(new Circle(startPosition, boundaryTangentRadius(startPosition)));
int samples = 0;
@ -99,7 +70,7 @@ public class ZoneGenerator
samples = 0;
for (int i = 0; i < MaximumPlacementSamples; i++)
{
var samplePos = random.NextFloat2(-radius, radius);
var samplePos = random.NextFloat2(-pack.Radius, pack.Radius);
var rad = tangentRadius(samplePos);
if (rad > 0)
{
@ -114,11 +85,11 @@ public class ZoneGenerator
var totalArea = occupiedAreas.Sum(c => c.Area);
foreach (var c in occupiedAreas)
{
planets.AddRange(GenerateEntities(settings, ref random, c.Area / totalArea * pack.Mass, c.Radius, c.Center));
planets.AddRange(GenerateEntities(zoneSettings, ref random, c.Area / totalArea * pack.Mass, c.Radius, c.Center));
}
}
else
planets.AddRange(GenerateEntities(settings, ref random, pack.Mass, pack.Radius, float2.zero));
planets.AddRange(GenerateEntities(zoneSettings, ref random, pack.Mass, pack.Radius, float2.zero));
// Create collections to map between zone generator output and database entries
var orbitMap = new Dictionary<GeneratorPlanet, OrbitData>();
@ -153,9 +124,9 @@ public class ZoneGenerator
{
// Dictionary<Guid, float> planetResources = new Dictionary<Guid, float>();
BodyType bodyType = planet.Belt ? BodyType.Asteroid :
planet.Mass > settings.SunMass ? BodyType.Sun :
planet.Mass > settings.GasGiantMass ? BodyType.GasGiant :
planet.Mass > settings.PlanetMass ? BodyType.Planet : BodyType.Planetoid;
planet.Mass > zoneSettings.SunMass ? BodyType.Sun :
planet.Mass > zoneSettings.GasGiantMass ? BodyType.GasGiant :
planet.Mass > zoneSettings.PlanetMass ? BodyType.Planet : BodyType.Planetoid;
// foreach (var r in resources)
// {
@ -193,13 +164,13 @@ public class ZoneGenerator
if (planetData is AsteroidBeltData beltData)
{
beltData.Asteroids =
Enumerable.Range(0, (int) (settings.AsteroidCount.Evaluate(beltData.Mass.Value * orbitMap[planet].Distance.Value)))
Enumerable.Range(0, (int) (zoneSettings.AsteroidCount.Evaluate(beltData.Mass.Value * orbitMap[planet].Distance.Value)))
.Select(_ => new Asteroid
{
Distance = orbitMap[planet].Distance.Value + random.NextFloat()*(random.NextFloat()-.5f)*settings.AsteroidBeltWidth.Evaluate(orbitMap[planet].Distance.Value),
Distance = orbitMap[planet].Distance.Value + random.NextFloat()*(random.NextFloat()-.5f)*zoneSettings.AsteroidBeltWidth.Evaluate(orbitMap[planet].Distance.Value),
Phase = random.NextFloat(),
Size = random.NextFloat(),
RotationSpeed = settings.AsteroidRotationSpeed.Evaluate(random.NextFloat())
RotationSpeed = zoneSettings.AsteroidRotationSpeed.Evaluate(random.NextFloat())
})
//.OrderByDescending(a=>a.Size)
.ToArray();
@ -209,25 +180,25 @@ public class ZoneGenerator
if (gas is SunData sun)
{
float primary = random.NextFloat();
float secondary = frac(primary + 1 + settings.SunSecondaryColorDistance * (random.NextFloat() > .5 ? 1 : -1));
float secondary = frac(primary + 1 + zoneSettings.SunSecondaryColorDistance * (random.NextFloat() > .5 ? 1 : -1));
gas.Colors.Value = new []
{
float4(ColorMath.HsvToRgb(float3(primary, settings.SunColorSaturation, .5f)), 0),
float4(ColorMath.HsvToRgb(float3(secondary, settings.SunColorSaturation, 1)), 1)
float4(ColorMath.HsvToRgb(float3(primary, zoneSettings.SunColorSaturation, .5f)), 0),
float4(ColorMath.HsvToRgb(float3(secondary, zoneSettings.SunColorSaturation, 1)), 1)
};
sun.FogTintColor.Value = ColorMath.HsvToRgb(float3(primary, settings.SunFogTintSaturation, 1));
sun.LightColor.Value = ColorMath.HsvToRgb(float3(primary, settings.SunLightSaturation, 1));
sun.FogTintColor.Value = ColorMath.HsvToRgb(float3(primary, zoneSettings.SunFogTintSaturation, 1));
sun.LightColor.Value = ColorMath.HsvToRgb(float3(primary, zoneSettings.SunLightSaturation, 1));
gas.FirstOffsetDomainRotationSpeed.Value = 5;
}
else
{
// Define primary color and two adjacent colors
float primary = random.NextFloat();
float right = frac(primary + settings.GasGiantBandColorSeparation);
float left = frac(primary + 1 - settings.GasGiantBandColorSeparation);
float right = frac(primary + zoneSettings.GasGiantBandColorSeparation);
float left = frac(primary + 1 - zoneSettings.GasGiantBandColorSeparation);
// Create n time keys from 0 to 1
var bandCount = (int) (settings.GasGiantBandCount.Evaluate(random.NextFloat()) + .5f);
var bandCount = (int) (zoneSettings.GasGiantBandCount.Evaluate(random.NextFloat()) + .5f);
var times = Enumerable.Range(0, bandCount)
.Select(i => (float) i / (bandCount-1));
@ -235,9 +206,9 @@ public class ZoneGenerator
// Saturation and Value are random with curves applied
gas.Colors.Value = times
.Select(time => float4(ColorMath.HsvToRgb(float3(
random.NextFloat() > settings.GasGiantBandAltColorChance ? primary : (random.NextFloat() > .5f ? right : left),
settings.GasGiantBandSaturation.Evaluate(random.NextFloat()),
settings.GasGiantBandSaturation.Evaluate(random.NextFloat()))),time))
random.NextFloat() > zoneSettings.GasGiantBandAltColorChance ? primary : (random.NextFloat() > .5f ? right : left),
zoneSettings.GasGiantBandSaturation.Evaluate(random.NextFloat()),
zoneSettings.GasGiantBandSaturation.Evaluate(random.NextFloat()))),time))
.ToArray();
gas.FirstOffsetDomainRotationSpeed.Value = 0;
@ -250,6 +221,15 @@ public class ZoneGenerator
return planetData;
}).ToList();
if (sectorZone.Owner != null)
{
var loadoutGenerator = new LoadoutGenerator(ref random, itemManager, sector, sectorZone, sectorZone.Owner, 1);
for (int i = 0; i < 3; i++)
{
pack.Entities.Add(loadoutGenerator.GenerateShipLoadout());
}
}
return pack;
}

View file

@ -128,7 +128,7 @@
float floorDensity = floorDist/_GridFloorBlend*_GridFloorDensity;
float fogDensity = patchDensity + max(0,floorDensity);
float alpha = min(max(max(fogDensity, 0) + fillDensity, _AlphaFloor), .99);
float albedo = (pow(1-alpha, _TintExponent));
float albedo = (pow(1-alpha, _TintExponent)) * smoothstep(0,-50,pos.y);
return float4((albedo*_Tint*lightTint).rgb, alpha);
}

Binary file not shown.

BIN
GameData/AetherDB.msgpack (Stored with Git LFS)

Binary file not shown.

BIN
GameData/PlayerSettings.msgpack (Stored with Git LFS)

Binary file not shown.