2020-03-22 19:05:26 +00:00
using System ;
using System.Collections ;
using System.Collections.Generic ;
using System.Linq ;
2020-05-04 00:07:36 +01:00
using Unity.Mathematics ;
2020-03-22 19:05:26 +00:00
using static Unity . Mathematics . math ;
2020-05-04 00:07:36 +01:00
using float2 = Unity . Mathematics . float2 ;
2020-04-30 02:54:31 +01:00
using Random = Unity . Mathematics . Random ;
2020-05-10 00:16:33 +01:00
using JM.LinqFaster ;
2020-12-01 00:16:11 +00:00
using UniRx ;
2020-05-30 02:44:22 +01:00
using float4 = Unity . Mathematics . float4 ;
2020-03-22 19:05:26 +00:00
public class GameContext
{
2020-04-30 02:54:31 +01:00
public Random Random = new Random ( ( uint ) ( DateTime . Now . Ticks % uint . MaxValue ) ) ;
2020-04-23 03:31:17 +01:00
public Dictionary < string , GalaxyMapLayerData > MapLayers = new Dictionary < string , GalaxyMapLayerData > ( ) ;
2020-11-27 22:47:33 +00:00
public SimpleCommodityData [ ] Resources ;
2020-05-07 03:53:54 +01:00
public Dictionary < Guid , List < IController > > CorporationControllers = new Dictionary < Guid , List < IController > > ( ) ;
2020-12-01 00:16:11 +00:00
public Dictionary < Guid , ZoneDefinition > GalaxyZones ;
2020-04-23 03:31:17 +01:00
2020-04-09 07:48:45 +01:00
private Action < string > _logger ;
2020-04-16 03:08:18 +01:00
private Dictionary < BlueprintStatEffect , PerformanceStat > AffectedStats =
new Dictionary < BlueprintStatEffect , PerformanceStat > ( ) ;
private double _time ;
private float _deltaTime ;
2020-04-23 03:31:17 +01:00
private GlobalData _globalData ;
2020-11-27 22:47:33 +00:00
private Dictionary < Guid , Zone > _zones = new Dictionary < Guid , Zone > ( ) ;
// private Guid _forceLoadZone;
2020-05-12 01:42:13 +01:00
2020-04-23 03:31:17 +01:00
public GlobalData GlobalData = > _globalData ? ? ( _globalData = Cache . GetAll < GlobalData > ( ) . FirstOrDefault ( ) ) ;
2020-04-16 03:08:18 +01:00
public DatabaseCache Cache { get ; }
2020-11-27 22:47:33 +00:00
// public Guid ForceLoadZone
// {
// get => _forceLoadZone;
// set
// {
// if(_forceLoadZone != Guid.Empty && ZoneEntities[_forceLoadZone].Count == 0)
// UnloadZone(_forceLoadZone);
// _forceLoadZone = value;
// if(!_loadedZones.Contains(_forceLoadZone))
// LoadZone(_forceLoadZone);
// }
// }
2020-05-10 00:16:33 +01:00
2020-04-16 03:08:18 +01:00
public double Time
{
get = > _time ;
set
{
_deltaTime = ( float ) ( value - _time ) ;
_time = value ;
2020-05-07 03:53:54 +01:00
//Log($"GameContext delta time: {_deltaTime}");
2020-04-16 03:08:18 +01:00
}
}
2020-04-09 07:48:45 +01:00
// private readonly Dictionary<CraftedItemData, int> Tier = new Dictionary<CraftedItemData, int>();
2020-03-27 01:53:03 +00:00
2020-04-09 07:48:45 +01:00
public GameContext ( DatabaseCache cache , Action < string > logger )
2020-03-27 01:53:03 +00:00
{
2020-04-16 03:08:18 +01:00
Cache = cache ;
2020-11-27 22:47:33 +00:00
MapLayers = cache . GetAll < GalaxyMapLayerData > ( ) . ToDictionary ( ml = > ml . Name ) ;
Resources = cache . GetAll < SimpleCommodityData > ( ) . Where ( i = > i . ResourceDensity . Any ( ) ) . ToArray ( ) ;
2020-04-09 07:48:45 +01:00
_logger = logger ;
2020-04-23 03:31:17 +01:00
// var globalData = Cache.GetAll<GlobalData>().FirstOrDefault();
// if (globalData == null)
// {
// globalData = new GlobalData();
// Cache.Add(globalData);
// }
2020-04-16 03:08:18 +01:00
}
public void Log ( string s )
{
_logger ( s ) ;
}
2020-12-01 00:16:11 +00:00
// public void Update()
// {
// foreach(var zone in _zones.Values)
// zone.Update((float) Time, _deltaTime);
//
// foreach (var corporation in Cache.GetAll<Corporation>())
// {
// foreach (var tasks in corporation.Tasks
// .Select(id => Cache.Get<AgentTask>(id)) // Fetch the tasks from the database cache
// .Where(task => !task.Reserved) // Filter out tasks that have already been reserved
// .GroupBy(task => task.Type)) // Group tasks by type
// {
// // Create a list of available controllers for this task type
// var availableControllers = CorporationControllers[corporation.ID]
// .Where(controller => controller.Available && controller.TaskType == tasks.Key).ToList();
//
// // Iterate over the highest priority tasks for which controllers are available
// foreach (var task in tasks.OrderByDescending(task => task.Priority).Take(availableControllers.Count))
// {
// // Find the nearest controller for this task
// IController nearestController = availableControllers[0];
// List<ZoneDefinition> nearestControllerPath = FindPath(GalaxyZones[availableControllers.First().Zone.Data.ID], GalaxyZones[task.Zone], true);
// foreach (var controller in availableControllers.Skip(1))
// {
// var path = FindPath(GalaxyZones[controller.Zone.Data.ID], GalaxyZones[task.Zone], true);
// if (path.Count < nearestControllerPath.Count)
// {
// nearestControllerPath = path;
// nearestController = controller;
// }
// }
// task.Reserved = true;
// nearestController.AssignTask(task.ID);
// }
// }
// }
//
// }
2020-05-28 04:50:40 +01:00
2020-12-01 00:16:11 +00:00
// public Zone GetZone(Guid zone)
// {
// if (_zones.ContainsKey(zone)) return _zones[zone];
//
// // var zoneData = Cache.Get<ZoneData>(zone);
// // if (zoneData == null) throw new ArgumentException("Zone parameter is not a valid zone ID!", nameof(zone));
// //
// // return GetZone(zoneData);
// return null;
// }
//
// public Zone GetZone(ZonePack zonePack)
// {
// var z = new Zone(this, zonePack);
// _zones.Add(zonePack.Data.ID, z);
// return z;
// }
//
// public void UnloadZone(Guid zone)
// {
// _zones.Remove(zone);
// }
2020-05-10 00:16:33 +01:00
2020-11-27 22:47:33 +00:00
// public void Warp(Entity entity, Guid targetZone)
// {
// if (length(entity.Position - WormholePosition(entity.Zone, targetZone)) < GlobalData.WarpDistance)
// {
// var sourceZone = entity.Zone;
//
// // Remove entity from source zone
// ZoneEntities[sourceZone].Remove(entity.ID);
//
// // Unload source zone if empty and unobserved
// if(ForceLoadZone != sourceZone && ZoneEntities[sourceZone].Count == 0)
// UnloadZone(sourceZone);
//
// // Load target zone if not yet loaded
// if(!_loadedZones.Contains(targetZone))
// LoadZone(targetZone);
//
// entity.Zone = targetZone;
// entity.Position = WormholePosition(targetZone, sourceZone);
// ZoneEntities[targetZone][entity.ID] = entity;
// }
// }
2020-05-21 01:53:06 +01:00
public void PlaceMegas ( )
{
var megas = Cache . GetAll < MegaCorporation > ( ) ;
var availableZones = Cache . GetAll < ZoneData > ( )
. Where ( z = > megas . All ( m = > m . HomeZone ! = z . ID ) )
. ToList ( ) ;
foreach ( var megaPlacement in megas
. OrderBy ( m = > m . PlacementType )
. GroupBy ( m = > m . PlacementType ) )
switch ( megaPlacement . Key )
{
case MegaPlacementType . Mass :
foreach ( var mega in megaPlacement )
{
var zone = availableZones
. MaxBy ( z = > z . Mass ) ;
availableZones . Remove ( zone ) ;
mega . HomeZone = zone . ID ;
}
break ;
2020-11-27 22:47:33 +00:00
// case MegaPlacementType.Planets:
// foreach (var mega in megaPlacement)
// {
// var zone = availableZones
// .MaxBy(z => z.Planets.Length);
// availableZones.Remove(zone);
// mega.HomeZone = zone.ID;
// }
// break;
// case MegaPlacementType.Resources:
// foreach (var mega in megaPlacement)
// {
// var zone = availableZones
// .MaxBy(z => z.Planets
// .SelectMany(id=>Cache.Get<PlanetData>(id).Resources
// .Select(r=>r.Key))
// .Distinct()
// .Count());
// availableZones.Remove(zone);
// mega.HomeZone = zone.ID;
// }
// break;
2020-05-21 01:53:06 +01:00
case MegaPlacementType . Connected :
foreach ( var mega in megaPlacement )
{
var zone = availableZones
. OrderByDescending ( z = > z . Wormholes . Count )
. ThenBy ( z = > megas
. Sum ( m = > m . HomeZone = = Guid . Empty ? 0 : lengthsq ( Cache . Get < ZoneData > ( m . HomeZone ) . Position - z . Position ) ) )
. First ( ) ;
availableZones . Remove ( zone ) ;
mega . HomeZone = zone . ID ;
}
break ;
case MegaPlacementType . Isolated :
foreach ( var mega in megaPlacement )
{
var zone = availableZones
. Where ( z = > z . Wormholes . Count = = 1 )
. MaxBy ( z = >
{
int soloChain = 0 ;
var previous = z ;
var next = Cache . Get < ZoneData > ( z . Wormholes . First ( ) ) ;
while ( next . Wormholes . Count = = 2 )
{
var temp = next ;
next = Cache . Get < ZoneData > ( next . Wormholes . First ( w = > w ! = previous . ID ) ) ;
previous = temp ;
soloChain + + ;
}
return soloChain ;
} ) ;
availableZones . Remove ( zone ) ;
mega . HomeZone = zone . ID ;
}
break ;
default :
throw new ArgumentOutOfRangeException ( ) ;
}
}
2020-03-22 19:05:26 +00:00
2020-04-09 07:48:45 +01:00
// public int ItemTier(CraftedItemData itemData)
// {
// if (Tier.ContainsKey(itemData)) return Tier[itemData];
//
// Tier[itemData] = itemData.Ingredients.Keys.Max(ci => _cache.Get<ItemData>(ci) is CraftedItemData craftableIngredient ? ItemTier(craftableIngredient) : 0);
//
// return Tier[itemData];
// }
2020-03-22 19:05:26 +00:00
public ItemData GetData ( ItemInstance item )
{
2020-04-16 03:08:18 +01:00
return Cache . Get < ItemData > ( item . Data ) ;
2020-03-22 19:05:26 +00:00
}
public SimpleCommodityData GetData ( SimpleCommodity item )
{
2020-04-16 03:08:18 +01:00
return Cache . Get < SimpleCommodityData > ( item . Data ) ;
2020-03-22 19:05:26 +00:00
}
public CraftedItemData GetData ( CraftedItemInstance item )
{
2020-04-16 03:08:18 +01:00
return Cache . Get < CraftedItemData > ( item . Data ) ;
2020-03-22 19:05:26 +00:00
}
public EquippableItemData GetData ( Gear gear )
{
2020-04-16 03:08:18 +01:00
return Cache . Get < EquippableItemData > ( gear . Data ) ;
2020-03-22 19:05:26 +00:00
}
public float GetMass ( ItemInstance item )
{
var data = GetData ( item ) ;
switch ( item )
{
case CraftedItemInstance _ :
return data . Mass ;
case SimpleCommodity commodity :
return data . Mass * commodity . Quantity ;
}
return 0 ;
}
2020-05-26 01:12:06 +01:00
public float GetSize ( ItemInstance item )
{
var data = GetData ( item ) ;
switch ( item )
{
case CraftedItemInstance _ :
return data . Size ;
case SimpleCommodity commodity :
return data . Size * commodity . Quantity ;
}
return 0 ;
}
2020-06-05 04:16:33 +01:00
public float GetThermalMass ( ItemInstance item )
2020-03-22 19:05:26 +00:00
{
var data = GetData ( item ) ;
switch ( item )
{
case CraftedItemInstance _ :
return data . Mass * data . SpecificHeat ;
case SimpleCommodity commodity :
return data . Mass * data . SpecificHeat * commodity . Quantity ;
}
return 0 ;
}
2020-04-09 07:48:45 +01:00
public PerformanceStat GetAffectedStat ( BlueprintData blueprint , BlueprintStatEffect effect )
{
// We've already cached this effect's stat, return it directly
if ( AffectedStats . ContainsKey ( effect ) ) return AffectedStats [ effect ] ;
// Get the data for the item the blueprint is for, return null if not found or not equippable
2020-04-16 03:08:18 +01:00
var blueprintItem = Cache . Get < EquippableItemData > ( blueprint . Item ) ;
2020-04-09 07:48:45 +01:00
if ( blueprintItem = = null )
{
_logger ( $"Attempted to get stat effect but Blueprint {blueprint.ID} is not for an equippable item!" ) ;
return AffectedStats [ effect ] = null ;
}
// Get the first behavior of the type specified in the blueprint stat effect, return null if not found
2020-05-12 01:42:13 +01:00
var effectObject = effect . StatReference . Target = = blueprintItem . Name ? ( object ) blueprintItem :
blueprintItem . Behaviors . FirstOrDefault ( b = > b . GetType ( ) . Name = = effect . StatReference . Target ) ;
2020-04-16 03:08:18 +01:00
if ( effectObject = = null )
2020-04-09 07:48:45 +01:00
{
2020-05-12 01:42:13 +01:00
_logger ( $"Attempted to get stat effect for Blueprint {blueprint.ID} but stat references missing behavior \" { effect . StatReference . Target } \ "!" ) ;
2020-04-09 07:48:45 +01:00
return AffectedStats [ effect ] = null ;
}
// Get the first field in the behavior matching the name specified in the stat effect, return null if not found
2020-04-16 03:08:18 +01:00
var type = effectObject . GetType ( ) ;
2020-04-09 07:48:45 +01:00
var field = type . GetField ( effect . StatReference . Stat ) ;
if ( field = = null )
{
2020-05-12 01:42:13 +01:00
_logger ( $"Attempted to get stat effect for Blueprint {blueprint.ID} but object {effect.StatReference.Target} does not have a stat named \" { effect . StatReference . Stat } \ "!" ) ;
2020-04-09 07:48:45 +01:00
return AffectedStats [ effect ] = null ;
}
// Finally we've confirmed the stat effect is valid, return the affected stat
2020-04-16 03:08:18 +01:00
return AffectedStats [ effect ] = field . GetValue ( effectObject ) as PerformanceStat ;
2020-04-09 07:48:45 +01:00
}
2020-05-22 00:23:34 +01:00
private readonly Dictionary < CraftedItemInstance , float > ItemQuality = new Dictionary < CraftedItemInstance , float > ( ) ;
2020-05-27 03:43:30 +01:00
2020-05-22 00:23:34 +01:00
public float CompoundQuality ( CraftedItemInstance item )
{
if ( ItemQuality . ContainsKey ( item ) ) return ItemQuality [ item ] ;
var quality = item . Quality ;
var craftedIngredients = item . Ingredients . Where ( i = > i is CraftedItemInstance ) . ToArray ( ) ;
if ( craftedIngredients . Length > 0 )
{
var ingredientQualityWeight = Cache . Get < CraftedItemData > ( item . Data ) . IngredientQualityWeight ;
quality = quality * ( 1 - ingredientQualityWeight ) +
craftedIngredients . Cast < CraftedItemInstance > ( ) . Average ( CompoundQuality ) * ingredientQualityWeight ;
}
ItemQuality [ item ] = quality ;
return ItemQuality [ item ] ;
}
2020-03-22 19:05:26 +00:00
// Determine quality of either the item itself or the specific ingredient this stat depends on
public float Quality ( PerformanceStat stat , Gear item )
{
2020-04-30 02:54:31 +01:00
var blueprint = Cache . Get < BlueprintData > ( item . Blueprint ) ;
var activeEffects = blueprint . StatEffects . Where ( x = > GetAffectedStat ( blueprint , x ) = = stat ) . ToArray ( ) ;
2020-03-22 19:05:26 +00:00
float quality ;
2020-04-09 07:48:45 +01:00
if ( ! activeEffects . Any ( ) )
2020-05-22 00:23:34 +01:00
quality = CompoundQuality ( item ) ;
2020-03-22 19:05:26 +00:00
else
{
2020-04-28 01:50:50 +01:00
var ingredientInstances = item . Ingredients . Select ( i = > Cache . Get < ItemInstance > ( i ) ) . ToArray ( ) ;
var ingredients = ingredientInstances . Where ( i = > activeEffects . Any ( e = > e . Ingredient = = i . Data ) ) . ToArray ( ) ;
2020-06-05 04:16:33 +01:00
var distinctIngredients = ingredients . Select ( i = > i . Data ) . Distinct ( ) ;
if ( distinctIngredients . Count ( ) ! = activeEffects . Length )
2020-04-09 07:48:45 +01:00
{
_logger ( $"Item {item.ID} does not have the ingredients specified by the stat effects of its blueprint!" ) ;
return 0 ;
}
float sum = 0 ;
foreach ( var i in ingredients )
{
if ( i is CraftedItemInstance ci )
2020-05-22 00:23:34 +01:00
sum + = CompoundQuality ( ci ) ;
2020-04-09 07:48:45 +01:00
else _logger ( $"Blueprint stat effect for item {item.ID} specifies invalid (non crafted) ingredient!" ) ;
}
quality = sum / ingredients . Length ;
2020-03-22 19:05:26 +00:00
}
return quality ;
}
// Returns stat when not equipped
public float Evaluate ( PerformanceStat stat , Gear item )
{
var quality = pow ( Quality ( stat , item ) , stat . QualityExponent ) ;
var result = lerp ( stat . Min , stat . Max , quality ) ;
if ( float . IsNaN ( result ) )
return stat . Min ;
return result ;
}
// Returns stat using ship temperature and modifiers
2020-04-09 10:33:16 +01:00
public float Evaluate ( PerformanceStat stat , Gear item , Entity entity )
2020-03-22 19:05:26 +00:00
{
var itemData = GetData ( item ) ;
2020-04-09 10:33:16 +01:00
var heat = ! stat . HeatDependent ? 1 : pow ( itemData . Performance ( entity . Temperature ) , Evaluate ( itemData . HeatExponent , item ) ) ;
2020-04-16 03:08:18 +01:00
var durability = ! stat . DurabilityDependent ? 1 : pow ( item . Durability / Evaluate ( itemData . Durability , item ) , Evaluate ( itemData . DurabilityExponent , item ) ) ;
2020-03-22 19:05:26 +00:00
var quality = pow ( Quality ( stat , item ) , stat . QualityExponent ) ;
2020-04-09 10:33:16 +01:00
var scaleModifier = stat . GetScaleModifiers ( entity ) . Values . Aggregate ( 1.0f , ( current , mod ) = > current * mod ) ;
2020-03-22 19:05:26 +00:00
2020-04-09 10:33:16 +01:00
var constantModifier = stat . GetConstantModifiers ( entity ) . Values . Sum ( ) ;
2020-03-22 19:05:26 +00:00
var result = lerp ( stat . Min , stat . Max , heat * durability * quality ) * scaleModifier + constantModifier ;
if ( float . IsNaN ( result ) )
return stat . Min ;
return result ;
}
2020-05-25 03:05:30 +01:00
2020-11-27 22:47:33 +00:00
public Entity CreateEntity ( Guid zoneID , Guid corporation , Guid loadout )
2020-05-25 03:05:30 +01:00
{
if ( ! ( Cache . Get ( loadout ) is LoadoutData loadoutData ) )
{
_logger ( "Attempted to spawn invalid loadout ID" ) ;
return null ;
}
if ( ! ( Cache . Get ( loadoutData . Hull ) is HullData hullData ) )
{
_logger ( "Attempted to spawn loadout with invalid hull ID" ) ;
return null ;
}
2020-11-27 22:47:33 +00:00
if ( ! ( Cache . Get ( zoneID ) is ZoneData zoneData ) )
2020-05-25 03:05:30 +01:00
{
_logger ( "Attempted to spawn entity with invalid zone ID" ) ;
return null ;
}
if ( ! ( Cache . Get ( corporation ) is Corporation corpData ) )
{
_logger ( "Attempted to spawn entity with invalid corporation ID" ) ;
return null ;
}
2020-06-11 02:55:11 +01:00
var gearData = loadoutData . Gear
2020-05-25 03:05:30 +01:00
. Take ( hullData . Hardpoints . Count )
. Where ( id = > id ! = Guid . Empty )
. Select ( id = > Cache . Get < GearData > ( id ) )
. ToArray ( ) ;
if ( gearData . Any ( g = > g = = null ) )
{
_logger ( "Attempted to spawn loadout with invalid gear ID" ) ;
return null ;
}
var gear = gearData
. Select ( gd = > CreateInstance ( gd . ID , GlobalData . StartingGearQualityMin , GlobalData . StartingGearQualityMax ) )
. ToArray ( ) ;
if ( gear . Any ( g = > g = = null ) )
return null ;
foreach ( var g in gear )
Cache . Add ( g ) ;
2020-06-11 02:55:11 +01:00
var cargoData = loadoutData . CompoundCargo
. SelectMany ( x = > Enumerable . Repeat ( Cache . Get < CraftedItemData > ( x . Key ) , x . Value ) )
. ToArray ( ) ;
if ( cargoData . Any ( g = > g = = null ) )
{
_logger ( "Attempted to spawn loadout with invalid cargo ID" ) ;
return null ;
}
2020-05-25 03:05:30 +01:00
var cargo = cargoData
. Select ( gd = > CreateInstance ( gd . ID , GlobalData . StartingGearQualityMin , GlobalData . StartingGearQualityMax ) )
. ToArray ( ) ;
if ( cargo . Any ( g = > g = = null ) )
return null ;
foreach ( var c in cargo )
Cache . Add ( c ) ;
var simpleCargo = loadoutData . SimpleCargo ?
. Select ( x = > CreateInstance ( x . Key , x . Value ) )
. ToArray ( ) ? ? new SimpleCommodity [ 0 ] ;
if ( simpleCargo . Any ( g = > g = = null ) )
return null ;
var hull = CreateInstance ( loadoutData . Hull , GlobalData . StartingGearQualityMin , GlobalData . StartingGearQualityMax ) ;
if ( hull = = null )
return null ;
2020-11-27 22:47:33 +00:00
// Get target zone
var zone = _zones [ zoneID ] ;
2020-05-25 03:05:30 +01:00
if ( hullData . HullType = = HullType . Ship )
{
2020-06-12 01:57:15 +01:00
var entity = CreateShip ( hull . ID , gear . Select ( g = > g . ID ) ,
2020-07-03 01:33:42 +01:00
cargo . Select ( c = > c . ID ) . Concat ( simpleCargo . Select ( c = > c . ID ) ) , zone , corporation , Guid . Empty , loadoutData . Name ) ;
2020-06-11 02:55:11 +01:00
entity . Active = true ;
2020-05-25 03:05:30 +01:00
return entity ;
}
if ( hullData . HullType = = HullType . Station )
{
var distance = lerp ( . 2f , . 8f , Random . NextFloat ( ) ) * zoneData . Radius ;
var orbit = new OrbitData
{
Context = this ,
2020-12-01 00:16:11 +00:00
Distance = new ReactiveProperty < float > ( distance ) ,
2020-11-27 22:47:33 +00:00
Parent = zone . Orbits . Values . Select ( o = > o . Data )
. First ( orbitData = > orbitData . Parent = = Guid . Empty ) . ID ,
Phase = Random . NextFloat ( )
2020-05-25 03:05:30 +01:00
} ;
2020-11-27 22:47:33 +00:00
zone . AddOrbit ( orbit ) ;
2020-05-25 03:05:30 +01:00
var entity = new OrbitalEntity ( this , hull . ID , gear . Select ( g = > g . ID ) ,
2020-05-27 02:23:25 +01:00
cargo . Select ( c = > c . ID ) . Concat ( simpleCargo . Select ( c = > c . ID ) ) , orbit . ID , zone , corporation )
2020-05-25 03:05:30 +01:00
{
2020-05-26 01:12:06 +01:00
Name = $"{loadoutData.Name} {Random.NextInt(1,255):X}" ,
2020-06-01 03:11:04 +01:00
Temperature = 293 ,
2020-06-08 01:01:33 +01:00
Population = 4
2020-05-25 03:05:30 +01:00
} ;
2020-06-11 02:55:11 +01:00
entity . Active = true ;
2020-06-01 03:11:04 +01:00
var parentCorp = Cache . Get < MegaCorporation > ( corpData . Parent ) ;
foreach ( var attribute in parentCorp . Personality )
entity . Personality [ attribute . Key ] = attribute . Value ;
2020-05-25 03:05:30 +01:00
Cache . Add ( entity ) ;
2020-11-27 22:47:33 +00:00
zone . Entities [ entity . ID ] = entity ;
2020-05-25 03:05:30 +01:00
return entity ;
}
return null ;
}
2020-06-12 01:57:15 +01:00
2020-11-27 22:47:33 +00:00
public Ship CreateShip ( Guid hull , IEnumerable < Guid > gear , IEnumerable < Guid > cargo , Zone zone , Guid corporation , Guid homeEntity , string typeName )
2020-06-12 01:57:15 +01:00
{
var ship = new Ship ( this , hull , gear , cargo , zone , corporation )
{
2020-07-03 01:33:42 +01:00
Name = $"{typeName} {Random.NextInt(1,255):X}" ,
HomeEntity = homeEntity
2020-06-12 01:57:15 +01:00
} ;
Cache . Add ( ship ) ;
2020-11-27 22:47:33 +00:00
zone . Entities [ ship . ID ] = ship ;
2020-06-12 01:57:15 +01:00
return ship ;
}
2020-03-22 19:05:26 +00:00
public SimpleCommodity CreateInstance ( Guid data , int count )
{
2020-04-16 03:08:18 +01:00
var item = Cache . Get < SimpleCommodityData > ( data ) ;
2020-03-22 19:05:26 +00:00
if ( item ! = null )
2020-06-02 07:01:03 +01:00
{
var newItem = new SimpleCommodity
2020-03-22 19:05:26 +00:00
{
2020-06-02 07:01:03 +01:00
Context = this ,
2020-03-22 19:05:26 +00:00
Data = data ,
2020-05-25 03:05:30 +01:00
Quantity = count
2020-03-22 19:05:26 +00:00
} ;
2020-06-02 07:01:03 +01:00
Cache . Add ( newItem ) ;
return newItem ;
}
2020-03-22 19:05:26 +00:00
2020-04-09 07:48:45 +01:00
_logger ( "Attempted to create Simple Commodity instance using missing or incorrect item id" ) ;
return null ;
2020-03-22 19:05:26 +00:00
}
2020-05-25 03:05:30 +01:00
public CraftedItemInstance CreateInstance ( Guid data , float qualityMin , float qualityMax )
2020-03-22 19:05:26 +00:00
{
2020-04-16 03:08:18 +01:00
var item = Cache . Get < CraftedItemData > ( data ) ;
2020-03-22 19:05:26 +00:00
if ( item = = null )
{
2020-04-09 07:48:45 +01:00
_logger ( "Attempted to create crafted item instance using missing or incorrect item id!" ) ;
return null ;
2020-03-22 19:05:26 +00:00
}
2020-04-16 03:08:18 +01:00
var blueprint = Cache . GetAll < BlueprintData > ( ) . FirstOrDefault ( b = > b . Item = = data ) ;
2020-04-09 07:48:45 +01:00
if ( blueprint = = null )
{
_logger ( "Attempted to create crafted item instance which has no blueprint!" ) ;
return null ;
}
2020-06-11 02:55:11 +01:00
bool invalidIngredientFound = false ;
ItemData invalidIngredient = null ;
var ingredients = new List < ItemInstance > ( ) ;
foreach ( var ingredient in blueprint . Ingredients )
{
var itemData = Cache . Get < ItemData > ( ingredient . Key ) ;
if ( itemData is SimpleCommodityData )
2020-03-22 19:05:26 +00:00
{
2020-06-11 02:55:11 +01:00
var itemInstance = CreateInstance ( ingredient . Key , ingredient . Value ) ;
if ( itemInstance = = null )
{
invalidIngredientFound = true ;
invalidIngredient = itemData ;
}
else ingredients . Add ( itemInstance ) ;
}
else
{
for ( int i = 0 ; i < ingredient . Value ; i + + )
{
var itemInstance = CreateInstance ( ingredient . Key , qualityMin , qualityMax ) ;
if ( itemInstance = = null )
{
invalidIngredientFound = true ;
invalidIngredient = itemData ;
break ;
}
ingredients . Add ( itemInstance ) ;
}
}
}
if ( invalidIngredientFound )
{
_logger ( $"Unable to create crafted item ingredient: {invalidIngredient?.Name??" null "} for item {item.Name}" ) ;
}
2020-03-22 19:05:26 +00:00
2020-04-28 01:50:50 +01:00
Cache . AddAll ( ingredients ) ;
2020-03-22 19:05:26 +00:00
if ( item is EquippableItemData equippableItemData )
{
2020-04-16 03:08:18 +01:00
var newGear = new Gear
2020-03-22 19:05:26 +00:00
{
Context = this ,
Data = data ,
2020-04-28 01:50:50 +01:00
Ingredients = ingredients . Select ( i = > i . ID ) . ToList ( ) ,
2020-05-25 03:05:30 +01:00
Quality = Random . NextFloat ( qualityMin , qualityMax ) ,
2020-06-02 07:01:03 +01:00
Blueprint = blueprint . ID ,
2020-06-07 03:21:47 +01:00
Name = $"{item.Name}"
2020-03-22 19:05:26 +00:00
} ;
2020-04-16 03:08:18 +01:00
newGear . Durability = Evaluate ( equippableItemData . Durability , newGear ) ;
2020-04-28 01:50:50 +01:00
Cache . Add ( newGear ) ;
2020-04-16 03:08:18 +01:00
return newGear ;
2020-03-22 19:05:26 +00:00
}
2020-04-28 01:50:50 +01:00
var newCommodity = new CompoundCommodity
2020-03-22 19:05:26 +00:00
{
Context = this ,
Data = data ,
2020-04-28 01:50:50 +01:00
Ingredients = ingredients . Select ( i = > i . ID ) . ToList ( ) ,
2020-05-25 03:05:30 +01:00
Quality = Random . NextFloat ( qualityMin , qualityMax ) ,
2020-06-02 07:01:03 +01:00
Blueprint = blueprint . ID ,
2020-06-07 03:21:47 +01:00
Name = $"{item.Name}"
2020-03-22 19:05:26 +00:00
} ;
2020-04-28 01:50:50 +01:00
Cache . Add ( newCommodity ) ;
return newCommodity ;
2020-03-22 19:05:26 +00:00
}
2020-05-10 00:16:33 +01:00
class DijkstraNode
{
public float Cost ;
public DijkstraNode Parent ;
2020-12-01 00:16:11 +00:00
public ZoneDefinition Zone ;
2020-05-10 00:16:33 +01:00
}
2020-12-01 00:16:11 +00:00
public List < ZoneDefinition > FindPath ( ZoneDefinition source , ZoneDefinition target , bool bestFirst = false )
2020-05-10 00:16:33 +01:00
{
SortedList < float , DijkstraNode > members = new SortedList < float , DijkstraNode > { { 0 , new DijkstraNode { Zone = source } } } ;
List < DijkstraNode > searched = new List < DijkstraNode > ( ) ;
while ( true )
{
var s = members . FirstOrDefault ( m = > ! searched . Contains ( m . Value ) ) . Value ; // Lowest cost unsearched node
if ( s = = null ) return null ; // No vertices left unsearched
if ( s . Zone = = target ) // We found the path
{
Stack < DijkstraNode > path = new Stack < DijkstraNode > ( ) ; // Since we start at the end, use a LIFO collection
path . Push ( s ) ;
while ( path . Peek ( ) . Parent ! = null ) // Keep pushing until we reach the start, which has no parent
path . Push ( path . Peek ( ) . Parent ) ;
return path . Select ( dv = > dv . Zone ) . ToList ( ) ;
}
// For each adjacent star (filter already visited zones unless heuristic is in use)
foreach ( var dijkstraStar in s . Zone . Links . WhereSelectF ( i = > ! bestFirst | | members . All ( m = > m . Value . Zone ! = GalaxyZones [ i ] ) ,
// Cost is parent cost plus distance
i = > new DijkstraNode { Parent = s , Zone = GalaxyZones [ i ] , Cost = s . Cost + length ( s . Zone . Position - GalaxyZones [ i ] . Position ) } ) )
// Add new member to list, sorted by cost plus optional heuristic
members . Add ( bestFirst ? dijkstraStar . Cost + length ( dijkstraStar . Zone . Position - target . Position ) : dijkstraStar . Cost , dijkstraStar ) ;
searched . Add ( s ) ;
}
}
2020-05-25 03:05:30 +01:00
2020-06-05 04:16:33 +01:00
// public bool MoveCargo(Entity source, Entity target, ItemInstance item, int quantity = int.MaxValue)
// {
// if (item is CraftedItemInstance craftedItemInstance)
// {
// var craftedItemData = Cache.Get<CraftedItemData>(craftedItemInstance.Data);
// if (target.Capacity - target.OccupiedCapacity > craftedItemData.Size)
// {
// // Target has the cargo capacity for the item, simply move the instance
// source.Cargo.Remove(item.ID);
// target.Cargo.Add(item.ID);
// source.RecalculateMass();
// target.RecalculateMass();
// return true;
// }
// return false;
// }
//
// if (item is SimpleCommodity simpleCommoditySource)
// {
// quantity = min(quantity, simpleCommoditySource.Quantity);
// var simpleCommodityData = Cache.Get<SimpleCommodityData>(simpleCommoditySource.Data);
// var spareCapacity = (int) (target.Capacity - target.OccupiedCapacity);
// var simpleCommodityTarget = target.Cargo
// .Select(i => Cache.Get<ItemInstance>(i))
// .FirstOrDefault(i => i.Data == simpleCommodityData.ID) as SimpleCommodity;
// var success = spareCapacity >= quantity;
// quantity = min(quantity, spareCapacity);
// if (simpleCommodityTarget == null)
// {
// if (quantity == simpleCommoditySource.Quantity)
// {
// // Target has the cargo capacity to hold the full quantity,
// // and the target has no matching item instance;
// // simply move the existing item instance to the target
// source.Cargo.Remove(simpleCommoditySource.ID);
// target.Cargo.Add(simpleCommoditySource.ID);
// source.RecalculateMass();
// target.RecalculateMass();
// return success;
// }
// else
// {
// // Target has the cargo capacity to hold the desired quantity
// // and the target has no matching item instance;
// // Create a new item instance on the target and decrement the quantity of the source instance
// var newSimpleCommodity = new SimpleCommodity
// {
// Context = this,
// Data = simpleCommodityData.ID,
// Quantity = simpleCommoditySource.Quantity
// };
// Cache.Add(newSimpleCommodity);
// target.Cargo.Add(newSimpleCommodity.ID);
// simpleCommoditySource.Quantity -= quantity;
// source.RecalculateMass();
// target.RecalculateMass();
// return success;
// }
// }
// else
// {
// if (quantity == simpleCommoditySource.Quantity)
// {
// // Target has the cargo capacity to hold the full quantity,
// // and there is already a matching item instance;
// // delete the source entity's item instance and increment the target's quantity
// source.Cargo.Remove(simpleCommoditySource.ID);
// Cache.Delete(simpleCommoditySource);
// simpleCommodityTarget.Quantity += quantity;
// source.RecalculateMass();
// target.RecalculateMass();
// return success;
// }
// else
// {
// // Target has the cargo capacity to hold the desired quantity,
// // and there is already a matching item instance;
// // decrement the source's quantity and increment the target's quantity
// simpleCommoditySource.Quantity -= quantity;
// simpleCommodityTarget.Quantity += quantity;
// source.RecalculateMass();
// target.RecalculateMass();
// return success;
// }
// }
//
// }
//
// return false;
// }
2020-04-16 03:08:18 +01:00
}