source code checkin

This commit is contained in:
Brett Hewitson 2021-01-07 16:23:23 +10:00
parent 5f8fb2c825
commit 7e57b72e35
675 changed files with 168433 additions and 0 deletions

View file

@ -0,0 +1,14 @@
using System;
namespace ServerManagerTool.Lib
{
public class ProfileEventArgs : EventArgs
{
public ProfileEventArgs(ServerProfile profile)
{
Profile = profile;
}
public ServerProfile Profile;
}
}

View file

@ -0,0 +1,410 @@
using ServerManagerTool.Common.Model;
using ServerManagerTool.Enums;
using ServerManagerTool.Lib.ViewModel;
using ServerManagerTool.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using WPFSharp.Globalizer;
namespace ServerManagerTool.Lib
{
public static class GameData
{
public const string MOD_ALL = "All";
public const string MOD_UNKNOWN = "Unknown";
public static string MainDataFolder = Path.Combine(Environment.CurrentDirectory, Config.Default.GameDataDir);
public static string UserDataFolder = Path.Combine(Config.Default.DataDir, Config.Default.GameDataDir);
public static int DefaultMaxExperiencePointsDino = 10;
public static int DefaultMaxExperiencePointsPlayer = 5;
private static MainGameData gameData = null;
public static void Initialize()
{
// read static game data
GameDataUtils.ReadAllData(out gameData, MainDataFolder, Config.Default.GameDataExtension, Config.Default.GameDataApplication);
// read user game data
MainGameData userGameData = new MainGameData();
if (!UserDataFolder.Equals(MainDataFolder, StringComparison.OrdinalIgnoreCase))
{
GameDataUtils.ReadAllData(out userGameData, UserDataFolder, Config.Default.GameDataExtension, Config.Default.GameDataApplication, true);
}
// creatures
gameData.Creatures.AddRange(userGameData.Creatures);
dinoSpawns = gameData.Creatures.ConvertAll(item => new DinoSpawn { ClassName = item.ClassName, Mod = item.Mod, KnownDino = true, DinoNameTag = item.NameTag }).ToArray();
dinoMultipliers = gameData.Creatures.ConvertAll(item => new ClassMultiplier { ClassName = item.ClassName }).ToArray();
// engrams
gameData.Engrams.AddRange(userGameData.Engrams);
engrams = gameData.Engrams.ConvertAll(item => new Engram { EngramClassName = item.ClassName, EngramLevelRequirement = item.Level, EngramPointsCost = item.Points, Mod = item.Mod, KnownEngram = true, IsTekgram = item.IsTekGram }).ToArray();
// items
gameData.Items.AddRange(userGameData.Items);
items = gameData.Items.ConvertAll(item => new PrimalItem { ClassName = item.ClassName, Mod = item.Mod, KnownItem = true, Category = item.Category }).ToArray();
// resources
resourceMultipliers = gameData.Items.Where(item => item.IsHarvestable).ToList().ConvertAll(item => new ResourceClassMultiplier { ClassName = item.ClassName, Mod = item.Mod, KnownResource = true }).ToArray();
// map spawners
gameData.MapSpawners.AddRange(userGameData.MapSpawners);
mapSpawners = gameData.MapSpawners.ConvertAll(item => new MapSpawner { ClassName = item.ClassName, Mod = item.Mod, KnownSpawner = true }).ToArray();
// supply crates
gameData.SupplyCrates.AddRange(userGameData.SupplyCrates);
var crates = gameData.SupplyCrates.ConvertAll(item => new SupplyCrate { ClassName = item.ClassName, Mod = item.Mod, KnownSupplyCrate = true });
// inventories
gameData.Inventories.AddRange(userGameData.Inventories);
crates.AddRange(gameData.Inventories.ConvertAll(item => new SupplyCrate { ClassName = item.ClassName, Mod = item.Mod, KnownSupplyCrate = true }));
supplyCrates = crates.ToArray();
// game maps
gameData.GameMaps.AddRange(userGameData.GameMaps);
if (gameData.GameMaps.Count > 0)
{
var maps1 = gameMaps.ToList();
maps1.AddRange(gameData.GameMaps.Where(item => !item.IsSotF).ToList().ConvertAll(item => new ComboBoxItem { ValueMember = item.ClassName, DisplayMember = item.Description }));
var maps2 = gameMapsSotF.ToList();
maps2.AddRange(gameData.GameMaps.Where(item => item.IsSotF).ToList().ConvertAll(item => new ComboBoxItem { ValueMember = item.ClassName, DisplayMember = item.Description }));
gameMaps = maps1.ToArray();
gameMapsSotF = maps2.ToArray();
}
// total conversion mods
gameData.Mods.AddRange(userGameData.Mods);
if (gameData.Mods.Count > 0)
{
var mods1 = totalConversions.ToList();
mods1.AddRange(gameData.Mods.Where(item => !item.IsSotF).ToList().ConvertAll(item => new ComboBoxItem { ValueMember = item.ClassName, DisplayMember = item.Description }));
var mods2 = totalConversionsSotF.ToList();
mods2.AddRange(gameData.Mods.Where(item => item.IsSotF).ToList().ConvertAll(item => new ComboBoxItem { ValueMember = item.ClassName, DisplayMember = item.Description }));
totalConversions = mods1.ToArray();
totalConversionsSotF = mods2.ToArray();
}
// creature levels
if (userGameData.CreatureLevels.Count > 0)
gameData.CreatureLevels = userGameData.CreatureLevels;
if (gameData.CreatureLevels.Count > 0)
{
levelsDino = gameData.CreatureLevels.ConvertAll(item => new Level { XPRequired = item.XPRequired }).ToArray();
DefaultMaxExperiencePointsDino = levelsDino.Max(l => l.XPRequired) + 1;
}
// player levels
if (userGameData.PlayerLevels.Count > 0)
gameData.PlayerLevels = userGameData.PlayerLevels;
LevelsPlayerAdditional = userGameData.PlayerAdditionalLevels;
if (gameData.PlayerLevels.Count > 0)
{
levelsPlayer = gameData.PlayerLevels.ConvertAll(item => new Level { EngramPoints = item.EngramPoints, XPRequired = item.XPRequired }).ToArray();
DefaultMaxExperiencePointsPlayer = levelsPlayer.Max(l => l.XPRequired) + 1;
}
if (gameData.PlayerAdditionalLevels > LevelsPlayerAdditional)
LevelsPlayerAdditional = gameData.PlayerAdditionalLevels;
// branches
gameData.Branches.AddRange(userGameData.Branches);
if (gameData.Branches.Count > 0)
{
var branches1 = branches.ToList();
branches1.AddRange(gameData.Branches.Where(item => !item.IsSotF).ToList().ConvertAll(item => new ComboBoxItem { ValueMember = item.BranchName, DisplayMember = item.Description }));
var branches2 = branchesSotF.ToList();
branches2.AddRange(gameData.Branches.Where(item => item.IsSotF).ToList().ConvertAll(item => new ComboBoxItem { ValueMember = item.BranchName, DisplayMember = item.Description }));
branches = branches1.ToArray();
branchesSotF = branches2.ToArray();
}
// events
gameData.Events.AddRange(userGameData.Events);
if (gameData.Events.Count > 0)
{
var events1 = events.ToList();
events1.AddRange(gameData.Events.Where(item => !item.IsSotF).ToList().ConvertAll(item => new ComboBoxItem { ValueMember = item.EventName, DisplayMember = item.Description }));
var events2 = eventsSotF.ToList();
events2.AddRange(gameData.Events.Where(item => item.IsSotF).ToList().ConvertAll(item => new ComboBoxItem { ValueMember = item.EventName, DisplayMember = item.Description }));
events = events1.ToArray();
eventsSotF = events2.ToArray();
}
// official mods
gameData.OfficialMods.AddRange(userGameData.OfficialMods);
if (gameData.OfficialMods.Count > 0)
{
ModUtils.AddOfficialMods(gameData.OfficialMods.Where(m => !string.IsNullOrWhiteSpace(m.ModId)).Select(m => m.ModId));
}
}
public static string FriendlyNameForClass(string className, bool returnNullIfNotFound = false) => string.IsNullOrWhiteSpace(className) ? (returnNullIfNotFound ? null : string.Empty) : GlobalizedApplication.Instance.GetResourceString(className) ?? (returnNullIfNotFound ? null : className);
#region Creatures
private static DinoSpawn[] dinoSpawns = new DinoSpawn[0];
public static IEnumerable<DinoSpawn> GetDinoSpawns() => dinoSpawns.Select(d => d.Duplicate<DinoSpawn>());
public static IEnumerable<NPCReplacement> GetNPCReplacements() => dinoSpawns.Select(d => new NPCReplacement() { FromClassName = d.ClassName, ToClassName = d.ClassName });
public static bool IsSpawnableForClass(string className) => gameData?.Creatures?.FirstOrDefault(c => c.ClassName.Equals(className))?.IsSpawnable ?? true;
public static DinoTamable IsTameableForClass(string className) => gameData?.Creatures?.FirstOrDefault(c => c.ClassName.Equals(className))?.IsTameable ?? DinoTamable.True;
public static string NameTagForClass(string className, bool returnEmptyIfNotFound = false) => gameData?.Creatures?.FirstOrDefault(c => c.ClassName.Equals(className))?.NameTag ?? (returnEmptyIfNotFound ? string.Empty : className);
public static string FriendlyCreatureNameForClass(string className, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(className) ? string.Empty : GlobalizedApplication.Instance.GetResourceString(className) ?? gameData?.Creatures?.FirstOrDefault(i => i.ClassName.Equals(className))?.Description ?? (returnEmptyIfNotFound ? string.Empty : className);
private static ClassMultiplier[] dinoMultipliers = new ClassMultiplier[0];
public static IEnumerable<ClassMultiplier> GetDinoMultipliers() => dinoMultipliers.Select(d => d.Duplicate<ClassMultiplier>());
#endregion
#region Engrams
private static Engram[] engrams = new Engram[0];
public static IEnumerable<Engram> GetEngrams() => engrams.Select(d => d.Duplicate());
public static IEnumerable<EngramEntry> GetEngramEntries() => engrams.Select(d => new EngramEntry() { EngramClassName = d.EngramClassName, EngramLevelRequirement = d.EngramLevelRequirement, EngramPointsCost = d.EngramPointsCost });
public static Engram GetEngramForClass(string className) => engrams.FirstOrDefault(e => e.EngramClassName.Equals(className));
public static bool HasEngramForClass(string className) => engrams.Any(e => e.EngramClassName.Equals(className));
public static bool IsTekgram(string className) => engrams.Any(e => e.EngramClassName.Equals(className) && e.IsTekgram);
public static string FriendlyEngramNameForClass(string className, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(className) ? string.Empty : GlobalizedApplication.Instance.GetResourceString(className) ?? gameData?.Engrams?.FirstOrDefault(i => i.ClassName.Equals(className))?.Description ?? (returnEmptyIfNotFound ? string.Empty : className);
#endregion
#region Items
private static PrimalItem[] items = new PrimalItem[0];
public static IEnumerable<PrimalItem> GetItems() => items.Select(d => d.Duplicate());
public static PrimalItem GetItemForClass(string className) => items.FirstOrDefault(e => e.ClassName.Equals(className));
public static bool HasItemForClass(string className) => items.Any(e => e.ClassName.Equals(className));
public static string FriendlyItemNameForClass(string className, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(className) ? string.Empty : GlobalizedApplication.Instance.GetResourceString(className) ?? gameData?.Items?.FirstOrDefault(i => i.ClassName.Equals(className))?.Description ?? (returnEmptyIfNotFound ? string.Empty : className);
#endregion
#region Resources
private static ResourceClassMultiplier[] resourceMultipliers = new ResourceClassMultiplier[0];
public static IEnumerable<ResourceClassMultiplier> GetResourceMultipliers() => resourceMultipliers.Select(d => d.Duplicate<ResourceClassMultiplier>());
public static ResourceClassMultiplier GetResourceMultiplierForClass(string className) => resourceMultipliers.FirstOrDefault(e => e.ClassName.Equals(className));
public static bool HasResourceMultiplierForClass(string className) => resourceMultipliers.Any(e => e.ClassName.Equals(className));
public static string FriendlyResourceNameForClass(string className) => string.IsNullOrWhiteSpace(className) ? string.Empty : GlobalizedApplication.Instance.GetResourceString(className) ?? gameData?.Items?.FirstOrDefault(i => i.ClassName.Equals(className) && i.IsHarvestable)?.Description ?? className;
#endregion
#region Map Spawners
private static MapSpawner[] mapSpawners = new MapSpawner[0];
public static IEnumerable<MapSpawner> GetMapSpawners() => mapSpawners.Select(d => d.Duplicate());
public static MapSpawner GetMapSpawnerForClass(string className) => mapSpawners.FirstOrDefault(e => e.ClassName.Equals(className));
public static bool HasMapSpawnerForClass(string className) => mapSpawners.Any(e => e.ClassName.Equals(className));
public static string FriendlyMapSpawnerNameForClass(string className, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(className) ? string.Empty : GlobalizedApplication.Instance.GetResourceString(className) ?? gameData?.MapSpawners?.FirstOrDefault(i => i.ClassName.Equals(className))?.Description ?? (returnEmptyIfNotFound ? string.Empty : className);
#endregion
#region Supply Crates
private static SupplyCrate[] supplyCrates = new SupplyCrate[0];
public static IEnumerable<SupplyCrate> GetSupplyCrates() => supplyCrates.Select(d => d.Duplicate());
public static SupplyCrate GetSupplyCrateForClass(string className) => supplyCrates.FirstOrDefault(e => e.ClassName.Equals(className));
public static bool HasSupplyCrateForClass(string className) => supplyCrates.Any(e => e.ClassName.Equals(className));
public static string FriendlySupplyCrateNameForClass(string className, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(className) ? string.Empty : GlobalizedApplication.Instance.GetResourceString(className) ?? gameData?.SupplyCrates?.FirstOrDefault(i => i.ClassName.Equals(className))?.Description ?? (returnEmptyIfNotFound ? string.Empty : className);
#endregion
#region Game Maps
private static ComboBoxItem[] gameMaps = new[]
{
new ComboBoxItem { ValueMember="", DisplayMember="" },
};
public static IEnumerable<ComboBoxItem> GetGameMaps() => gameMaps.Select(d => d.Duplicate());
public static string FriendlyMapNameForClass(string className, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(className) ? string.Empty : GlobalizedApplication.Instance.GetResourceString(className) ?? gameData?.GameMaps?.FirstOrDefault(i => i.ClassName.Equals(className) && !i.IsSotF)?.Description ?? (returnEmptyIfNotFound ? string.Empty : className);
private static ComboBoxItem[] gameMapsSotF = new[]
{
new ComboBoxItem { ValueMember="", DisplayMember="" },
};
public static IEnumerable<ComboBoxItem> GetGameMapsSotF() => gameMapsSotF.Select(d => d.Duplicate());
public static string FriendlyMapSotFNameForClass(string className, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(className) ? string.Empty : GlobalizedApplication.Instance.GetResourceString(className) ?? gameData?.GameMaps?.FirstOrDefault(i => i.ClassName.Equals(className) && i.IsSotF)?.Description ?? (returnEmptyIfNotFound ? string.Empty : className);
#endregion
#region Total Conversions
private static ComboBoxItem[] totalConversions = new[]
{
new ComboBoxItem { ValueMember="", DisplayMember="" },
};
public static IEnumerable<ComboBoxItem> GetTotalConversions() => totalConversions.Select(d => d.Duplicate());
public static string FriendlyTotalConversionNameForClass(string className, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(className) ? string.Empty : GlobalizedApplication.Instance.GetResourceString(className) ?? gameData?.Mods?.FirstOrDefault(i => i.ClassName.Equals(className) && !i.IsSotF)?.Description ?? (returnEmptyIfNotFound ? string.Empty : className);
private static ComboBoxItem[] totalConversionsSotF = new[]
{
new ComboBoxItem { ValueMember="", DisplayMember="" },
};
public static IEnumerable<ComboBoxItem> GetTotalConversionsSotF() => totalConversionsSotF.Select(d => d.Duplicate());
public static string FriendlyTotalConversionSotFNameForClass(string className, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(className) ? string.Empty : GlobalizedApplication.Instance.GetResourceString(className) ?? gameData?.Mods?.FirstOrDefault(i => i.ClassName.Equals(className) && i.IsSotF)?.Description ?? (returnEmptyIfNotFound ? string.Empty : className);
#endregion
#region Stats Multipliers
internal static IEnumerable<float> GetPerLevelStatsMultipliers_DinoWild()
{
return new float[] { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
}
internal static IEnumerable<float> GetPerLevelStatsMultipliers_DinoTamed()
{
return new float[] { 0.2f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.17f, 1.0f, 1.0f, 1.0f };
}
internal static IEnumerable<float> GetPerLevelStatsMultipliers_DinoTamedAdd()
{
return new float[] { 0.14f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.14f, 1.0f, 1.0f, 1.0f };
}
internal static IEnumerable<float> GetPerLevelStatsMultipliers_DinoTamedAffinity()
{
return new float[] { 0.44f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.44f, 1.0f, 1.0f, 1.0f };
}
internal static IEnumerable<float> GetBaseStatMultipliers_Player()
{
return new float[] { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
}
internal static IEnumerable<float> GetPerLevelStatsMultipliers_Player()
{
return new float[] { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
}
internal static bool[] GetStatMultiplierInclusions_DinoWildPerLevel()
{
return new bool[] { true, true, false, true, true, false, true, true, true, true, false, true };
}
internal static bool[] GetStatMultiplierInclusions_DinoTamedPerLevel()
{
return new bool[] { true, true, false, true, true, false, true, true, true, true, false, true };
}
internal static bool[] GetStatMultiplierInclusions_DinoTamedAdd()
{
return new bool[] { true, true, true, true, true, true, true, true, true, true, true, true };
}
internal static bool[] GetStatMultiplierInclusions_DinoTamedAffinity()
{
return new bool[] { true, true, true, true, true, true, true, true, true, true, true, true };
}
internal static bool[] GetStatMultiplierInclusions_PlayerBase()
{
return new bool[] { true, true, true, true, true, true, true, true, true, true, true, true };
}
internal static bool[] GetStatMultiplierInclusions_PlayerPerLevel()
{
return new bool[] { true, true, false, true, true, true, true, true, true, true, true, true };
}
#endregion
#region Levels
private static Level[] levelsDino = new[]
{
new Level { XPRequired=10 },
};
private static Level[] levelsPlayer = new[]
{
new Level { XPRequired=5, EngramPoints=8 },
};
public static IEnumerable<Level> LevelsDino => levelsDino.Select(l => l.Duplicate());
public static IEnumerable<Level> LevelsPlayer => levelsPlayer.Select(l => l.Duplicate());
public static int LevelsPlayerAdditional = 0;
#endregion
#region Branches
private static ComboBoxItem[] branches = new[]
{
new ComboBoxItem { ValueMember="", DisplayMember=FriendlyNameForClass(Config.Default.DefaultServerBranchName) },
};
public static IEnumerable<ComboBoxItem> GetBranches() => branches.Select(d => d.Duplicate());
public static string FriendlyBranchName(string branchName, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(branchName) ? string.Empty : GlobalizedApplication.Instance.GetResourceString(branchName) ?? gameData?.Branches?.FirstOrDefault(i => i.BranchName.Equals(branchName) && !i.IsSotF)?.Description ?? (returnEmptyIfNotFound ? string.Empty : branchName);
private static ComboBoxItem[] branchesSotF = new[]
{
new ComboBoxItem { ValueMember="", DisplayMember=FriendlyNameForClass(Config.Default.DefaultServerBranchName) },
};
public static IEnumerable<ComboBoxItem> GetBranchesSotF() => branchesSotF.Select(d => d.Duplicate());
public static string FriendlyBranchSotFName(string branchName, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(branchName) ? string.Empty : GlobalizedApplication.Instance.GetResourceString(branchName) ?? gameData?.Branches?.FirstOrDefault(i => i.BranchName.Equals(branchName) && i.IsSotF)?.Description ?? (returnEmptyIfNotFound ? string.Empty : branchName);
#endregion
#region Events
private static ComboBoxItem[] events = new[]
{
new ComboBoxItem { ValueMember="", DisplayMember=string.Empty },
};
public static IEnumerable<ComboBoxItem> GetEvents() => events.Select(d => d.Duplicate());
public static string FriendlyEventName(string eventName, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(eventName) ? string.Empty : GlobalizedApplication.Instance.GetResourceString(eventName) ?? gameData?.Events?.FirstOrDefault(i => i.EventName.Equals(eventName) && !i.IsSotF)?.Description ?? (returnEmptyIfNotFound ? string.Empty : eventName);
private static ComboBoxItem[] eventsSotF = new[]
{
new ComboBoxItem { ValueMember="", DisplayMember=string.Empty },
};
public static IEnumerable<ComboBoxItem> GetEventsSotF() => eventsSotF.Select(d => d.Duplicate());
public static string FriendlyEventSotFName(string eventName, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(eventName) ? string.Empty : GlobalizedApplication.Instance.GetResourceString(eventName) ?? gameData?.Events?.FirstOrDefault(i => i.EventName.Equals(eventName) && i.IsSotF)?.Description ?? (returnEmptyIfNotFound ? string.Empty : eventName);
#endregion
}
}

View file

@ -0,0 +1,46 @@
using ServerManagerTool.Common.Attibutes;
using ServerManagerTool.Common.Model;
using System;
using System.Runtime.Serialization;
using System.Windows;
namespace ServerManagerTool.Lib
{
[DataContract]
public class ClassMultiplier : AggregateIniValue
{
public const float DEFAULT_MULTIPLIER = 1.0f;
public static readonly DependencyProperty ClassNameProperty = DependencyProperty.Register(nameof(ClassName), typeof(string), typeof(ClassMultiplier), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty MultiplierProperty = DependencyProperty.Register(nameof(Multiplier), typeof(float), typeof(ClassMultiplier), new PropertyMetadata(DEFAULT_MULTIPLIER));
[DataMember]
[AggregateIniValueEntry]
public string ClassName
{
get { return (string)GetValue(ClassNameProperty); }
set { SetValue(ClassNameProperty, value); }
}
[DataMember]
[AggregateIniValueEntry]
public float Multiplier
{
get { return (float)GetValue(MultiplierProperty); }
set { SetValue(MultiplierProperty, value); }
}
public virtual string DisplayName => GameData.FriendlyNameForClass(ClassName);
public static ClassMultiplier FromINIValue(string iniValue)
{
var newSpawn = new ClassMultiplier();
newSpawn.InitializeFromINIValue(iniValue);
return newSpawn;
}
public override string GetSortKey() => GameData.FriendlyNameForClass(this.ClassName);
public override bool IsEquivalent(AggregateIniValue other) => String.Equals(this.ClassName, ((ClassMultiplier)other).ClassName, StringComparison.OrdinalIgnoreCase);
}
}

View file

@ -0,0 +1,123 @@
using ServerManagerTool.Common.Attibutes;
using ServerManagerTool.Common.Model;
using System.Runtime.Serialization;
using System.Windows;
namespace ServerManagerTool.Lib
{
[DataContract]
public class CraftingOverride : AggregateIniValue
{
public CraftingOverride()
{
BaseCraftingResourceRequirements = new AggregateIniValueList<CraftingResourceRequirement>(null, null);
}
public static readonly DependencyProperty ItemClassStringProperty = DependencyProperty.Register(nameof(ItemClassString), typeof(string), typeof(CraftingOverride), new PropertyMetadata(string.Empty));
[DataMember]
[AggregateIniValueEntry]
public string ItemClassString
{
get { return (string)GetValue(ItemClassStringProperty); }
set { SetValue(ItemClassStringProperty, value); }
}
public static readonly DependencyProperty BaseCraftingResourceRequirementsProperty = DependencyProperty.Register(nameof(BaseCraftingResourceRequirements), typeof(AggregateIniValueList<CraftingResourceRequirement>), typeof(CraftingOverride), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry(ValueWithinBrackets = true, ListValueWithinBrackets = true)]
public AggregateIniValueList<CraftingResourceRequirement> BaseCraftingResourceRequirements
{
get { return (AggregateIniValueList<CraftingResourceRequirement>)GetValue(BaseCraftingResourceRequirementsProperty); }
set { SetValue(BaseCraftingResourceRequirementsProperty, value); }
}
public override string GetSortKey()
{
return null;
}
public override bool IsEquivalent(AggregateIniValue other)
{
return false;
}
public override void InitializeFromINIValue(string value)
{
if (string.IsNullOrWhiteSpace(value))
return;
var kvPair = value.Split(new[] { '=' }, 2);
var kvValue = kvPair[1].Trim(' ');
if (kvValue.StartsWith("("))
kvValue = kvValue.Substring(1);
if (kvValue.EndsWith(")"))
kvValue = kvValue.Substring(0, kvValue.Length - 1);
base.FromComplexINIValue(kvValue);
}
public override string ToINIValue()
{
return base.ToComplexINIValue(true);
}
public string DisplayName => GameData.FriendlyItemNameForClass(ItemClassString);
public bool IsValid => !string.IsNullOrWhiteSpace(ItemClassString) && BaseCraftingResourceRequirements.Count > 0;
}
[DataContract]
public class CraftingResourceRequirement : AggregateIniValue
{
public static readonly DependencyProperty ResourceItemTypeStringProperty = DependencyProperty.Register(nameof(ResourceItemTypeString), typeof(string), typeof(CraftingResourceRequirement), new PropertyMetadata(string.Empty));
[DataMember]
[AggregateIniValueEntry]
public string ResourceItemTypeString
{
get { return (string)GetValue(ResourceItemTypeStringProperty); }
set { SetValue(ResourceItemTypeStringProperty, value); }
}
public static readonly DependencyProperty BaseResourceRequirementProperty = DependencyProperty.Register(nameof(BaseResourceRequirement), typeof(float), typeof(CraftingResourceRequirement), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float BaseResourceRequirement
{
get { return (float)GetValue(BaseResourceRequirementProperty); }
set { SetValue(BaseResourceRequirementProperty, value); }
}
public static readonly DependencyProperty CraftingRequireExactResourceTypeProperty = DependencyProperty.Register(nameof(CraftingRequireExactResourceType), typeof(bool), typeof(CraftingResourceRequirement), new PropertyMetadata(false));
[DataMember]
[AggregateIniValueEntry(Key = "bCraftingRequireExactResourceType")]
public bool CraftingRequireExactResourceType
{
get { return (bool)GetValue(CraftingRequireExactResourceTypeProperty); }
set { SetValue(CraftingRequireExactResourceTypeProperty, value); }
}
public override string GetSortKey()
{
return null;
}
public override bool IsEquivalent(AggregateIniValue other)
{
return false;
}
public override void InitializeFromINIValue(string value)
{
base.FromComplexINIValue(value);
}
public override string ToINIValue()
{
return base.ToComplexINIValue(false);
}
public string DisplayName => GameData.FriendlyItemNameForClass(ResourceItemTypeString);
public bool IsValid => !string.IsNullOrWhiteSpace(ResourceItemTypeString);
}
}

View file

@ -0,0 +1,101 @@
using ServerManagerTool.Common.Attibutes;
using ServerManagerTool.Common.Model;
using ServerManagerTool.Enums;
using System;
using System.Runtime.Serialization;
using System.Windows;
using System.Xml.Serialization;
namespace ServerManagerTool.Lib
{
[DataContract]
public class DinoSpawn : AggregateIniValue
{
public const bool DEFAULT_OVERRIDE_SPAWN_LIMIT_PERCENTAGE = true;
public const float DEFAULT_SPAWN_LIMIT_PERCENTAGE = ClassMultiplier.DEFAULT_MULTIPLIER;
public const float DEFAULT_SPAWN_WEIGHT_MULTIPLIER = ClassMultiplier.DEFAULT_MULTIPLIER;
public static readonly DependencyProperty ClassNameProperty = DependencyProperty.Register(nameof(ClassName), typeof(string), typeof(DinoSpawn), new PropertyMetadata(String.Empty));
public static readonly DependencyProperty ModProperty = DependencyProperty.Register(nameof(Mod), typeof(string), typeof(DinoSpawn), new PropertyMetadata(String.Empty));
public static readonly DependencyProperty KnownDinoProperty = DependencyProperty.Register(nameof(KnownDino), typeof(bool), typeof(DinoSpawn), new PropertyMetadata(false));
public static readonly DependencyProperty DinoNameTagProperty = DependencyProperty.Register(nameof(DinoNameTag), typeof(string), typeof(DinoSpawn), new PropertyMetadata(String.Empty));
public static readonly DependencyProperty OverrideSpawnLimitPercentageProperty = DependencyProperty.Register(nameof(OverrideSpawnLimitPercentage), typeof(bool), typeof(DinoSpawn), new PropertyMetadata(DEFAULT_OVERRIDE_SPAWN_LIMIT_PERCENTAGE));
public static readonly DependencyProperty SpawnLimitPercentageProperty = DependencyProperty.Register(nameof(SpawnLimitPercentage), typeof(float), typeof(DinoSpawn), new PropertyMetadata(DEFAULT_SPAWN_LIMIT_PERCENTAGE));
public static readonly DependencyProperty SpawnWeightMultiplierProperty = DependencyProperty.Register(nameof(SpawnWeightMultiplier), typeof(float), typeof(DinoSpawn), new PropertyMetadata(DEFAULT_SPAWN_WEIGHT_MULTIPLIER));
[DataMember]
public string ClassName
{
get { return (string)GetValue(ClassNameProperty); }
set { SetValue(ClassNameProperty, value); }
}
[DataMember]
public string Mod
{
get { return (string)GetValue(ModProperty); }
set { SetValue(ModProperty, value); }
}
[DataMember]
public bool KnownDino
{
get { return (bool)GetValue(KnownDinoProperty); }
set { SetValue(KnownDinoProperty, value); }
}
[XmlElement(ElementName="Name")]
[DataMember]
[AggregateIniValueEntry]
public string DinoNameTag
{
get { return (string)GetValue(DinoNameTagProperty); }
set { SetValue(DinoNameTagProperty, value); }
}
[DataMember]
[AggregateIniValueEntry]
public bool OverrideSpawnLimitPercentage
{
get { return (bool)GetValue(OverrideSpawnLimitPercentageProperty); }
set { SetValue(OverrideSpawnLimitPercentageProperty, value); }
}
[DataMember]
[AggregateIniValueEntry]
public float SpawnLimitPercentage
{
get { return (float)GetValue(SpawnLimitPercentageProperty); }
set { SetValue(SpawnLimitPercentageProperty, value); }
}
[DataMember]
[AggregateIniValueEntry]
public float SpawnWeightMultiplier
{
get { return (float)GetValue(SpawnWeightMultiplierProperty); }
set { SetValue(SpawnWeightMultiplierProperty, value); }
}
public string DisplayName => GameData.FriendlyCreatureNameForClass(ClassName);
public string DisplayMod => GameData.FriendlyNameForClass($"Mod_{Mod}", true) ?? Mod;
public static DinoSpawn FromINIValue(string iniValue)
{
var newSpawn = new DinoSpawn();
newSpawn.InitializeFromINIValue(iniValue);
return newSpawn;
}
public override string GetSortKey()
{
return this.DinoNameTag;
}
public override bool IsEquivalent(AggregateIniValue other)
{
return String.Equals(this.DinoNameTag, ((DinoSpawn)other).DinoNameTag, StringComparison.OrdinalIgnoreCase);
}
}
}

View file

@ -0,0 +1,91 @@
using ServerManagerTool.Common.Attibutes;
using ServerManagerTool.Common.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Windows;
namespace ServerManagerTool.Lib
{
public class EngramAutoUnlockList : AggregateIniValueList<EngramAutoUnlock>
{
public EngramAutoUnlockList(string aggregateValueName)
: base(aggregateValueName, null)
{
}
public override void FromIniValues(IEnumerable<string> iniValues)
{
var items = iniValues?.Select(AggregateIniValue.FromINIValue<EngramAutoUnlock>).ToArray();
Clear();
var itemsToAdd = items.Where(i => !this.Any(e => e.IsEquivalent(i))).ToArray();
AddRange(itemsToAdd);
var itemsToUpdate = items.Where(i => this.Any(e => e.IsEquivalent(i))).ToArray();
foreach (var item in itemsToUpdate)
{
var e = this.FirstOrDefault(r => r.IsEquivalent(item));
e.LevelToAutoUnlock = item.LevelToAutoUnlock;
}
IsEnabled = (Count != 0);
Sort(AggregateIniValue.SortKeySelector);
}
public override IEnumerable<string> ToIniValues()
{
if (string.IsNullOrWhiteSpace(IniCollectionKey))
return this.Where(d => d.ShouldSave()).Select(d => d.ToINIValue());
return this.Where(d => d.ShouldSave()).Select(d => $"{this.IniCollectionKey}={d.ToINIValue()}");
}
}
public class EngramAutoUnlock : AggregateIniValue
{
public static readonly DependencyProperty EngramClassNameProperty = DependencyProperty.Register(nameof(EngramClassName), typeof(string), typeof(EngramAutoUnlock), new PropertyMetadata(String.Empty));
public static readonly DependencyProperty LevelToAutoUnlockProperty = DependencyProperty.Register(nameof(LevelToAutoUnlock), typeof(int), typeof(EngramAutoUnlock), new PropertyMetadata(0));
[DataMember]
[AggregateIniValueEntry]
public string EngramClassName
{
get { return (string)GetValue(EngramClassNameProperty); }
set { SetValue(EngramClassNameProperty, value); }
}
[DataMember]
[AggregateIniValueEntry]
public int LevelToAutoUnlock
{
get { return (int)GetValue(LevelToAutoUnlockProperty); }
set { SetValue(LevelToAutoUnlockProperty, value); }
}
public static EngramAutoUnlock FromINIValue(string iniValue)
{
var engramAutoUnlock = new EngramAutoUnlock();
engramAutoUnlock.InitializeFromINIValue(iniValue);
return engramAutoUnlock;
}
public override string GetSortKey()
{
return null;
}
public override bool IsEquivalent(AggregateIniValue other)
{
return String.Equals(this.EngramClassName, ((EngramAutoUnlock)other).EngramClassName, StringComparison.OrdinalIgnoreCase);
}
public override string ToINIValue()
{
return base.ToINIValue();
}
}
}

View file

@ -0,0 +1,128 @@
using ServerManagerTool.Common.Attibutes;
using ServerManagerTool.Common.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Windows;
namespace ServerManagerTool.Lib
{
[DataContract]
public class EngramEntryList : AggregateIniValueList<EngramEntry>
{
public EngramEntryList(string aggregateValueName)
: base(aggregateValueName, null)
{
}
public override void FromIniValues(IEnumerable<string> iniValues)
{
var items = iniValues?.Select(AggregateIniValue.FromINIValue<EngramEntry>).ToArray();
Clear();
var itemsToAdd = items.Where(i => !this.Any(e => e.IsEquivalent(i))).ToArray();
AddRange(itemsToAdd);
var itemsToUpdate = items.Where(i => this.Any(e => e.IsEquivalent(i))).ToArray();
foreach (var item in itemsToUpdate)
{
var e = this.FirstOrDefault(r => r.IsEquivalent(item));
e.EngramLevelRequirement = item.EngramLevelRequirement;
e.EngramPointsCost = item.EngramPointsCost;
e.EngramHidden = item.EngramHidden;
e.RemoveEngramPreReq = item.RemoveEngramPreReq;
}
IsEnabled = (Count != 0);
Sort(AggregateIniValue.SortKeySelector);
}
public override IEnumerable<string> ToIniValues()
{
if (string.IsNullOrWhiteSpace(IniCollectionKey))
return this.Where(d => d.ShouldSave()).Select(d => d.ToINIValue());
return this.Where(d => d.ShouldSave()).Select(d => $"{this.IniCollectionKey}={d.ToINIValue()}");
}
}
[DataContract]
public class EngramEntry : AggregateIniValue
{
public static readonly DependencyProperty EngramClassNameProperty = DependencyProperty.Register(nameof(EngramClassName), typeof(string), typeof(EngramEntry), new PropertyMetadata(String.Empty));
public static readonly DependencyProperty EngramLevelRequirementProperty = DependencyProperty.Register(nameof(EngramLevelRequirement), typeof(int), typeof(EngramEntry), new PropertyMetadata(0));
public static readonly DependencyProperty EngramPointsCostProperty = DependencyProperty.Register(nameof(EngramPointsCost), typeof(int), typeof(EngramEntry), new PropertyMetadata(0));
public static readonly DependencyProperty EngramHiddenProperty = DependencyProperty.Register(nameof(EngramHidden), typeof(bool), typeof(EngramEntry), new PropertyMetadata(false));
public static readonly DependencyProperty RemoveEngramPreReqProperty = DependencyProperty.Register(nameof(RemoveEngramPreReq), typeof(bool), typeof(EngramEntry), new PropertyMetadata(false));
[DataMember]
[AggregateIniValueEntry]
public string EngramClassName
{
get { return (string)GetValue(EngramClassNameProperty); }
set { SetValue(EngramClassNameProperty, value); }
}
[DataMember]
[AggregateIniValueEntry]
public int EngramLevelRequirement
{
get { return (int)GetValue(EngramLevelRequirementProperty); }
set { SetValue(EngramLevelRequirementProperty, value); }
}
[DataMember]
[AggregateIniValueEntry]
public int EngramPointsCost
{
get { return (int)GetValue(EngramPointsCostProperty); }
set { SetValue(EngramPointsCostProperty, value); }
}
[DataMember]
[AggregateIniValueEntry]
public bool EngramHidden
{
get { return (bool)GetValue(EngramHiddenProperty); }
set { SetValue(EngramHiddenProperty, value); }
}
[DataMember]
[AggregateIniValueEntry]
public bool RemoveEngramPreReq
{
get { return (bool)GetValue(RemoveEngramPreReqProperty); }
set { SetValue(RemoveEngramPreReqProperty, value); }
}
public static EngramEntry FromINIValue(string iniValue)
{
var engramEntry = new EngramEntry();
engramEntry.InitializeFromINIValue(iniValue);
return engramEntry;
}
public override string GetSortKey()
{
return null;
}
public override void InitializeFromINIValue(string value)
{
base.InitializeFromINIValue(value);
}
public override bool IsEquivalent(AggregateIniValue other)
{
return String.Equals(this.EngramClassName, ((EngramEntry)other).EngramClassName, StringComparison.OrdinalIgnoreCase);
}
public override string ToINIValue()
{
return base.ToINIValue();
}
}
}

View file

@ -0,0 +1,260 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Xml.Serialization;
using TinyCsvParser.Mapping;
using System.Runtime.Serialization;
using ServerManagerTool.Common.Model;
namespace ServerManagerTool.Lib
{
[DataContract]
public class LevelList : SortableObservableCollection<Level>
{
const bool WORKAROUND_FOR_ENGRAM_LIST = true;
public static readonly Regex XPRegex = new Regex(@"ExperiencePointsForLevel\[(?<level>\d*)]=(?<xp>\d*)", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.Compiled);
public static readonly Regex EngramRegex = new Regex(@"OverridePlayerLevelEngramPoints=(?<points>\d*)", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.Compiled);
public static int AdditionalLevels = GameData.LevelsPlayerAdditional;
public void RemoveLevel(Level level)
{
base.Remove(level);
UpdateTotals();
}
public void AddRange(IEnumerable<Level> levels)
{
foreach (var level in levels)
{
base.Add(level);
}
UpdateTotals();
}
public void AddNewLevel(Level afterLevel)
{
AddNewLevel(afterLevel, 1);
}
public void AddNewLevel(Level afterLevel, int xpIncrease)
{
var newLevel = new Level
{
LevelIndex = 0,
XPRequired = afterLevel.XPRequired + xpIncrease,
EngramPoints = afterLevel.EngramPoints
};
base.Insert(base.IndexOf(afterLevel) + 1, newLevel);
UpdateTotals();
}
public void UpdateTotals()
{
int index = 0;
int xpTotal = 0;
int engramTotal = 0;
foreach (var existingLevel in this.OrderBy(l => l.XPRequired).ToArray())
{
xpTotal += existingLevel.XPRequired;
engramTotal += existingLevel.EngramPoints;
existingLevel.XPTotal = xpTotal;
existingLevel.EngramTotal = engramTotal;
existingLevel.LevelIndex = index;
existingLevel.ShowColored = index >= this.Count - AdditionalLevels;
index++;
}
base.Sort(f => f.LevelIndex);
}
public string ToINIValueForXP()
{
var builder = new StringBuilder();
builder.Append("LevelExperienceRampOverrides=(");
builder.Append(String.Join(",", this.OrderBy(l => l.XPRequired).Select(l => l.GetINISubValueForXP())));
builder.Append(')');
return builder.ToString();
}
public List<string> ToINIValuesForEngramPoints()
{
var entries = new List<string>();
if (WORKAROUND_FOR_ENGRAM_LIST)
{
entries.Add(new Level().GetINIValueForEngramPointsEarned());
}
foreach (var level in this.OrderBy(l => l.XPRequired))
{
entries.Add(level.GetINIValueForEngramPointsEarned());
}
return entries;
}
public static LevelList FromINIValues(string xpValue, IEnumerable<string> engramValues = null)
{
var levels = new LevelList();
var xpResult = XPRegex.Match(xpValue);
var engramResult = engramValues == null ? null : EngramRegex.Match(String.Join(" ", engramValues));
if (WORKAROUND_FOR_ENGRAM_LIST)
{
if (engramResult != null)
{
engramResult = engramResult.NextMatch();
}
}
while (xpResult.Success && (engramValues == null || engramResult.Success))
{
int levelIndex;
if (!int.TryParse(xpResult.Groups["level"].Value, out levelIndex))
{
Debug.WriteLine(String.Format("Invalid level index value: '{0}'", xpResult.Groups["level"].Value));
break;
}
int xpRequired;
if (!int.TryParse(xpResult.Groups["xp"].Value, out xpRequired))
{
Debug.WriteLine(String.Format("Invalid xm required value: '{0}'", xpResult.Groups["xp"].Value));
break;
}
int engramPoints = 0;
if (engramResult != null)
{
if (!int.TryParse(engramResult.Groups["points"].Value, out engramPoints))
{
Debug.WriteLine(String.Format("Invalid engram points value: '{0}'", engramResult.Groups["points"].Value));
break;
}
}
levels.Add(new Level { LevelIndex = levelIndex, XPRequired = xpRequired, EngramPoints = engramPoints });
xpResult = xpResult.NextMatch();
if (engramResult != null)
{
engramResult = engramResult.NextMatch();
}
}
levels.UpdateTotals();
return levels;
}
}
[DataContract]
public class Level : DependencyObject
{
public static readonly DependencyProperty LevelIndexProperty = DependencyProperty.Register(nameof(LevelIndex), typeof(int), typeof(Level), new PropertyMetadata(0));
public static readonly DependencyProperty XPRequiredProperty = DependencyProperty.Register(nameof(XPRequired), typeof(int), typeof(Level), new PropertyMetadata(0));
public static readonly DependencyProperty EngramPointsProperty = DependencyProperty.Register(nameof(EngramPoints), typeof(int), typeof(Level), new PropertyMetadata(0));
public static readonly DependencyProperty XPTotalProperty = DependencyProperty.Register(nameof(XPTotal), typeof(int), typeof(Level), new PropertyMetadata(0));
public static readonly DependencyProperty EngramTotalProperty = DependencyProperty.Register(nameof(EngramTotal), typeof(int), typeof(Level), new PropertyMetadata(0));
public static readonly DependencyProperty ShowColoredProperty = DependencyProperty.Register(nameof(ShowColored), typeof(bool), typeof(Level), new PropertyMetadata(false));
[DataMember]
public int LevelIndex
{
get { return (int)GetValue(LevelIndexProperty); }
set { SetValue(LevelIndexProperty, value); }
}
[DataMember]
public int XPRequired
{
get { return (int)GetValue(XPRequiredProperty); }
set { SetValue(XPRequiredProperty, value); }
}
[DataMember]
public int EngramPoints
{
get { return (int)GetValue(EngramPointsProperty); }
set { SetValue(EngramPointsProperty, value); }
}
[XmlIgnore()]
public int XPTotal
{
get { return (int)GetValue(XPTotalProperty); }
set { SetValue(XPTotalProperty, value); }
}
[XmlIgnore()]
public int EngramTotal
{
get { return (int)GetValue(EngramTotalProperty); }
set { SetValue(EngramTotalProperty, value); }
}
public string GetINISubValueForXP()
{
return String.Format("ExperiencePointsForLevel[{0}]={1}", this.LevelIndex, this.XPRequired);
}
public string GetINIValueForEngramPointsEarned()
{
return String.Format("OverridePlayerLevelEngramPoints={0}", this.EngramPoints);
}
internal Level Duplicate()
{
return new Level { XPRequired = this.XPRequired, EngramPoints = this.EngramPoints };
}
public bool ShowColored
{
get { return (bool)GetValue(ShowColoredProperty); }
set { SetValue(ShowColoredProperty, value); }
}
}
public class CsvPlayerLevelMapping : CsvMapping<ImportLevel>
{
public CsvPlayerLevelMapping()
: base()
{
MapProperty(0, x => x.LevelIndex);
MapProperty(1, x => x.XPRequired);
MapProperty(2, x => x.EngramPoints);
}
}
public class CsvDinoLevelMapping : CsvMapping<ImportLevel>
{
public CsvDinoLevelMapping()
: base()
{
MapProperty(0, x => x.LevelIndex);
MapProperty(1, x => x.XPRequired);
}
}
public class ImportLevel
{
public int LevelIndex { get; set; }
public int XPRequired { get; set; }
public int EngramPoints { get; set; }
public Level AsLevel()
{
return new Level() { LevelIndex = LevelIndex, XPRequired = XPRequired, EngramPoints = EngramPoints };
}
}
}

View file

@ -0,0 +1,53 @@
using ServerManagerTool.Common.Attibutes;
using ServerManagerTool.Common.Model;
using System;
using System.Runtime.Serialization;
using System.Windows;
namespace ServerManagerTool.Lib
{
[DataContract]
public class NPCReplacement : AggregateIniValue
{
public static readonly DependencyProperty FromClassNameProperty = DependencyProperty.Register(nameof(FromClassName), typeof(string), typeof(NPCReplacement), new PropertyMetadata(String.Empty));
public static readonly DependencyProperty ToClassNameProperty = DependencyProperty.Register(nameof(ToClassName), typeof(string), typeof(NPCReplacement), new PropertyMetadata(String.Empty));
[DataMember]
[AggregateIniValueEntry]
public string FromClassName
{
get { return (string)GetValue(FromClassNameProperty); }
set { SetValue(FromClassNameProperty, value); }
}
[DataMember]
[AggregateIniValueEntry]
public string ToClassName
{
get { return (string)GetValue(ToClassNameProperty); }
set { SetValue(ToClassNameProperty, value); }
}
public static NPCReplacement FromINIValue(string iniValue)
{
var newSpawn = new NPCReplacement();
newSpawn.InitializeFromINIValue(iniValue);
return newSpawn;
}
public override string GetSortKey()
{
return this.FromClassName;
}
public override bool IsEquivalent(AggregateIniValue other)
{
return String.Equals(this.FromClassName, ((NPCReplacement)other).FromClassName, StringComparison.OrdinalIgnoreCase);
}
public override bool ShouldSave()
{
return (!String.Equals(FromClassName, ToClassName, StringComparison.OrdinalIgnoreCase));
}
}
}

View file

@ -0,0 +1,509 @@
using ServerManagerTool.Common.Attibutes;
using ServerManagerTool.Common.Interfaces;
using ServerManagerTool.Common.Model;
using ServerManagerTool.Common.Utils;
using ServerManagerTool.Enums;
using ServerManagerTool.Interface;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Windows;
namespace ServerManagerTool.Lib
{
[DataContract]
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class NPCSpawnAttribute : Attribute
{
/// <summary>
/// Attribute for the NPCSpawn value
/// </summary>
public NPCSpawnAttribute(NPCSpawnContainerType[] containerTypes)
{
this.ContainerTypes = containerTypes.ToList();
}
/// <summary>
/// The ContainerTypes that are valid for the property.
/// </summary>
[DataMember]
public List<NPCSpawnContainerType> ContainerTypes;
}
[DataContract]
public class NPCSpawnContainerList<T> : AggregateIniValueList<T>, ISpawnIniValuesCollection
where T : AggregateIniValue, new()
{
public NPCSpawnContainerList(string aggregateValueName, NPCSpawnContainerType containerType)
: base(aggregateValueName, null)
{
ContainerType = containerType;
}
[DataMember]
public NPCSpawnContainerType ContainerType
{
get;
set;
}
public override IEnumerable<string> ToIniValues()
{
return this.ToIniValues(ContainerType);
}
public IEnumerable<string> ToIniValues(NPCSpawnContainerType containerType)
{
if (string.IsNullOrWhiteSpace(IniCollectionKey))
return this.Where(d => d.ShouldSave()).Cast<ISpawnIniValue>().Select(d => d.ToIniValue(containerType));
return this.Where(d => d.ShouldSave()).Cast<ISpawnIniValue>().Select(d => $"{this.IniCollectionKey}={d.ToIniValue(containerType)}");
}
}
[DataContract]
public class NPCSpawnContainer : AggregateIniValue, ISpawnIniValue
{
public NPCSpawnContainer()
{
NPCSpawnEntries = new NPCSpawnList<NPCSpawnEntry>(null);
NPCSpawnLimits = new NPCSpawnList<NPCSpawnLimit>(null);
}
[DataMember]
public Guid UniqueId = Guid.NewGuid();
public static readonly DependencyProperty NPCSpawnEntriesContainerClassStringProperty = DependencyProperty.Register(nameof(NPCSpawnEntriesContainerClassString), typeof(string), typeof(NPCSpawnContainer), new PropertyMetadata(string.Empty));
[DataMember]
[AggregateIniValueEntry]
[NPCSpawn(new[] { NPCSpawnContainerType.Add, NPCSpawnContainerType.Subtract, NPCSpawnContainerType.Override })]
public string NPCSpawnEntriesContainerClassString
{
get { return (string)GetValue(NPCSpawnEntriesContainerClassStringProperty); }
set { SetValue(NPCSpawnEntriesContainerClassStringProperty, value); }
}
public static readonly DependencyProperty NPCSpawnEntriesProperty = DependencyProperty.Register(nameof(NPCSpawnEntries), typeof(NPCSpawnList<NPCSpawnEntry>), typeof(NPCSpawnContainer), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry(ValueWithinBrackets = true, ListValueWithinBrackets = true)]
[NPCSpawn(new[] { NPCSpawnContainerType.Add, NPCSpawnContainerType.Subtract, NPCSpawnContainerType.Override })]
public NPCSpawnList<NPCSpawnEntry> NPCSpawnEntries
{
get { return (NPCSpawnList<NPCSpawnEntry>)GetValue(NPCSpawnEntriesProperty); }
set { SetValue(NPCSpawnEntriesProperty, value); }
}
public static readonly DependencyProperty NPCSpawnLimitsProperty = DependencyProperty.Register(nameof(NPCSpawnLimits), typeof(NPCSpawnList<NPCSpawnLimit>), typeof(NPCSpawnContainer), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry(ValueWithinBrackets = true, ListValueWithinBrackets = true)]
[NPCSpawn(new[] { NPCSpawnContainerType.Add, NPCSpawnContainerType.Subtract, NPCSpawnContainerType.Override })]
public NPCSpawnList<NPCSpawnLimit> NPCSpawnLimits
{
get { return (NPCSpawnList<NPCSpawnLimit>)GetValue(NPCSpawnLimitsProperty); }
set { SetValue(NPCSpawnLimitsProperty, value); }
}
public override string GetSortKey()
{
return null;
}
public override bool IsEquivalent(AggregateIniValue other)
{
return false;
}
public override void InitializeFromINIValue(string value)
{
if (string.IsNullOrWhiteSpace(value))
return;
var kvPair = value.Split(new[] { '=' }, 2);
var kvValue = kvPair[1].Trim(' ');
if (kvValue.StartsWith("("))
kvValue = kvValue.Substring(1);
if (kvValue.EndsWith(")"))
kvValue = kvValue.Substring(0, kvValue.Length - 1);
base.FromComplexINIValue(kvValue);
}
public override string ToINIValue()
{
throw new NotImplementedException();
}
public string ToIniValue(NPCSpawnContainerType containerType)
{
GetPropertyInfos();
if (this.Properties.Count == 0)
return string.Empty;
var result = new StringBuilder();
result.Append("(");
var delimiter = "";
foreach (var prop in this.Properties)
{
var attrSpawn = prop.GetCustomAttributes(typeof(NPCSpawnAttribute), false).OfType<NPCSpawnAttribute>().FirstOrDefault();
if (!attrSpawn?.ContainerTypes?.Contains(containerType) ?? false)
continue;
result.Append(delimiter);
var attr = prop.GetCustomAttributes(typeof(AggregateIniValueEntryAttribute), false).OfType<AggregateIniValueEntryAttribute>().FirstOrDefault();
var propName = string.IsNullOrWhiteSpace(attr?.Key) ? prop.Name : attr.Key;
result.Append($"{propName}=");
if (attr?.ValueWithinBrackets ?? false)
result.Append("(");
var val = prop.GetValue(this);
var spawnCollection = val as ISpawnIniValuesCollection;
if (spawnCollection != null)
{
var iniVals = spawnCollection.ToIniValues(containerType);
var delimiter2 = "";
foreach (var iniVal in iniVals)
{
result.Append(delimiter2);
if (attr?.ListValueWithinBrackets ?? false)
result.Append($"({iniVal})");
else
result.Append(iniVal);
delimiter2 = DELIMITER.ToString();
}
}
else
{
var collection = val as IIniValuesCollection;
if (collection != null)
{
var iniVals = collection.ToIniValues();
var delimiter2 = "";
foreach (var iniVal in iniVals)
{
result.Append(delimiter2);
if (attr?.ListValueWithinBrackets ?? false)
result.Append($"({iniVal})");
else
result.Append(iniVal);
delimiter2 = DELIMITER.ToString();
}
}
else
{
var propValue = StringUtils.GetPropertyValue(val, prop);
result.Append(propValue);
}
}
if (attr?.ValueWithinBrackets ?? false)
result.Append(")");
delimiter = DELIMITER.ToString();
}
result.Append(")");
return result.ToString();
}
public override string ToString()
{
return $"{NPCSpawnEntriesContainerClassString}; NPCSpawnEntries={NPCSpawnEntries.Count}; NPCSpawnLimits={NPCSpawnLimits.Count}";
}
public bool IsValid => !string.IsNullOrWhiteSpace(NPCSpawnEntriesContainerClassString) && NPCSpawnEntries.Count == NPCSpawnLimits.Count;
}
[DataContract]
public class NPCSpawnList<T> : AggregateIniValueList<T>, ISpawnIniValuesCollection
where T : AggregateIniValue, new()
{
public NPCSpawnList(string aggregateValueName)
: base(aggregateValueName, null)
{
}
public override IEnumerable<string> ToIniValues()
{
throw new NotImplementedException();
}
public IEnumerable<string> ToIniValues(NPCSpawnContainerType containerType)
{
if (string.IsNullOrWhiteSpace(IniCollectionKey))
return this.Where(d => d.ShouldSave()).Cast<ISpawnIniValue>().Select(d => d.ToIniValue(containerType));
return this.Where(d => d.ShouldSave()).Cast<ISpawnIniValue>().Select(d => $"{this.IniCollectionKey}={d.ToIniValue(containerType)}");
}
}
[DataContract]
public class NPCSpawnEntry : AggregateIniValue, ISpawnIniValue
{
public static readonly DependencyProperty AnEntryNameProperty = DependencyProperty.Register(nameof(AnEntryName), typeof(string), typeof(NPCSpawnEntry), new PropertyMetadata(string.Empty));
[DataMember]
[AggregateIniValueEntry]
[NPCSpawn(new[] { NPCSpawnContainerType.Add, NPCSpawnContainerType.Override })]
public string AnEntryName
{
get { return (string)GetValue(AnEntryNameProperty); }
set { SetValue(AnEntryNameProperty, value); }
}
public static readonly DependencyProperty EntryWeightProperty = DependencyProperty.Register(nameof(EntryWeight), typeof(float), typeof(NPCSpawnEntry), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
[NPCSpawn(new[] { NPCSpawnContainerType.Add, NPCSpawnContainerType.Override })]
public float EntryWeight
{
get { return (float)GetValue(EntryWeightProperty); }
set { SetValue(EntryWeightProperty, value); }
}
public static readonly DependencyProperty NPCsToSpawnStringsProperty = DependencyProperty.Register(nameof(NPCsToSpawnStrings), typeof(string), typeof(NPCSpawnEntry), new PropertyMetadata(string.Empty));
[DataMember]
[AggregateIniValueEntry(ValueWithinBrackets = true)]
[NPCSpawn(new[] { NPCSpawnContainerType.Add, NPCSpawnContainerType.Subtract, NPCSpawnContainerType.Override })]
public string NPCsToSpawnStrings
{
get { return (string)GetValue(NPCsToSpawnStringsProperty); }
set { SetValue(NPCsToSpawnStringsProperty, value); }
}
public override string GetSortKey()
{
return null;
}
public override bool IsEquivalent(AggregateIniValue other)
{
return false;
}
public override void InitializeFromINIValue(string value)
{
base.FromComplexINIValue(value);
}
public override string ToINIValue()
{
throw new NotImplementedException();
}
public string ToIniValue(NPCSpawnContainerType containerType)
{
GetPropertyInfos();
if (this.Properties.Count == 0)
return string.Empty;
var result = new StringBuilder();
var delimiter = "";
foreach (var prop in this.Properties)
{
var attrSpawn = prop.GetCustomAttributes(typeof(NPCSpawnAttribute), false).OfType<NPCSpawnAttribute>().FirstOrDefault();
if (!attrSpawn?.ContainerTypes?.Contains(containerType) ?? false)
continue;
result.Append(delimiter);
var attr = prop.GetCustomAttributes(typeof(AggregateIniValueEntryAttribute), false).OfType<AggregateIniValueEntryAttribute>().FirstOrDefault();
var propName = string.IsNullOrWhiteSpace(attr?.Key) ? prop.Name : attr.Key;
result.Append($"{propName}=");
if (attr?.ValueWithinBrackets ?? false)
result.Append("(");
var val = prop.GetValue(this);
var spawnCollection = val as ISpawnIniValuesCollection;
if (spawnCollection != null)
{
var iniVals = spawnCollection.ToIniValues(containerType);
var delimiter2 = "";
foreach (var iniVal in iniVals)
{
result.Append(delimiter2);
if (attr?.ListValueWithinBrackets ?? false)
result.Append($"({iniVal})");
else
result.Append(iniVal);
delimiter2 = DELIMITER.ToString();
}
}
else
{
var collection = val as IIniValuesCollection;
if (collection != null)
{
var iniVals = collection.ToIniValues();
var delimiter2 = "";
foreach (var iniVal in iniVals)
{
result.Append(delimiter2);
if (attr?.ListValueWithinBrackets ?? false)
result.Append($"({iniVal})");
else
result.Append(iniVal);
delimiter2 = DELIMITER.ToString();
}
}
else
{
var propValue = StringUtils.GetPropertyValue(val, prop);
result.Append(propValue);
}
}
if (attr?.ValueWithinBrackets ?? false)
result.Append(")");
delimiter = DELIMITER.ToString();
}
return result.ToString();
}
public override string ToString()
{
return $"AnEntryName={AnEntryName}; EntryWeight={EntryWeight}; NPCsToSpawnStrings={NPCsToSpawnStrings}";
}
public bool IsValid => !string.IsNullOrWhiteSpace(NPCsToSpawnStrings);
}
[DataContract]
public class NPCSpawnLimit : AggregateIniValue, ISpawnIniValue
{
public static readonly DependencyProperty NPCClassStringProperty = DependencyProperty.Register(nameof(NPCClassString), typeof(string), typeof(NPCSpawnLimit), new PropertyMetadata(string.Empty));
[DataMember]
[AggregateIniValueEntry]
[NPCSpawn(new[] { NPCSpawnContainerType.Add, NPCSpawnContainerType.Subtract, NPCSpawnContainerType.Override })]
public string NPCClassString
{
get { return (string)GetValue(NPCClassStringProperty); }
set { SetValue(NPCClassStringProperty, value); }
}
public static readonly DependencyProperty MaxPercentageOfDesiredNumToAllowProperty = DependencyProperty.Register(nameof(MaxPercentageOfDesiredNumToAllow), typeof(float), typeof(NPCSpawnLimit), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
[NPCSpawn(new[] { NPCSpawnContainerType.Add, NPCSpawnContainerType.Override })]
public float MaxPercentageOfDesiredNumToAllow
{
get { return (float)GetValue(MaxPercentageOfDesiredNumToAllowProperty); }
set { SetValue(MaxPercentageOfDesiredNumToAllowProperty, value); }
}
public override string GetSortKey()
{
return null;
}
public override bool IsEquivalent(AggregateIniValue other)
{
return false;
}
public override void InitializeFromINIValue(string value)
{
base.FromComplexINIValue(value);
}
public override string ToINIValue()
{
throw new NotImplementedException();
}
public string ToIniValue(NPCSpawnContainerType containerType)
{
GetPropertyInfos();
if (this.Properties.Count == 0)
return string.Empty;
var result = new StringBuilder();
var delimiter = "";
foreach (var prop in this.Properties)
{
var attrSpawn = prop.GetCustomAttributes(typeof(NPCSpawnAttribute), false).OfType<NPCSpawnAttribute>().FirstOrDefault();
if (!attrSpawn?.ContainerTypes?.Contains(containerType) ?? false)
continue;
result.Append(delimiter);
var attr = prop.GetCustomAttributes(typeof(AggregateIniValueEntryAttribute), false).OfType<AggregateIniValueEntryAttribute>().FirstOrDefault();
var propName = string.IsNullOrWhiteSpace(attr?.Key) ? prop.Name : attr.Key;
result.Append($"{propName}=");
if (attr?.ValueWithinBrackets ?? false)
result.Append("(");
var val = prop.GetValue(this);
var spawnCollection = val as ISpawnIniValuesCollection;
if (spawnCollection != null)
{
var iniVals = spawnCollection.ToIniValues(containerType);
var delimiter2 = "";
foreach (var iniVal in iniVals)
{
result.Append(delimiter2);
if (attr?.ListValueWithinBrackets ?? false)
result.Append($"({iniVal})");
else
result.Append(iniVal);
delimiter2 = DELIMITER.ToString();
}
}
else
{
var collection = val as IIniValuesCollection;
if (collection != null)
{
var iniVals = collection.ToIniValues();
var delimiter2 = "";
foreach (var iniVal in iniVals)
{
result.Append(delimiter2);
if (attr?.ListValueWithinBrackets ?? false)
result.Append($"({iniVal})");
else
result.Append(iniVal);
delimiter2 = DELIMITER.ToString();
}
}
else
{
var propValue = StringUtils.GetPropertyValue(val, prop);
result.Append(propValue);
}
}
if (attr?.ValueWithinBrackets ?? false)
result.Append(")");
delimiter = DELIMITER.ToString();
}
return result.ToString();
}
public override string ToString()
{
return $"NPCClassString={NPCClassString}; MaxPercentageOfDesiredNumToAllow={MaxPercentageOfDesiredNumToAllow}";
}
public bool IsValid => !string.IsNullOrWhiteSpace(NPCClassString);
}
}

View file

@ -0,0 +1,855 @@
using ServerManagerTool.Common.Attibutes;
using ServerManagerTool.Common.Model;
using ServerManagerTool.Common.Utils;
using System;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Windows;
namespace ServerManagerTool.Lib
{
[DataContract]
public class PGMTerrain : AggregateIniValue
{
private new const char DELIMITER = ';';
public PGMTerrain()
{
SnowBiomeLocation = new PGMTerrainXY(0.2f, 0.2f);
RedWoodForestBiomeLocation = new PGMTerrainXY(0.5f, 0.5f);
NorthRegion1Start = new PGMTerrainXY(0.25f, 0.0f);
NorthRegion1End = new PGMTerrainXY(0.416f, 0.5f);
NorthRegion2Start = new PGMTerrainXY(0.416f, 0.0f);
NorthRegion2End = new PGMTerrainXY(0.582f, 0.5f);
NorthRegion3Start = new PGMTerrainXY(0.582f, 0.0f);
NorthRegion3End = new PGMTerrainXY(0.75f, 0.0f);
SouthRegion1Start = new PGMTerrainXY(0.25f, 0.5f);
SouthRegion1End = new PGMTerrainXY(0.416f, 1.0f);
SouthRegion2Start = new PGMTerrainXY(0.416f, 0.5f);
SouthRegion2End = new PGMTerrainXY(0.582f, 1.0f);
SouthRegion3Start = new PGMTerrainXY(0.582f, 0.5f);
SouthRegion3End = new PGMTerrainXY(0.75f, 1.0f);
EastRegion1Start = new PGMTerrainXY(0.75f, 0.0f);
EastRegion1End = new PGMTerrainXY(1.0f, 0.333f);
EastRegion2Start = new PGMTerrainXY(0.75f, 0.333f);
EastRegion2End = new PGMTerrainXY(1.0f, 0.666f);
EastRegion3Start = new PGMTerrainXY(0.75f, 0.666f);
EastRegion3End = new PGMTerrainXY(1.0f, 1.0f);
WestRegion1Start = new PGMTerrainXY(0.0f, 0.0f);
WestRegion1End = new PGMTerrainXY(0.25f, 0.333f);
WestRegion2Start = new PGMTerrainXY(0.0f, 0.333f);
WestRegion2End = new PGMTerrainXY(0.25f, 0.666f);
WestRegion3Start = new PGMTerrainXY(0.0f, 0.666f);
WestRegion3End = new PGMTerrainXY(0.25f, 1.0f);
TerrainScaleMultiplier = new PGMTerrainXYZ(1.0f, 1.0f, 1.0f);
}
public static readonly DependencyProperty MapSeedProperty = DependencyProperty.Register(nameof(MapSeed), typeof(int), typeof(PGMTerrain), new PropertyMetadata(999));
[DataMember]
[AggregateIniValueEntry]
public int MapSeed
{
get { return (int)GetValue(MapSeedProperty); }
set { SetValue(MapSeedProperty, value); }
}
public static readonly DependencyProperty LandscapeRadiusProperty = DependencyProperty.Register(nameof(LandscapeRadius), typeof(float), typeof(PGMTerrain), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float LandscapeRadius
{
get { return (float)GetValue(LandscapeRadiusProperty); }
set { SetValue(LandscapeRadiusProperty, value); }
}
public static readonly DependencyProperty WaterFrequencyProperty = DependencyProperty.Register(nameof(WaterFrequency), typeof(float), typeof(PGMTerrain), new PropertyMetadata(5.0f));
[DataMember]
[AggregateIniValueEntry(Key = "Water Frequency")]
public float WaterFrequency
{
get { return (float)GetValue(WaterFrequencyProperty); }
set { SetValue(WaterFrequencyProperty, value); }
}
public static readonly DependencyProperty MountainsFrequencyProperty = DependencyProperty.Register(nameof(MountainsFrequency), typeof(float), typeof(PGMTerrain), new PropertyMetadata(12.0f));
[DataMember]
[AggregateIniValueEntry(Key = "Mountains Frequency")]
public float MountainsFrequency
{
get { return (float)GetValue(MountainsFrequencyProperty); }
set { SetValue(MountainsFrequencyProperty, value); }
}
public static readonly DependencyProperty MountainsSlopeProperty = DependencyProperty.Register(nameof(MountainsSlope), typeof(float), typeof(PGMTerrain), new PropertyMetadata(1.8f));
[DataMember]
[AggregateIniValueEntry(Key = "Mountains Slope")]
public float MountainsSlope
{
get { return (float)GetValue(MountainsSlopeProperty); }
set { SetValue(MountainsSlopeProperty, value); }
}
public static readonly DependencyProperty MountainsHeightProperty = DependencyProperty.Register(nameof(MountainsHeight), typeof(float), typeof(PGMTerrain), new PropertyMetadata(1.25f));
[DataMember]
[AggregateIniValueEntry]
public float MountainsHeight
{
get { return (float)GetValue(MountainsHeightProperty); }
set { SetValue(MountainsHeightProperty, value); }
}
public static readonly DependencyProperty TurbulencePowerProperty = DependencyProperty.Register(nameof(TurbulencePower), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.0125f));
[DataMember]
[AggregateIniValueEntry(Key = "Turbulence Power")]
public float TurbulencePower
{
get { return (float)GetValue(TurbulencePowerProperty); }
set { SetValue(TurbulencePowerProperty, value); }
}
public static readonly DependencyProperty ShoreSlopeProperty = DependencyProperty.Register(nameof(ShoreSlope), typeof(float), typeof(PGMTerrain), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry(Key = "Shore Slope")]
public float ShoreSlope
{
get { return (float)GetValue(ShoreSlopeProperty); }
set { SetValue(ShoreSlopeProperty, value); }
}
public static readonly DependencyProperty WaterLevelProperty = DependencyProperty.Register(nameof(WaterLevel), typeof(float), typeof(PGMTerrain), new PropertyMetadata(-0.72f));
[DataMember]
[AggregateIniValueEntry]
public float WaterLevel
{
get { return (float)GetValue(WaterLevelProperty); }
set { SetValue(WaterLevelProperty, value); }
}
public static readonly DependencyProperty ShoreLineEndProperty = DependencyProperty.Register(nameof(ShoreLineEnd), typeof(float), typeof(PGMTerrain), new PropertyMetadata(-0.715f));
[DataMember]
[AggregateIniValueEntry]
public float ShoreLineEnd
{
get { return (float)GetValue(ShoreLineEndProperty); }
set { SetValue(ShoreLineEndProperty, value); }
}
public static readonly DependencyProperty GrassDensityProperty = DependencyProperty.Register(nameof(GrassDensity), typeof(float), typeof(PGMTerrain), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float GrassDensity
{
get { return (float)GetValue(GrassDensityProperty); }
set { SetValue(GrassDensityProperty, value); }
}
public static readonly DependencyProperty JungleGrassDensityProperty = DependencyProperty.Register(nameof(JungleGrassDensity), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.02f));
[DataMember]
[AggregateIniValueEntry]
public float JungleGrassDensity
{
get { return (float)GetValue(JungleGrassDensityProperty); }
set { SetValue(JungleGrassDensityProperty, value); }
}
public static readonly DependencyProperty OceanFloorLevelProperty = DependencyProperty.Register(nameof(OceanFloorLevel), typeof(float), typeof(PGMTerrain), new PropertyMetadata(-1.0f));
[DataMember]
[AggregateIniValueEntry]
public float OceanFloorLevel
{
get { return (float)GetValue(OceanFloorLevelProperty); }
set { SetValue(OceanFloorLevelProperty, value); }
}
public static readonly DependencyProperty SnowBiomeSizeProperty = DependencyProperty.Register(nameof(SnowBiomeSize), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.3f));
[DataMember]
[AggregateIniValueEntry]
public float SnowBiomeSize
{
get { return (float)GetValue(SnowBiomeSizeProperty); }
set { SetValue(SnowBiomeSizeProperty, value); }
}
public static readonly DependencyProperty RedWoodBiomeSizeProperty = DependencyProperty.Register(nameof(RedWoodBiomeSize), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.075f));
[DataMember]
[AggregateIniValueEntry(Key = "RWBiomeSize")]
public float RedWoodBiomeSize
{
get { return (float)GetValue(RedWoodBiomeSizeProperty); }
set { SetValue(RedWoodBiomeSizeProperty, value); }
}
public static readonly DependencyProperty MountainBiomeStartProperty = DependencyProperty.Register(nameof(MountainBiomeStart), typeof(float), typeof(PGMTerrain), new PropertyMetadata(-0.55f));
[DataMember]
[AggregateIniValueEntry]
public float MountainBiomeStart
{
get { return (float)GetValue(MountainBiomeStartProperty); }
set { SetValue(MountainBiomeStartProperty, value); }
}
public static readonly DependencyProperty MountainsTreeDensityProperty = DependencyProperty.Register(nameof(MountainsTreeDensity), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.01f));
[DataMember]
[AggregateIniValueEntry]
public float MountainsTreeDensity
{
get { return (float)GetValue(MountainsTreeDensityProperty); }
set { SetValue(MountainsTreeDensityProperty, value); }
}
public static readonly DependencyProperty JungleBiomeStartProperty = DependencyProperty.Register(nameof(JungleBiomeStart), typeof(float), typeof(PGMTerrain), new PropertyMetadata(-0.65f));
[DataMember]
[AggregateIniValueEntry]
public float JungleBiomeStart
{
get { return (float)GetValue(JungleBiomeStartProperty); }
set { SetValue(JungleBiomeStartProperty, value); }
}
public static readonly DependencyProperty IslandBorderCurveExponentProperty = DependencyProperty.Register(nameof(IslandBorderCurveExponent), typeof(float), typeof(PGMTerrain), new PropertyMetadata(4.0f));
[DataMember]
[AggregateIniValueEntry(Key = "IslandBorderCurveExp")]
public float IslandBorderCurveExponent
{
get { return (float)GetValue(IslandBorderCurveExponentProperty); }
set { SetValue(IslandBorderCurveExponentProperty, value); }
}
public static readonly DependencyProperty MaxSpawnPointHeightProperty = DependencyProperty.Register(nameof(MaxSpawnPointHeight), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.1f));
[DataMember]
[AggregateIniValueEntry(Key = "MaxSawnPointHeight")]
public float MaxSpawnPointHeight
{
get { return (float)GetValue(MaxSpawnPointHeightProperty); }
set { SetValue(MaxSpawnPointHeightProperty, value); }
}
public static readonly DependencyProperty MountainGrassDensityProperty = DependencyProperty.Register(nameof(MountainGrassDensity), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.05f));
[DataMember]
[AggregateIniValueEntry]
public float MountainGrassDensity
{
get { return (float)GetValue(MountainGrassDensityProperty); }
set { SetValue(MountainGrassDensityProperty, value); }
}
public static readonly DependencyProperty SnowMountainGrassDensityProperty = DependencyProperty.Register(nameof(SnowMountainGrassDensity), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.15f));
[DataMember]
[AggregateIniValueEntry]
public float SnowMountainGrassDensity
{
get { return (float)GetValue(SnowMountainGrassDensityProperty); }
set { SetValue(SnowMountainGrassDensityProperty, value); }
}
public static readonly DependencyProperty SnowGrassDensityProperty = DependencyProperty.Register(nameof(SnowGrassDensity), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.25f));
[DataMember]
[AggregateIniValueEntry]
public float SnowGrassDensity
{
get { return (float)GetValue(SnowGrassDensityProperty); }
set { SetValue(SnowGrassDensityProperty, value); }
}
public static readonly DependencyProperty UnderwaterObjectsDensityProperty = DependencyProperty.Register(nameof(UnderwaterObjectsDensity), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.5f));
[DataMember]
[AggregateIniValueEntry]
public float UnderwaterObjectsDensity
{
get { return (float)GetValue(UnderwaterObjectsDensityProperty); }
set { SetValue(UnderwaterObjectsDensityProperty, value); }
}
public static readonly DependencyProperty SnowMountainsTreeDensityProperty = DependencyProperty.Register(nameof(SnowMountainsTreeDensity), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.01f));
[DataMember]
[AggregateIniValueEntry]
public float SnowMountainsTreeDensity
{
get { return (float)GetValue(SnowMountainsTreeDensityProperty); }
set { SetValue(SnowMountainsTreeDensityProperty, value); }
}
public static readonly DependencyProperty TreeDensityProperty = DependencyProperty.Register(nameof(TreeDensity), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.003f));
[DataMember]
[AggregateIniValueEntry]
public float TreeDensity
{
get { return (float)GetValue(TreeDensityProperty); }
set { SetValue(TreeDensityProperty, value); }
}
public static readonly DependencyProperty JungleTreeDensityProperty = DependencyProperty.Register(nameof(JungleTreeDensity), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.66f));
[DataMember]
[AggregateIniValueEntry]
public float JungleTreeDensity
{
get { return (float)GetValue(JungleTreeDensityProperty); }
set { SetValue(JungleTreeDensityProperty, value); }
}
public static readonly DependencyProperty RedWoodTreeDensityProperty = DependencyProperty.Register(nameof(RedWoodTreeDensity), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.35f));
[DataMember]
[AggregateIniValueEntry]
public float RedWoodTreeDensity
{
get { return (float)GetValue(RedWoodTreeDensityProperty); }
set { SetValue(RedWoodTreeDensityProperty, value); }
}
public static readonly DependencyProperty SnowTreeDensityProperty = DependencyProperty.Register(nameof(SnowTreeDensity), typeof(float), typeof(PGMTerrain), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float SnowTreeDensity
{
get { return (float)GetValue(SnowTreeDensityProperty); }
set { SetValue(SnowTreeDensityProperty, value); }
}
public static readonly DependencyProperty RedwoodGrassDensityProperty = DependencyProperty.Register(nameof(RedwoodGrassDensity), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.1f));
[DataMember]
[AggregateIniValueEntry]
public float RedwoodGrassDensity
{
get { return (float)GetValue(RedwoodGrassDensityProperty); }
set { SetValue(RedwoodGrassDensityProperty, value); }
}
public static readonly DependencyProperty ShoreTreeDensityProperty = DependencyProperty.Register(nameof(ShoreTreeDensity), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.05f));
[DataMember]
[AggregateIniValueEntry]
public float ShoreTreeDensity
{
get { return (float)GetValue(ShoreTreeDensityProperty); }
set { SetValue(ShoreTreeDensityProperty, value); }
}
public static readonly DependencyProperty SnowShoreTreeDensityProperty = DependencyProperty.Register(nameof(SnowShoreTreeDensity), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.025f));
[DataMember]
[AggregateIniValueEntry]
public float SnowShoreTreeDensity
{
get { return (float)GetValue(SnowShoreTreeDensityProperty); }
set { SetValue(SnowShoreTreeDensityProperty, value); }
}
public static readonly DependencyProperty DeepWaterBiomesDepthProperty = DependencyProperty.Register(nameof(DeepWaterBiomesDepth), typeof(float), typeof(PGMTerrain), new PropertyMetadata(-0.24f));
[DataMember]
[AggregateIniValueEntry]
public float DeepWaterBiomesDepth
{
get { return (float)GetValue(DeepWaterBiomesDepthProperty); }
set { SetValue(DeepWaterBiomesDepthProperty, value); }
}
public static readonly DependencyProperty InlandWaterObjectsDensityProperty = DependencyProperty.Register(nameof(InlandWaterObjectsDensity), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.5f));
[DataMember]
[AggregateIniValueEntry]
public float InlandWaterObjectsDensity
{
get { return (float)GetValue(InlandWaterObjectsDensityProperty); }
set { SetValue(InlandWaterObjectsDensityProperty, value); }
}
public static readonly DependencyProperty ShorelineStartOffsetProperty = DependencyProperty.Register(nameof(ShorelineStartOffset), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.01f));
[DataMember]
[AggregateIniValueEntry]
public float ShorelineStartOffset
{
get { return (float)GetValue(ShorelineStartOffsetProperty); }
set { SetValue(ShorelineStartOffsetProperty, value); }
}
public static readonly DependencyProperty ShorelineThicknessProperty = DependencyProperty.Register(nameof(ShorelineThickness), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.0015f));
[DataMember]
[AggregateIniValueEntry]
public float ShorelineThickness
{
get { return (float)GetValue(ShorelineThicknessProperty); }
set { SetValue(ShorelineThicknessProperty, value); }
}
public static readonly DependencyProperty TreesGroundSlopeAccuracyProperty = DependencyProperty.Register(nameof(TreesGroundSlopeAccuracy), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.5f));
[DataMember]
[AggregateIniValueEntry]
public float TreesGroundSlopeAccuracy
{
get { return (float)GetValue(TreesGroundSlopeAccuracyProperty); }
set { SetValue(TreesGroundSlopeAccuracyProperty, value); }
}
public static readonly DependencyProperty ErosionStepsProperty = DependencyProperty.Register(nameof(ErosionSteps), typeof(int), typeof(PGMTerrain), new PropertyMetadata(4));
[DataMember]
[AggregateIniValueEntry]
public int ErosionSteps
{
get { return (int)GetValue(ErosionStepsProperty); }
set { SetValue(ErosionStepsProperty, value); }
}
public static readonly DependencyProperty ErosionStrengthProperty = DependencyProperty.Register(nameof(ErosionStrength), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.75f));
[DataMember]
[AggregateIniValueEntry]
public float ErosionStrength
{
get { return (float)GetValue(ErosionStrengthProperty); }
set { SetValue(ErosionStrengthProperty, value); }
}
public static readonly DependencyProperty DepositionStrengthProperty = DependencyProperty.Register(nameof(DepositionStrength), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.5f));
[DataMember]
[AggregateIniValueEntry]
public float DepositionStrength
{
get { return (float)GetValue(DepositionStrengthProperty); }
set { SetValue(DepositionStrengthProperty, value); }
}
public static readonly DependencyProperty MountainGeneralTreesPercentProperty = DependencyProperty.Register(nameof(MountainGeneralTreesPercent), typeof(float), typeof(PGMTerrain), new PropertyMetadata(0.1f));
[DataMember]
[AggregateIniValueEntry]
public float MountainGeneralTreesPercent
{
get { return (float)GetValue(MountainGeneralTreesPercentProperty); }
set { SetValue(MountainGeneralTreesPercentProperty, value); }
}
public static readonly DependencyProperty SnowBiomeLocationProperty = DependencyProperty.Register(nameof(SnowBiomeLocation), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY SnowBiomeLocation
{
get { return (PGMTerrainXY)GetValue(SnowBiomeLocationProperty); }
set { SetValue(SnowBiomeLocationProperty, value); }
}
public static readonly DependencyProperty RedWoodForestBiomeLocationProperty = DependencyProperty.Register(nameof(RedWoodForestBiomeLocation), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry(Key = "RWForestBiomeLocation")]
public PGMTerrainXY RedWoodForestBiomeLocation
{
get { return (PGMTerrainXY)GetValue(RedWoodForestBiomeLocationProperty); }
set { SetValue(RedWoodForestBiomeLocationProperty, value); }
}
public static readonly DependencyProperty NorthRegion1StartProperty = DependencyProperty.Register(nameof(NorthRegion1Start), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY NorthRegion1Start
{
get { return (PGMTerrainXY)GetValue(NorthRegion1StartProperty); }
set { SetValue(NorthRegion1StartProperty, value); }
}
public static readonly DependencyProperty NorthRegion1EndProperty = DependencyProperty.Register(nameof(NorthRegion1End), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY NorthRegion1End
{
get { return (PGMTerrainXY)GetValue(NorthRegion1EndProperty); }
set { SetValue(NorthRegion1EndProperty, value); }
}
public static readonly DependencyProperty NorthRegion2StartProperty = DependencyProperty.Register(nameof(NorthRegion2Start), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY NorthRegion2Start
{
get { return (PGMTerrainXY)GetValue(NorthRegion2StartProperty); }
set { SetValue(NorthRegion2StartProperty, value); }
}
public static readonly DependencyProperty NorthRegion2EndProperty = DependencyProperty.Register(nameof(NorthRegion2End), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY NorthRegion2End
{
get { return (PGMTerrainXY)GetValue(NorthRegion2EndProperty); }
set { SetValue(NorthRegion2EndProperty, value); }
}
public static readonly DependencyProperty NorthRegion3StartProperty = DependencyProperty.Register(nameof(NorthRegion3Start), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY NorthRegion3Start
{
get { return (PGMTerrainXY)GetValue(NorthRegion3StartProperty); }
set { SetValue(NorthRegion3StartProperty, value); }
}
public static readonly DependencyProperty NorthRegion3EndProperty = DependencyProperty.Register(nameof(NorthRegion3End), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY NorthRegion3End
{
get { return (PGMTerrainXY)GetValue(NorthRegion3EndProperty); }
set { SetValue(NorthRegion3EndProperty, value); }
}
public static readonly DependencyProperty SouthRegion1StartProperty = DependencyProperty.Register(nameof(SouthRegion1Start), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY SouthRegion1Start
{
get { return (PGMTerrainXY)GetValue(SouthRegion1StartProperty); }
set { SetValue(SouthRegion1StartProperty, value); }
}
public static readonly DependencyProperty SouthRegion1EndProperty = DependencyProperty.Register(nameof(SouthRegion1End), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY SouthRegion1End
{
get { return (PGMTerrainXY)GetValue(SouthRegion1EndProperty); }
set { SetValue(SouthRegion1EndProperty, value); }
}
public static readonly DependencyProperty SouthRegion2StartProperty = DependencyProperty.Register(nameof(SouthRegion2Start), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY SouthRegion2Start
{
get { return (PGMTerrainXY)GetValue(SouthRegion2StartProperty); }
set { SetValue(SouthRegion2StartProperty, value); }
}
public static readonly DependencyProperty SouthRegion2EndProperty = DependencyProperty.Register(nameof(SouthRegion2End), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY SouthRegion2End
{
get { return (PGMTerrainXY)GetValue(SouthRegion2EndProperty); }
set { SetValue(SouthRegion2EndProperty, value); }
}
public static readonly DependencyProperty SouthRegion3StartProperty = DependencyProperty.Register(nameof(SouthRegion3Start), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY SouthRegion3Start
{
get { return (PGMTerrainXY)GetValue(SouthRegion3StartProperty); }
set { SetValue(SouthRegion3StartProperty, value); }
}
public static readonly DependencyProperty SouthRegion3EndProperty = DependencyProperty.Register(nameof(SouthRegion3End), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY SouthRegion3End
{
get { return (PGMTerrainXY)GetValue(SouthRegion3EndProperty); }
set { SetValue(SouthRegion3EndProperty, value); }
}
public static readonly DependencyProperty EastRegion1StartProperty = DependencyProperty.Register(nameof(EastRegion1Start), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY EastRegion1Start
{
get { return (PGMTerrainXY)GetValue(EastRegion1StartProperty); }
set { SetValue(EastRegion1StartProperty, value); }
}
public static readonly DependencyProperty EastRegion1EndProperty = DependencyProperty.Register(nameof(EastRegion1End), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY EastRegion1End
{
get { return (PGMTerrainXY)GetValue(EastRegion1EndProperty); }
set { SetValue(EastRegion1EndProperty, value); }
}
public static readonly DependencyProperty EastRegion2StartProperty = DependencyProperty.Register(nameof(EastRegion2Start), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY EastRegion2Start
{
get { return (PGMTerrainXY)GetValue(EastRegion2StartProperty); }
set { SetValue(EastRegion2StartProperty, value); }
}
public static readonly DependencyProperty EastRegion2EndProperty = DependencyProperty.Register(nameof(EastRegion2End), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY EastRegion2End
{
get { return (PGMTerrainXY)GetValue(EastRegion2EndProperty); }
set { SetValue(EastRegion2EndProperty, value); }
}
public static readonly DependencyProperty EastRegion3StartProperty = DependencyProperty.Register(nameof(EastRegion3Start), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY EastRegion3Start
{
get { return (PGMTerrainXY)GetValue(EastRegion3StartProperty); }
set { SetValue(EastRegion3StartProperty, value); }
}
public static readonly DependencyProperty EastRegion3EndProperty = DependencyProperty.Register(nameof(EastRegion3End), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY EastRegion3End
{
get { return (PGMTerrainXY)GetValue(EastRegion3EndProperty); }
set { SetValue(EastRegion3EndProperty, value); }
}
public static readonly DependencyProperty WestRegion1StartProperty = DependencyProperty.Register(nameof(WestRegion1Start), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY WestRegion1Start
{
get { return (PGMTerrainXY)GetValue(WestRegion1StartProperty); }
set { SetValue(WestRegion1StartProperty, value); }
}
public static readonly DependencyProperty WestRegion1EndProperty = DependencyProperty.Register(nameof(WestRegion1End), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY WestRegion1End
{
get { return (PGMTerrainXY)GetValue(WestRegion1EndProperty); }
set { SetValue(WestRegion1EndProperty, value); }
}
public static readonly DependencyProperty WestRegion2StartProperty = DependencyProperty.Register(nameof(WestRegion2Start), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY WestRegion2Start
{
get { return (PGMTerrainXY)GetValue(WestRegion2StartProperty); }
set { SetValue(WestRegion2StartProperty, value); }
}
public static readonly DependencyProperty WestRegion2EndProperty = DependencyProperty.Register(nameof(WestRegion2End), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY WestRegion2End
{
get { return (PGMTerrainXY)GetValue(WestRegion2EndProperty); }
set { SetValue(WestRegion2EndProperty, value); }
}
public static readonly DependencyProperty WestRegion3StartProperty = DependencyProperty.Register(nameof(WestRegion3Start), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY WestRegion3Start
{
get { return (PGMTerrainXY)GetValue(WestRegion3StartProperty); }
set { SetValue(WestRegion3StartProperty, value); }
}
public static readonly DependencyProperty WestRegion3EndProperty = DependencyProperty.Register(nameof(WestRegion3End), typeof(PGMTerrainXY), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXY WestRegion3End
{
get { return (PGMTerrainXY)GetValue(WestRegion3EndProperty); }
set { SetValue(WestRegion3EndProperty, value); }
}
public static readonly DependencyProperty TerrainScaleMultiplierProperty = DependencyProperty.Register(nameof(TerrainScaleMultiplier), typeof(PGMTerrainXYZ), typeof(PGMTerrain), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry]
public PGMTerrainXYZ TerrainScaleMultiplier
{
get { return (PGMTerrainXYZ)GetValue(TerrainScaleMultiplierProperty); }
set { SetValue(TerrainScaleMultiplierProperty, value); }
}
public override string GetSortKey()
{
return null;
}
public override bool IsEquivalent(AggregateIniValue other)
{
return false;
}
public override void InitializeFromINIValue(string value)
{
if (string.IsNullOrWhiteSpace(value))
return;
GetPropertyInfos();
if (this.Properties.Count == 0)
return;
value = value.Trim('(', ')', ' ');
var pairs = value.Split(DELIMITER);
foreach (var pair in pairs)
{
var kvPair = pair.Split(new[] { '=' }, 2);
if (kvPair.Length != 2)
continue;
var key = kvPair[0].Trim();
var val = kvPair[1].Trim();
var propInfo = this.Properties.FirstOrDefault(p => string.Equals(p.Name, key, StringComparison.OrdinalIgnoreCase));
if (propInfo != null)
StringUtils.SetPropertyValue(val, this, propInfo);
else
{
propInfo = this.Properties.FirstOrDefault(f => f.GetCustomAttributes(typeof(AggregateIniValueEntryAttribute), false).OfType<AggregateIniValueEntryAttribute>().Any(a => string.Equals(a.Key, key, StringComparison.OrdinalIgnoreCase)));
if (propInfo != null)
StringUtils.SetPropertyValue(val, this, propInfo);
}
}
}
public override string ToINIValue()
{
GetPropertyInfos();
if (this.Properties.Count == 0)
return string.Empty;
var result = new StringBuilder();
var delimiter = "";
foreach (var prop in this.Properties)
{
result.Append(delimiter);
var attr = prop.GetCustomAttributes(typeof(AggregateIniValueEntryAttribute), false).OfType<AggregateIniValueEntryAttribute>().FirstOrDefault();
var propName = string.IsNullOrWhiteSpace(attr?.Key) ? prop.Name : attr.Key;
var val = prop.GetValue(this);
var propValue = StringUtils.GetPropertyValue(val, prop);
result.Append($"{propName}={propValue}");
delimiter = DELIMITER.ToString();
}
return result.ToString();
}
}
[DataContract]
public class PGMTerrainXY : AggregateIniValue
{
public PGMTerrainXY()
{
}
public PGMTerrainXY(float x, float y)
{
X = x;
Y = y;
}
public static readonly DependencyProperty XProperty = DependencyProperty.Register(nameof(X), typeof(float), typeof(PGMTerrainXY), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float X
{
get { return (float)GetValue(XProperty); }
set { SetValue(XProperty, value); }
}
public static readonly DependencyProperty YProperty = DependencyProperty.Register(nameof(Y), typeof(float), typeof(PGMTerrainXY), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float Y
{
get { return (float)GetValue(YProperty); }
set { SetValue(YProperty, value); }
}
public override string GetSortKey()
{
return null;
}
public override bool IsEquivalent(AggregateIniValue other)
{
return false;
}
public override void InitializeFromINIValue(string value)
{
if (string.IsNullOrWhiteSpace(value))
return;
GetPropertyInfos();
if (this.Properties.Count == 0)
return;
value = value.Trim('(', ')', ' ');
var pairs = value.Split(DELIMITER);
foreach (var pair in pairs)
{
var kvPair = pair.Split(new[] { '=' }, 2);
if (kvPair.Length != 2)
continue;
var key = kvPair[0].Trim();
var val = kvPair[1].Trim();
var propInfo = this.Properties.FirstOrDefault(p => string.Equals(p.Name, key, StringComparison.OrdinalIgnoreCase));
if (propInfo != null)
StringUtils.SetPropertyValue(val, this, propInfo);
else
{
propInfo = this.Properties.FirstOrDefault(f => f.GetCustomAttributes(typeof(AggregateIniValueEntryAttribute), false).OfType<AggregateIniValueEntryAttribute>().Any(a => string.Equals(a.Key, key, StringComparison.OrdinalIgnoreCase)));
if (propInfo != null)
StringUtils.SetPropertyValue(val, this, propInfo);
}
}
}
public override string ToINIValue()
{
GetPropertyInfos();
if (this.Properties.Count == 0)
return string.Empty;
var result = new StringBuilder();
result.Append("(");
var delimiter = "";
foreach (var prop in this.Properties.OrderBy(p => p.Name))
{
result.Append(delimiter);
var attr = prop.GetCustomAttributes(typeof(AggregateIniValueEntryAttribute), false).OfType<AggregateIniValueEntryAttribute>().FirstOrDefault();
var propName = string.IsNullOrWhiteSpace(attr?.Key) ? prop.Name : attr.Key;
var val = prop.GetValue(this);
var propValue = StringUtils.GetPropertyValue(val, prop);
result.Append($"{propName}={propValue}");
delimiter = DELIMITER.ToString();
}
result.Append(")");
return result.ToString();
}
}
[DataContract]
public class PGMTerrainXYZ : PGMTerrainXY
{
public PGMTerrainXYZ()
{
}
public PGMTerrainXYZ(float x, float y, float z)
: base(x, y)
{
Z = z;
}
public static readonly DependencyProperty ZProperty = DependencyProperty.Register(nameof(Z), typeof(float), typeof(PGMTerrainXYZ), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float Z
{
get { return (float)GetValue(ZProperty); }
set { SetValue(ZProperty, value); }
}
}
}

View file

@ -0,0 +1,33 @@
using System.Windows;
namespace ServerManagerTool.Lib
{
public class PlayerListParameters : DependencyObject
{
public static readonly DependencyProperty ProfileNameProperty = DependencyProperty.Register(nameof(ProfileName), typeof(string), typeof(PlayerListParameters), new PropertyMetadata(string.Empty));
public string ProfileName
{
get { return (string)GetValue(ProfileNameProperty); }
set { SetValue(ProfileNameProperty, value); }
}
public string ProfileId { get; set; }
public string InstallDirectory { get; set; }
public string AltSaveDirectoryName { get; set; }
public bool PGM_Enabled { get; set; }
public string PGM_Name { get; set; }
public Server Server { get; set; }
public string ServerMap { get; set; }
public Rect WindowExtents { get; set; }
public string WindowTitle { get; set; }
}
}

View file

@ -0,0 +1,503 @@
using ServerManagerTool.Common.Model;
using ServerManagerTool.Utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using WPFSharp.Globalizer;
namespace ServerManagerTool.Lib.Model
{
public class ModDetailList : ObservableCollection<ModDetail>
{
public bool AnyUnknownModTypes
{
get
{
return this.Any(m => !m.IsValidModType);
}
}
public new void Add(ModDetail mod)
{
if (mod == null || this.Any(m => m.ModId.Equals(mod.ModId)))
return;
base.Add(mod);
SetPublishedFileIndex();
}
public void AddRange(ModDetail[] mods)
{
foreach (var mod in mods)
{
if (mod == null || this.Any(m => m.ModId.Equals(mod.ModId)))
continue;
base.Add(mod);
}
SetPublishedFileIndex();
}
public new void Insert(int index, ModDetail mod)
{
if (mod == null || this.Any(m => m.ModId.Equals(mod.ModId)))
return;
base.Insert(index, mod);
SetPublishedFileIndex();
}
public void Move(ModDetail mod, int newIndex)
{
if (mod == null)
return;
var index = base.IndexOf(mod);
if (index <= 0)
return;
base.Move(index, newIndex);
SetPublishedFileIndex();
}
public void MoveDown(ModDetail mod)
{
if (mod == null)
return;
var index = base.IndexOf(mod);
if (index >= base.Count - 1)
return;
base.Move(index, index + 1);
SetPublishedFileIndex();
}
public void MoveUp(ModDetail mod)
{
if (mod == null)
return;
var index = base.IndexOf(mod);
if (index <= 0)
return;
base.Move(index, index - 1);
SetPublishedFileIndex();
}
public void PopulateExtended(string modsRootFolder)
{
var results = new Dictionary<ModDetail, ModDetailExtended>();
foreach (var mod in this)
{
results.Add(mod, new ModDetailExtended(mod.ModId));
}
Parallel.ForEach(results, kvp => kvp.Value.PopulateExtended(modsRootFolder));
foreach (var kvp in results)
{
kvp.Key.PopulateExtended(kvp.Value);
}
}
public new bool Remove(ModDetail mod)
{
if (mod == null)
return false;
var removed = base.Remove(mod);
SetPublishedFileIndex();
return removed;
}
public void SetPublishedFileIndex()
{
foreach (var mod in this)
{
mod.Index = base.IndexOf(mod) + 1;
mod.IsFirst = false;
mod.IsLast = false;
}
if (this.Count == 0)
return;
this[0].IsFirst = true;
this[base.Count - 1].IsLast = true;
}
public bool GetModStrings(out string mapString, out string totalConversionString, out string modIdString)
{
mapString = null;
totalConversionString = null;
modIdString = string.Empty;
var delimiter = "";
foreach (var mod in this)
{
switch (mod.ModType)
{
case ModUtils.MODTYPE_MAP:
mapString = $"/Game/Mods/{mod.ModId}/{mod.MapName}";
break;
case ModUtils.MODTYPE_TOTCONV:
totalConversionString = mod.ModId;
break;
case ModUtils.MODTYPE_MAPEXT:
case ModUtils.MODTYPE_MOD:
default:
modIdString += $"{delimiter}{mod.ModId}";
delimiter = ",";
break;
}
}
return true;
}
public static ModDetailList GetModDetails(List<string> modIdList, string modsRootFolder, WorkshopFileList workshopFiles, PublishedFileDetailsResponse response)
{
var result = new ModDetailList();
if (modIdList != null)
{
foreach (var modId in modIdList)
{
var temp = workshopFiles?.FirstOrDefault(w => w.WorkshopId.Equals(modId));
result.Add(new ModDetail()
{
AppId = temp?.AppId ?? string.Empty,
ModId = modId,
TimeUpdated = -1,
Title = temp?.Title ?? "Mod name not available",
IsValid = false,
});
}
}
if (response?.publishedfiledetails != null)
{
foreach (var item in result)
{
var temp = response.publishedfiledetails.FirstOrDefault(w => w.publishedfileid.Equals(item.ModId));
if (temp != null)
{
item.AppId = temp?.creator_app_id ?? string.Empty;
item.ModId = temp?.publishedfileid ?? item.ModId;
item.TimeUpdated = temp?.time_updated ?? item.TimeUpdated;
item.Title = temp?.title ?? item.Title;
item.IsValid = temp?.creator_app_id != null;
}
}
}
result.SetPublishedFileIndex();
result.PopulateExtended(modsRootFolder);
return result;
}
public override string ToString()
{
return $"{nameof(ModDetailList)} - {Count}";
}
}
public class ModDetail : DependencyObject
{
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
public static readonly DependencyProperty AppIdProperty = DependencyProperty.Register(nameof(AppId), typeof(string), typeof(ModDetail), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty IndexProperty = DependencyProperty.Register(nameof(Index), typeof(int), typeof(ModDetail), new PropertyMetadata(0));
public static readonly DependencyProperty IsFirstProperty = DependencyProperty.Register(nameof(IsFirst), typeof(bool), typeof(ModDetail), new PropertyMetadata(false));
public static readonly DependencyProperty IsLastProperty = DependencyProperty.Register(nameof(IsLast), typeof(bool), typeof(ModDetail), new PropertyMetadata(false));
public static readonly DependencyProperty LastWriteTimeProperty = DependencyProperty.Register(nameof(LastWriteTime), typeof(DateTime), typeof(ModDetail), new PropertyMetadata(DateTime.MinValue));
public static readonly DependencyProperty LastTimeUpdatedProperty = DependencyProperty.Register(nameof(LastTimeUpdated), typeof(int), typeof(ModDetail), new PropertyMetadata(0));
public static readonly DependencyProperty ModIdProperty = DependencyProperty.Register(nameof(ModId), typeof(string), typeof(ModDetail), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty ModTypeProperty = DependencyProperty.Register(nameof(ModType), typeof(string), typeof(ModDetail), new PropertyMetadata(ModUtils.MODTYPE_UNKNOWN));
public static readonly DependencyProperty ModTypeStringProperty = DependencyProperty.Register(nameof(ModTypeString), typeof(string), typeof(ModDetail), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty ModUrlProperty = DependencyProperty.Register(nameof(ModUrl), typeof(string), typeof(ModDetail), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty TimeUpdatedProperty = DependencyProperty.Register(nameof(TimeUpdated), typeof(int), typeof(ModDetail), new PropertyMetadata(0));
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(ModDetail), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty IsValidProperty = DependencyProperty.Register(nameof(IsValid), typeof(bool), typeof(ModDetail), new PropertyMetadata(false));
public string AppId
{
get { return (string)GetValue(AppIdProperty); }
set { SetValue(AppIdProperty, value); }
}
public int Index
{
get { return (int)GetValue(IndexProperty); }
set { SetValue(IndexProperty, value); }
}
public bool IsFirst
{
get { return (bool)GetValue(IsFirstProperty); }
set { SetValue(IsFirstProperty, value); }
}
public bool IsLast
{
get { return (bool)GetValue(IsLastProperty); }
set { SetValue(IsLastProperty, value); }
}
public DateTime LastWriteTime
{
get { return (DateTime)GetValue(LastWriteTimeProperty); }
set { SetValue(LastWriteTimeProperty, value); }
}
public int LastTimeUpdated
{
get { return (int)GetValue(LastTimeUpdatedProperty); }
set { SetValue(LastTimeUpdatedProperty, value); }
}
public string ModId
{
get { return (string)GetValue(ModIdProperty); }
set { SetValue(ModIdProperty, value); }
}
public string ModType
{
get { return (string)GetValue(ModTypeProperty); }
set
{
SetValue(ModTypeProperty, value);
SetModTypeString();
}
}
public string ModTypeString
{
get { return (string)GetValue(ModTypeStringProperty); }
set { SetValue(ModTypeStringProperty, value); }
}
public int TimeUpdated
{
get { return (int)GetValue(TimeUpdatedProperty); }
set { SetValue(TimeUpdatedProperty, value); }
}
public string Title
{
get { return (string)GetValue(TitleProperty); }
set
{
SetValue(TitleProperty, value);
TitleFilterString = value?.ToLower();
}
}
public bool IsValid
{
get { return (bool)GetValue(IsValidProperty); }
set { SetValue(IsValidProperty, value); }
}
public bool IsOfficialMod => ModUtils.IsOfficialMod(ModId);
public bool IsValidModType => !string.IsNullOrWhiteSpace(ModType) && (ModType.Equals(ModUtils.MODTYPE_MAP) || ModType.Equals(ModUtils.MODTYPE_MAPEXT) || ModType.Equals(ModUtils.MODTYPE_MOD) || ModType.Equals(ModUtils.MODTYPE_TOTCONV));
public string LastWriteTimeString => LastWriteTime == DateTime.MinValue ? string.Empty : LastWriteTime.ToString();
public string LastWriteTimeSortString => LastWriteTime == DateTime.MinValue ? string.Empty : LastWriteTime.ToString("yyyyMMdd_HHmmss");
public string MapName { get; set; }
public string ModUrl => $"http://steamcommunity.com/sharedfiles/filedetails/?id={ModId}";
public string TimeUpdatedString => TimeUpdated <= 0 ? string.Empty : ModUtils.UnixTimeStampToDateTime(TimeUpdated).ToString();
public string TimeUpdatedSortString => TimeUpdated <= 0 ? string.Empty : ModUtils.UnixTimeStampToDateTime(TimeUpdated).ToString("yyyyMMdd_HHmmss");
public string TitleFilterString
{
get;
private set;
}
public bool UpToDate => !IsValid && TimeUpdated == -1 || LastTimeUpdated > 0 && LastTimeUpdated == TimeUpdated;
public long FolderSize { get; set; }
public string FolderSizeString
{
get
{
// GB
var divisor = Math.Pow(1024, 3);
if (FolderSize > divisor)
return $"{FolderSize / divisor:N2} GB";
// MB
divisor = Math.Pow(1024, 2);
if (FolderSize > divisor)
return $"{FolderSize / divisor:N2} MB";
// KB
divisor = Math.Pow(1024, 1);
if (FolderSize > divisor)
return $"{FolderSize / divisor:N2} KB";
return $"{FolderSize} B";
}
}
public void PopulateExtended(string modsRootFolder)
{
var modExtended = new ModDetailExtended(ModId);
modExtended.PopulateExtended(modsRootFolder);
PopulateExtended(modExtended);
}
public void PopulateExtended(ModDetailExtended extended)
{
LastTimeUpdated = extended.LastTimeUpdated;
LastWriteTime = extended.LastWriteTime;
MapName = extended.MapName;
ModType = extended.ModType;
FolderSize = extended.FolderSize;
}
public void SetModTypeString()
{
if (string.IsNullOrWhiteSpace(ModType))
ModTypeString = _globalizer.GetResourceString("ModType_Unknown");
switch (ModType)
{
case ModUtils.MODTYPE_MAP:
ModTypeString = _globalizer.GetResourceString("ModType_Map");
break;
case ModUtils.MODTYPE_MAPEXT:
ModTypeString = _globalizer.GetResourceString("ModType_MapExtension");
break;
case ModUtils.MODTYPE_MOD:
ModTypeString = _globalizer.GetResourceString("ModType_Mod");
break;
case ModUtils.MODTYPE_TOTCONV:
ModTypeString = _globalizer.GetResourceString("ModType_TotalConversion");
break;
default:
if (string.IsNullOrWhiteSpace(AppId))
ModTypeString = _globalizer.GetResourceString("ModType_Unknown");
else
ModTypeString = _globalizer.GetResourceString("ModType_NotDownloaded");
break;
}
}
public static ModDetail GetModDetail(PublishedFileDetail detail)
{
var result = new ModDetail();
result.AppId = detail.creator_app_id;
result.ModId = detail.publishedfileid;
result.TimeUpdated = detail.time_updated;
result.Title = detail.title;
result.IsValid = true;
return result;
}
public static ModDetail GetModDetail(WorkshopFileDetail detail)
{
var result = new ModDetail();
result.AppId = detail.creator_appid;
result.ModId = detail.publishedfileid;
result.TimeUpdated = detail.time_updated;
result.Title = detail.title;
result.IsValid = true;
return result;
}
public static ModDetail GetModDetail(WorkshopFileItem detail)
{
var result = new ModDetail();
result.AppId = detail.AppId;
result.ModId = detail.WorkshopId;
result.TimeUpdated = detail.TimeUpdated;
result.Title = detail.Title;
result.IsValid = true;
return result;
}
public override string ToString()
{
return $"{ModId} - {Title}";
}
}
public class ModDetailExtended
{
public ModDetailExtended(string modId)
{
ModId = modId;
}
public string MapName { get; set; }
private string ModId { get; set; }
public string ModType { get; set; }
public DateTime LastWriteTime { get; set; }
public int LastTimeUpdated { get; set; }
public long FolderSize { get; set; }
public void PopulateExtended(string modsRootFolder)
{
try
{
var modFolder = Path.Combine(modsRootFolder, ModId);
var modFile = $"{modFolder}.mod";
if (string.IsNullOrWhiteSpace(modFolder) || !Directory.Exists(modFolder))
return;
if (string.IsNullOrWhiteSpace(modFile) || !File.Exists(modFile))
return;
LastWriteTime = File.GetLastWriteTime(modFile);
var modTimeFile = Path.Combine(modFolder, Config.Default.LastUpdatedTimeFile);
if (!string.IsNullOrWhiteSpace(modTimeFile) && File.Exists(modTimeFile))
{
LastTimeUpdated = ModUtils.GetModLatestTime(modTimeFile);
}
ModUtils.ReadModFile(modFile, out string modId, out Dictionary<string, string> metaInformation, out List<string> mapNames);
ModType = metaInformation != null && metaInformation.ContainsKey("ModType") ? metaInformation["ModType"] : ModUtils.MODTYPE_UNKNOWN;
MapName = mapNames != null && mapNames.Count > 0 ? mapNames[0] : string.Empty;
FolderSize = 0;
foreach (var file in new DirectoryInfo(modFolder).GetFiles("*.*", SearchOption.AllDirectories))
{
FolderSize += file.Length;
}
}
catch (Exception)
{
// do nothing
}
}
}
}

View file

@ -0,0 +1,40 @@
using System.Net;
using System.Windows;
namespace ServerManagerTool.Lib
{
public class RCONParameters : PlayerListParameters
{
public static readonly DependencyProperty MaxPlayersProperty = DependencyProperty.Register(nameof(MaxPlayers), typeof(int), typeof(RCONParameters), new PropertyMetadata(0));
public string RCONHost { get; set; }
public IPAddress RCONHostIP
{
get
{
try
{
var ipAddresses = Dns.GetHostAddresses(RCONHost);
if (ipAddresses.Length > 0)
return ipAddresses[0].MapToIPv4();
}
catch {}
return IPAddress.None;
}
}
public int RCONPort { get; set; }
public string AdminPassword { get; set; }
public int MaxPlayers
{
get { return (int)GetValue(MaxPlayersProperty); }
set { SetValue(MaxPlayersProperty, value); }
}
public double PlayerListWidth { get; set; }
}
}

View file

@ -0,0 +1,105 @@
using ServerManagerTool.Common.Model;
using ServerManagerTool.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Windows;
namespace ServerManagerTool.Lib
{
[DataContract]
public class ResourceClassMultiplierList : AggregateIniValueList<ResourceClassMultiplier>
{
public ResourceClassMultiplierList(string aggregateValueName, Func<IEnumerable<ResourceClassMultiplier>> resetFunc)
: base(aggregateValueName, resetFunc)
{
}
public override void FromIniValues(IEnumerable<string> iniValues)
{
var items = iniValues?.Select(AggregateIniValue.FromINIValue<ResourceClassMultiplier>).ToArray();
Clear();
if (this._resetFunc != null)
this.AddRange(this._resetFunc());
var itemsToAdd = items.Where(i => !this.Any(r => r.IsEquivalent(i))).ToArray();
AddRange(itemsToAdd);
var itemsToUpdate = items.Where(i => this.Any(r => r.IsEquivalent(i))).ToArray();
foreach (var item in itemsToUpdate)
{
this.FirstOrDefault(r => r.IsEquivalent(item)).Multiplier = item.Multiplier;
}
IsEnabled = (items.Length > 0);
Sort(AggregateIniValue.SortKeySelector);
}
public override IEnumerable<string> ToIniValues()
{
if (string.IsNullOrWhiteSpace(IniCollectionKey))
return this.Where(d => d.ShouldSave()).Select(d => d.ToINIValue());
return this.Where(d => d.ShouldSave()).Select(d => $"{this.IniCollectionKey}={d.ToINIValue()}");
}
}
[DataContract]
public class ResourceClassMultiplier : ClassMultiplier
{
public static readonly DependencyProperty ModProperty = DependencyProperty.Register(nameof(Mod), typeof(string), typeof(ResourceClassMultiplier), new PropertyMetadata(String.Empty));
public static readonly DependencyProperty KnownResourceProperty = DependencyProperty.Register(nameof(KnownResource), typeof(bool), typeof(ResourceClassMultiplier), new PropertyMetadata(false));
[DataMember]
public string Mod
{
get { return (string)GetValue(ModProperty); }
set { SetValue(ModProperty, value); }
}
public bool KnownResource
{
get { return (bool)GetValue(KnownResourceProperty); }
set { SetValue(KnownResourceProperty, value); }
}
public override string DisplayName => GameData.FriendlyResourceNameForClass(ClassName);
public string DisplayMod => GameData.FriendlyNameForClass($"Mod_{Mod}", true) ?? Mod;
public new static ResourceClassMultiplier FromINIValue(string iniValue)
{
var newSpawn = new ResourceClassMultiplier();
newSpawn.InitializeFromINIValue(iniValue);
return newSpawn;
}
public override string GetSortKey()
{
return $"{DisplayName}|Mod";
}
public override void InitializeFromINIValue(string value)
{
base.InitializeFromINIValue(value);
if (!KnownResource)
Mod = GameData.MOD_UNKNOWN;
}
public override bool ShouldSave()
{
if (!KnownResource)
return true;
var resource = GameData.GetResourceMultiplierForClass(ClassName);
if (resource == null)
return true;
return (!resource.Multiplier.Equals(Multiplier));
}
}
}

View file

@ -0,0 +1,184 @@
using ServerManagerTool.Common.Attibutes;
using ServerManagerTool.Common.Model;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Windows;
namespace ServerManagerTool.Lib
{
[DataContract]
public class StackSizeOverrideList : AggregateIniValueList<StackSizeOverride>
{
public StackSizeOverrideList(string aggregateValueName)
: base(aggregateValueName, null)
{
}
public string[] RenderToView()
{
List<string> errors = new List<string>();
foreach (var stackSize in this)
{
if (stackSize.Quantity != null)
{
stackSize.IgnoreMultiplier = stackSize.Quantity.IgnoreMultiplier;
stackSize.MaxItemQuantity = stackSize.Quantity.MaxItemQuantity;
}
}
return errors.ToArray();
}
public void RenderToModel()
{
foreach (var stackSize in this)
{
if (stackSize.Quantity != null)
{
stackSize.Quantity.IgnoreMultiplier = stackSize.IgnoreMultiplier;
stackSize.Quantity.MaxItemQuantity = stackSize.MaxItemQuantity;
}
}
}
public void UpdateForLocalization()
{
}
}
[DataContract]
public class StackSizeOverride : AggregateIniValue
{
public StackSizeOverride()
{
Quantity = new StackSizeQuantity();
}
public static readonly DependencyProperty ItemClassStringProperty = DependencyProperty.Register(nameof(ItemClassString), typeof(string), typeof(StackSizeOverride), new PropertyMetadata(string.Empty));
[DataMember]
[AggregateIniValueEntry]
public string ItemClassString
{
get { return (string)GetValue(ItemClassStringProperty); }
set { SetValue(ItemClassStringProperty, value); }
}
public static readonly DependencyProperty IgnoreMultiplierProperty = DependencyProperty.Register(nameof(IgnoreMultiplier), typeof(bool), typeof(StackSizeOverride), new PropertyMetadata(true));
public bool IgnoreMultiplier
{
get { return (bool)GetValue(IgnoreMultiplierProperty); }
set { SetValue(IgnoreMultiplierProperty, value); }
}
public static readonly DependencyProperty MaxItemQuantityProperty = DependencyProperty.Register(nameof(MaxItemQuantity), typeof(int), typeof(StackSizeOverride), new PropertyMetadata(1));
public int MaxItemQuantity
{
get { return (int)GetValue(MaxItemQuantityProperty); }
set { SetValue(MaxItemQuantityProperty, value); }
}
[DataMember]
[AggregateIniValueEntry]
public StackSizeQuantity Quantity
{
get;
set;
}
public override string GetSortKey()
{
return null;
}
public override bool IsEquivalent(AggregateIniValue other)
{
return false;
}
public override void InitializeFromINIValue(string value)
{
if (string.IsNullOrWhiteSpace(value))
return;
var kvPair = value.Split(new[] { '=' }, 2);
var kvValue = kvPair[1].Trim(' ');
if (kvValue.StartsWith("("))
kvValue = kvValue.Substring(1);
if (kvValue.EndsWith(")"))
kvValue = kvValue.Substring(0, kvValue.Length - 1);
base.FromComplexINIValue(kvValue);
if (Quantity != null)
{
IgnoreMultiplier = Quantity.IgnoreMultiplier;
MaxItemQuantity = Quantity.MaxItemQuantity;
}
}
public override string ToINIValue()
{
if (Quantity != null)
{
Quantity.IgnoreMultiplier = IgnoreMultiplier;
Quantity.MaxItemQuantity = MaxItemQuantity;
}
return base.ToComplexINIValue(true);
}
public string DisplayName => GameData.FriendlyItemNameForClass(ItemClassString);
public bool IsValid => !string.IsNullOrWhiteSpace(ItemClassString);
}
[DataContract]
public class StackSizeQuantity : AggregateIniValue
{
[DataMember]
[AggregateIniValueEntry]
public int MaxItemQuantity
{
get;
set;
}
[DataMember]
[AggregateIniValueEntry(Key = "bIgnoreMultiplier")]
public bool IgnoreMultiplier
{
get;
set;
}
public override string GetSortKey()
{
return null;
}
public override bool IsEquivalent(AggregateIniValue other)
{
return false;
}
public override void InitializeFromINIValue(string value)
{
if (string.IsNullOrWhiteSpace(value))
return;
var kvValue = value;
if (kvValue.StartsWith("("))
kvValue = kvValue.Substring(1);
if (kvValue.EndsWith(")"))
kvValue = kvValue.Substring(0, kvValue.Length - 1);
base.FromComplexINIValue(kvValue);
}
public override string ToINIValue()
{
return base.ToComplexINIValue(true);
}
}
}

View file

@ -0,0 +1,88 @@
using ServerManagerTool.Common.Model;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ServerManagerTool.Lib.Model
{
public class StatsMultiplierArray : FloatIniValueArray
{
protected StatsMultiplierArray(string iniKeyName, Func<IEnumerable<float>> resetFunc, bool[] inclusions)
: base(iniKeyName, resetFunc)
{
Inclusions = inclusions;
}
public StatsMultiplierArray(string iniKeyName, Func<IEnumerable<float>> resetFunc, bool[] inclusions, bool onlyWriteNonDefaults)
: base(iniKeyName, resetFunc)
{
Inclusions = inclusions;
if (onlyWriteNonDefaults && resetFunc != null)
{
DefaultValues = new StatsMultiplierArray(iniKeyName, null, inclusions);
DefaultValues.AddRange(resetFunc());
}
}
public bool[] Inclusions { get; private set; } = null;
private StatsMultiplierArray DefaultValues { get; set; } = null;
public override void FromIniValues(IEnumerable<string> values)
{
this.Clear();
var list = new List<float>();
if (this.ResetFunc != null)
list.AddRange(this.ResetFunc());
foreach (var v in values)
{
var indexStart = v.IndexOf('[');
var indexEnd = v.IndexOf(']');
if (indexStart >= indexEnd)
{
// Invalid format
continue;
}
if (!int.TryParse(v.Substring(indexStart + 1, indexEnd - indexStart - 1), out int index))
{
// Invalid index
continue;
}
if (index >= list.Count)
{
// Unexpected size
continue;
}
list[index] = this.FromIniValue(v.Substring(v.IndexOf('=') + 1).Trim());
this.IsEnabled = true;
}
this.AddRange(list);
}
public override IEnumerable<string> ToIniValues()
{
var values = new List<string>();
for (var i = 0; i < this.Count; i++)
{
if (!(Inclusions?.ElementAtOrDefault(i) ?? true))
continue;
if (DefaultValues != null && Equals(DefaultValues[i], this[i]))
continue;
if (string.IsNullOrWhiteSpace(IniCollectionKey))
values.Add(this.ToIniValue(this[i]));
else
values.Add($"{this.IniCollectionKey}[{i}]={this.ToIniValue(this[i])}");
}
return values;
}
}
}

View file

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace ServerManagerTool.Lib
{
[DataContract]
public class StatsMultipliers
{
[DataMember]
public float Player
{
get;
set;
}
[DataMember]
public float WildDino
{
get;
set;
}
[DataMember]
public float TamedDino
{
get;
set;
}
}
}

View file

@ -0,0 +1,418 @@
using ServerManagerTool.Common.Attibutes;
using ServerManagerTool.Common.Model;
using ServerManagerTool.Lib.ViewModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using System.Windows;
namespace ServerManagerTool.Lib
{
[DataContract]
public class SupplyCrateOverrideList : AggregateIniValueList<SupplyCrateOverride>
{
public SupplyCrateOverrideList(string aggregateValueName)
: base(aggregateValueName, null)
{
}
public string[] RenderToView()
{
List<string> errors = new List<string>();
foreach (var supplyCrate in this)
{
foreach (var itemSet in supplyCrate.ItemSets)
{
foreach (var itemEntry in itemSet.ItemEntries)
{
itemEntry.Items = new ObservableCollection<SupplyCrateItemEntrySettings>();
for (var index = 0; index < itemEntry.ItemClassStrings.Count; index++)
{
var itemsWeight = 0.0f;
if (index < itemEntry.ItemsWeights.Count)
itemsWeight = itemEntry.ItemsWeights[index];
else
errors.Add($"Missing Supply Crate Item Weight: Crate '{supplyCrate.SupplyCrateClassString}'; Set '{itemSet.SetName}'; Entry '{itemEntry.ItemEntryName}'; Item '{itemEntry.ItemClassStrings[index]}'.");
itemEntry.Items.Add(new SupplyCrateItemEntrySettings {
ItemClassString = itemEntry.ItemClassStrings[index],
ItemWeight = itemsWeight,
});
}
}
}
}
return errors.ToArray();
}
public void RenderToModel()
{
foreach (var supplyCrate in this)
{
foreach (var itemSet in supplyCrate.ItemSets)
{
foreach (var itemEntry in itemSet.ItemEntries)
{
itemEntry.ItemClassStrings = new StringIniValueList(null, null);
itemEntry.ItemsWeights = new FloatIniValueList(null, null);
foreach (var itemClass in itemEntry.Items)
{
itemEntry.ItemClassStrings.Add(itemClass.ItemClassString);
itemEntry.ItemsWeights.Add(itemClass.ItemWeight);
}
}
}
}
}
public void UpdateForLocalization()
{
}
}
[DataContract]
public class SupplyCrateOverride : AggregateIniValue
{
public SupplyCrateOverride()
{
ItemSets = new AggregateIniValueList<SupplyCrateItemSet>(null, null);
}
public static readonly DependencyProperty SupplyCrateClassStringProperty = DependencyProperty.Register(nameof(SupplyCrateClassString), typeof(string), typeof(SupplyCrateOverride), new PropertyMetadata(string.Empty));
[DataMember]
[AggregateIniValueEntry]
public string SupplyCrateClassString
{
get { return (string)GetValue(SupplyCrateClassStringProperty); }
set { SetValue(SupplyCrateClassStringProperty, value); }
}
public static readonly DependencyProperty MinItemSetsProperty = DependencyProperty.Register(nameof(MinItemSets), typeof(float), typeof(SupplyCrateOverride), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float MinItemSets
{
get { return (float)GetValue(MinItemSetsProperty); }
set { SetValue(MinItemSetsProperty, value); }
}
public static readonly DependencyProperty MaxItemSetsProperty = DependencyProperty.Register(nameof(MaxItemSets), typeof(float), typeof(SupplyCrateOverride), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float MaxItemSets
{
get { return (float)GetValue(MaxItemSetsProperty); }
set { SetValue(MaxItemSetsProperty, value); }
}
public static readonly DependencyProperty NumItemSetsPowerProperty = DependencyProperty.Register(nameof(NumItemSetsPower), typeof(float), typeof(SupplyCrateOverride), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float NumItemSetsPower
{
get { return (float)GetValue(NumItemSetsPowerProperty); }
set { SetValue(NumItemSetsPowerProperty, value); }
}
public static readonly DependencyProperty SetsRandomWithoutReplacementProperty = DependencyProperty.Register(nameof(SetsRandomWithoutReplacement), typeof(bool), typeof(SupplyCrateOverride), new PropertyMetadata(true));
[DataMember]
[AggregateIniValueEntry(Key = "bSetsRandomWithoutReplacement")]
public bool SetsRandomWithoutReplacement
{
get { return (bool)GetValue(SetsRandomWithoutReplacementProperty); }
set { SetValue(SetsRandomWithoutReplacementProperty, value); }
}
public static readonly DependencyProperty AppendItemSetsProperty = DependencyProperty.Register(nameof(AppendItemSets), typeof(bool), typeof(SupplyCrateOverride), new PropertyMetadata(false));
[DataMember]
[AggregateIniValueEntry(Key = "bAppendItemSets", ExcludeIfFalse = true)]
public bool AppendItemSets
{
get { return (bool)GetValue(AppendItemSetsProperty); }
set { SetValue(AppendItemSetsProperty, value); }
}
public static readonly DependencyProperty AppendPreventIncreasingMinMaxItemSetsProperty = DependencyProperty.Register(nameof(AppendPreventIncreasingMinMaxItemSets), typeof(bool), typeof(SupplyCrateOverride), new PropertyMetadata(false));
[DataMember]
[AggregateIniValueEntry(Key = "bAppendPreventIncreasingMinMaxItemSets", ExcludeIfFalse = true)]
public bool AppendPreventIncreasingMinMaxItemSets
{
get { return (bool)GetValue(AppendPreventIncreasingMinMaxItemSetsProperty); }
set { SetValue(AppendPreventIncreasingMinMaxItemSetsProperty, value); }
}
public static readonly DependencyProperty ItemSetsProperty = DependencyProperty.Register(nameof(ItemSets), typeof(AggregateIniValueList<SupplyCrateItemSet>), typeof(SupplyCrateOverride), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry(ValueWithinBrackets = true, ListValueWithinBrackets = true, BracketsAroundValueDelimiter = 2)]
public AggregateIniValueList<SupplyCrateItemSet> ItemSets
{
get { return (AggregateIniValueList<SupplyCrateItemSet>)GetValue(ItemSetsProperty); }
set { SetValue(ItemSetsProperty, value); }
}
public override string GetSortKey()
{
return null;
}
public override bool IsEquivalent(AggregateIniValue other)
{
return false;
}
public override void InitializeFromINIValue(string value)
{
if (string.IsNullOrWhiteSpace(value))
return;
var kvPair = value.Split(new[] { '=' }, 2);
var kvValue = kvPair[1].Trim(' ');
if (kvValue.StartsWith("("))
kvValue = kvValue.Substring(1);
if (kvValue.EndsWith(")"))
kvValue = kvValue.Substring(0, kvValue.Length - 1);
base.FromComplexINIValue(kvValue);
}
public override string ToINIValue()
{
return base.ToComplexINIValue(true);
}
public string DisplayName => GameData.FriendlySupplyCrateNameForClass(SupplyCrateClassString);
public bool IsValid => !string.IsNullOrWhiteSpace(SupplyCrateClassString) && ItemSets.Count > 0;
}
[DataContract]
public class SupplyCrateItemSet : AggregateIniValue
{
public SupplyCrateItemSet()
{
ItemEntries = new AggregateIniValueList<SupplyCrateItemSetEntry>(null, null);
}
public static readonly DependencyProperty SetNameProperty = DependencyProperty.Register(nameof(SetName), typeof(string), typeof(SupplyCrateItemSet), new PropertyMetadata(string.Empty));
[DataMember]
[AggregateIniValueEntry(ExcludeIfEmpty = true)]
public string SetName
{
get { return (string)GetValue(SetNameProperty); }
set { SetValue(SetNameProperty, value); }
}
public static readonly DependencyProperty MinNumItemsProperty = DependencyProperty.Register(nameof(MinNumItems), typeof(float), typeof(SupplyCrateItemSet), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float MinNumItems
{
get { return (float)GetValue(MinNumItemsProperty); }
set { SetValue(MinNumItemsProperty, value); }
}
public static readonly DependencyProperty MaxNumItemsProperty = DependencyProperty.Register(nameof(MaxNumItems), typeof(float), typeof(SupplyCrateItemSet), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float MaxNumItems
{
get { return (float)GetValue(MaxNumItemsProperty); }
set { SetValue(MaxNumItemsProperty, value); }
}
public static readonly DependencyProperty NumItemsPowerProperty = DependencyProperty.Register(nameof(NumItemsPower), typeof(float), typeof(SupplyCrateItemSet), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float NumItemsPower
{
get { return (float)GetValue(NumItemsPowerProperty); }
set { SetValue(NumItemsPowerProperty, value); }
}
public static readonly DependencyProperty SetWeightProperty = DependencyProperty.Register(nameof(SetWeight), typeof(float), typeof(SupplyCrateItemSet), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float SetWeight
{
get { return (float)GetValue(SetWeightProperty); }
set { SetValue(SetWeightProperty, value); }
}
public static readonly DependencyProperty ItemsRandomWithoutReplacementProperty = DependencyProperty.Register(nameof(ItemsRandomWithoutReplacement), typeof(bool), typeof(SupplyCrateItemSet), new PropertyMetadata(true));
[DataMember]
[AggregateIniValueEntry(Key = "bItemsRandomWithoutReplacement")]
public bool ItemsRandomWithoutReplacement
{
get { return (bool)GetValue(ItemsRandomWithoutReplacementProperty); }
set { SetValue(ItemsRandomWithoutReplacementProperty, value); }
}
public static readonly DependencyProperty ItemEntriesProperty = DependencyProperty.Register(nameof(ItemEntries), typeof(AggregateIniValueList<SupplyCrateItemSetEntry>), typeof(SupplyCrateItemSet), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry(ValueWithinBrackets = true, ListValueWithinBrackets = true)]
public AggregateIniValueList<SupplyCrateItemSetEntry> ItemEntries
{
get { return (AggregateIniValueList<SupplyCrateItemSetEntry>)GetValue(ItemEntriesProperty); }
set { SetValue(ItemEntriesProperty, value); }
}
public override string GetSortKey()
{
return null;
}
public override bool IsEquivalent(AggregateIniValue other)
{
return false;
}
public override void InitializeFromINIValue(string value)
{
base.FromComplexINIValue(value);
}
public override string ToINIValue()
{
return base.ToComplexINIValue(false);
}
public bool IsValid => ItemEntries.Count > 0;
}
[DataContract]
public class SupplyCrateItemSetEntry : AggregateIniValue
{
public SupplyCrateItemSetEntry()
{
ItemClassStrings = new StringIniValueList(null, null);
ItemsWeights = new FloatIniValueList(null, null);
Items = new ObservableCollection<SupplyCrateItemEntrySettings>();
}
public static readonly DependencyProperty ItemEntryNameProperty = DependencyProperty.Register(nameof(ItemEntryName), typeof(string), typeof(SupplyCrateItemSetEntry), new PropertyMetadata(string.Empty));
[DataMember]
[AggregateIniValueEntry(ExcludeIfEmpty = true)]
public string ItemEntryName
{
get { return (string)GetValue(ItemEntryNameProperty); }
set { SetValue(ItemEntryNameProperty, value); }
}
public static readonly DependencyProperty EntryWeightProperty = DependencyProperty.Register(nameof(EntryWeight), typeof(float), typeof(SupplyCrateItemSetEntry), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float EntryWeight
{
get { return (float)GetValue(EntryWeightProperty); }
set { SetValue(EntryWeightProperty, value); }
}
public static readonly DependencyProperty MinQuantityProperty = DependencyProperty.Register(nameof(MinQuantity), typeof(float), typeof(SupplyCrateItemSetEntry), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float MinQuantity
{
get { return (float)GetValue(MinQuantityProperty); }
set { SetValue(MinQuantityProperty, value); }
}
public static readonly DependencyProperty MaxQuantityProperty = DependencyProperty.Register(nameof(MaxQuantity), typeof(float), typeof(SupplyCrateItemSetEntry), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float MaxQuantity
{
get { return (float)GetValue(MaxQuantityProperty); }
set { SetValue(MaxQuantityProperty, value); }
}
public static readonly DependencyProperty MinQualityProperty = DependencyProperty.Register(nameof(MinQuality), typeof(float), typeof(SupplyCrateItemSetEntry), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float MinQuality
{
get { return (float)GetValue(MinQualityProperty); }
set { SetValue(MinQualityProperty, value); }
}
public static readonly DependencyProperty MaxQualityProperty = DependencyProperty.Register(nameof(MaxQuality), typeof(float), typeof(SupplyCrateItemSetEntry), new PropertyMetadata(1.0f));
[DataMember]
[AggregateIniValueEntry]
public float MaxQuality
{
get { return (float)GetValue(MaxQualityProperty); }
set { SetValue(MaxQualityProperty, value); }
}
public static readonly DependencyProperty ForceBlueprintProperty = DependencyProperty.Register(nameof(ForceBlueprint), typeof(bool), typeof(SupplyCrateItemSetEntry), new PropertyMetadata(false));
[DataMember]
[AggregateIniValueEntry(Key = "bForceBlueprint")]
public bool ForceBlueprint
{
get { return (bool)GetValue(ForceBlueprintProperty); }
set { SetValue(ForceBlueprintProperty, value); }
}
public static readonly DependencyProperty ChanceToBeBlueprintOverrideProperty = DependencyProperty.Register(nameof(ChanceToBeBlueprintOverride), typeof(float), typeof(SupplyCrateItemSetEntry), new PropertyMetadata(0.0f));
[DataMember]
[AggregateIniValueEntry]
public float ChanceToBeBlueprintOverride
{
get { return (float)GetValue(ChanceToBeBlueprintOverrideProperty); }
set { SetValue(ChanceToBeBlueprintOverrideProperty, value); }
}
public static readonly DependencyProperty ItemClassStringsProperty = DependencyProperty.Register(nameof(ItemClassStrings), typeof(StringIniValueList), typeof(SupplyCrateItemSetEntry), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry(ValueWithinBrackets = true)]
public StringIniValueList ItemClassStrings
{
get { return (StringIniValueList)GetValue(ItemClassStringsProperty); }
set { SetValue(ItemClassStringsProperty, value); }
}
public static readonly DependencyProperty ItemsWeightsProperty = DependencyProperty.Register(nameof(ItemsWeights), typeof(FloatIniValueList), typeof(SupplyCrateItemSetEntry), new PropertyMetadata(null));
[DataMember]
[AggregateIniValueEntry(ValueWithinBrackets = true)]
public FloatIniValueList ItemsWeights
{
get { return (FloatIniValueList)GetValue(ItemsWeightsProperty); }
set { SetValue(ItemsWeightsProperty, value); }
}
public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register(nameof(Items), typeof(ObservableCollection<SupplyCrateItemEntrySettings>), typeof(SupplyCrateItemSetEntry), new PropertyMetadata(null));
public ObservableCollection<SupplyCrateItemEntrySettings> Items
{
get { return (ObservableCollection<SupplyCrateItemEntrySettings>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
public override string GetSortKey()
{
return null;
}
public override bool IsEquivalent(AggregateIniValue other)
{
return false;
}
public override void InitializeFromINIValue(string value)
{
base.FromComplexINIValue(value);
}
public override string ToINIValue()
{
return base.ToComplexINIValue(false);
}
public bool IsModelValid => ItemClassStrings.Count > 0 && ItemClassStrings.Count == ItemsWeights.Count;
public bool IsViewValid => Items.Count > 0;
}
}

View file

@ -0,0 +1,13 @@
using ServerManagerTool.Common.Attibutes;
using ServerManagerTool.Enums;
namespace ServerManagerTool.Lib
{
public class IniFileEntryAttribute : BaseIniFileEntryAttribute
{
public IniFileEntryAttribute(IniFiles file, IniSections section, ServerProfileCategory category, string key = "")
: base(file, section, category, key)
{
}
}
}

View file

@ -0,0 +1,9 @@
namespace ServerManagerTool.Lib
{
public enum IniFiles
{
Engine,
Game,
GameUserSettings,
}
}

View file

@ -0,0 +1,20 @@
namespace ServerManagerTool.Lib
{
public enum IniSections
{
// GameUserSettings.ini
GUS_ServerSettings,
GUS_ShooterGameUserSettings,
GUS_ScalabilityGroups,
GUS_SessionSettings,
GUS_GameSession,
GUS_MultiHome,
GUS_MessageOfTheDay,
// Game.ini
Game_ShooterGameMode,
// Misc
Custom,
}
}

View file

@ -0,0 +1,44 @@
using ServerManagerTool.Common.Serialization;
using System;
using System.Collections.Generic;
namespace ServerManagerTool.Lib
{
public class SystemIniFile : BaseSystemIniFile
{
public static readonly Dictionary<Enum, string> IniFileNames = new Dictionary<Enum, string>
{
{ IniFiles.GameUserSettings, Config.Default.ServerGameUserSettingsConfigFile },
{ IniFiles.Game, Config.Default.ServerGameConfigFile },
{ IniFiles.Engine, Config.Default.ServerEngineConfigFile },
};
public static readonly Dictionary<Enum, string> IniSectionNames = new Dictionary<Enum, string>
{
// GameUserSettings sections, used by the server manager
{ IniSections.GUS_ServerSettings, "ServerSettings" },
{ IniSections.GUS_ShooterGameUserSettings, "/Script/ShooterGame.ShooterGameUserSettings" },
{ IniSections.GUS_ScalabilityGroups, "ScalabilityGroups" },
{ IniSections.GUS_SessionSettings, "SessionSettings" },
{ IniSections.GUS_GameSession, "/Script/Engine.GameSession"},
{ IniSections.GUS_MultiHome, "MultiHome" },
{ IniSections.GUS_MessageOfTheDay, "MessageOfTheDay" },
// GameUserSettings sections, not used by server manager
// Game sections, used by the server manager
{ IniSections.Game_ShooterGameMode, "/script/shootergame.shootergamemode" },
// Game sections, not used by server manager
};
public override Dictionary<Enum, string> FileNames => IniFileNames;
public override Dictionary<Enum, string> SectionNames => IniSectionNames;
public SystemIniFile(string iniPath)
: base(iniPath)
{
}
}
}

View file

@ -0,0 +1,105 @@
using ServerManagerTool.Common.Lib;
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace ServerManagerTool.Lib
{
public class Server : DependencyObject, IDisposable
{
public static readonly DependencyProperty ProfileProperty = DependencyProperty.Register(nameof(Profile), typeof(ServerProfile), typeof(Server), new PropertyMetadata((ServerProfile)null));
public static readonly DependencyProperty RuntimeProperty = DependencyProperty.Register(nameof(Runtime), typeof(ServerRuntime), typeof(Server), new PropertyMetadata((ServerRuntime)null));
public static readonly DependencyProperty SelectedProperty = DependencyProperty.Register(nameof(Selected), typeof(bool), typeof(Server), new PropertyMetadata(false));
public ServerProfile Profile
{
get { return (ServerProfile)GetValue(ProfileProperty); }
protected set { SetValue(ProfileProperty, value); }
}
public ServerRuntime Runtime
{
get { return (ServerRuntime)GetValue(RuntimeProperty); }
protected set { SetValue(RuntimeProperty, value); }
}
public bool Selected
{
get { return (bool)GetValue(SelectedProperty); }
set { SetValue(SelectedProperty, value); }
}
private Server(ServerProfile profile)
{
InitializeFromProfile(profile);
}
public void Dispose()
{
this.Profile.DestroyServerFilesWatcher();
this.Runtime.StatusUpdate -= Runtime_StatusUpdate;
this.Runtime.Dispose();
}
private void Runtime_StatusUpdate(object sender, EventArgs eventArgs)
{
this.Profile.LastInstalledVersion = this.Runtime.Version.ToString();
}
public void ImportFromPath(string path, ServerProfile profile = null)
{
var loadedProfile = ServerProfile.LoadFrom(path, profile);
if (loadedProfile != null)
InitializeFromProfile(loadedProfile);
}
private void InitializeFromProfile(ServerProfile profile)
{
if (profile == null)
return;
this.Profile = profile;
this.Runtime = new ServerRuntime();
this.Runtime.AttachToProfile(this.Profile).Wait();
this.Runtime.StatusUpdate += Runtime_StatusUpdate;
}
public static Server FromPath(string path)
{
var loadedProfile = ServerProfile.LoadFrom(path);
if (loadedProfile == null)
return null;
return new Server(loadedProfile);
}
public static Server FromDefaults()
{
var loadedProfile = ServerProfile.FromDefaults();
if (loadedProfile == null)
return null;
return new Server(loadedProfile);
}
public async Task StartAsync()
{
await this.Runtime.AttachToProfile(this.Profile);
await this.Runtime.StartAsync();
}
public async Task StopAsync()
{
await this.Runtime.StopAsync();
}
public async Task<bool> UpgradeAsync(CancellationToken cancellationToken, bool updateServer, ServerBranchSnapshot branch, bool validate, bool updateMods, ProgressDelegate progressCallback)
{
await this.Runtime.AttachToProfile(this.Profile);
var success = await this.Runtime.UpgradeAsync(cancellationToken, updateServer, branch, validate, updateMods, progressCallback);
this.Profile.LastInstalledVersion = this.Runtime.Version.ToString();
return success;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
namespace ServerManagerTool.Lib
{
public class ServerBranchSnapshot
{
public string BranchName = string.Empty;
public string BranchPassword = string.Empty;
}
public class ServerBranchSnapshotComparer : IEqualityComparer<ServerBranchSnapshot>
{
public bool Equals(ServerBranchSnapshot x, ServerBranchSnapshot y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (x is null || y is null)
return false;
//Check whether the snapshot' properties are equal.
return x.BranchName == y.BranchName;
}
public int GetHashCode(ServerBranchSnapshot snapshot)
{
//Check whether the object is null
if (snapshot is null) return 0;
//Get hash code for the Name field if it is not null.
return snapshot.BranchName == null ? 0 : snapshot.BranchName.GetHashCode();
}
}
}

View file

@ -0,0 +1,135 @@
using ServerManagerTool.Common.Model;
using ServerManagerTool.Common.Utils;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Windows;
namespace ServerManagerTool.Lib
{
/// <summary>
/// This class is responsible for managing all of the servers the tool knows about.
/// </summary>
public class ServerManager : DependencyObject
{
static ServerManager()
{
ServerManager.Instance = new ServerManager();
}
public static ServerManager Instance
{
get;
private set;
}
public static readonly DependencyProperty ServersProperty = DependencyProperty.Register(nameof(Servers), typeof(SortableObservableCollection<Server>), typeof(ServerManager), new PropertyMetadata(new SortableObservableCollection<Server>()));
public SortableObservableCollection<Server> Servers
{
get { return (SortableObservableCollection<Server>)GetValue(ServersProperty); }
set { SetValue(ServersProperty, value); }
}
public ServerManager()
{
this.Servers.CollectionChanged += Servers_CollectionChanged;
}
void Servers_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if(e.Action == NotifyCollectionChangedAction.Remove)
{
foreach(Server server in e.OldItems)
{
server.Dispose();
}
}
}
public int AddFromPath(string path)
{
var server = Server.FromPath(path);
if (server == null)
return this.Servers.Count - 1;
this.Servers.Add(server);
return this.Servers.Count - 1;
}
public int AddNew()
{
var server = Server.FromDefaults();
if (server == null)
return this.Servers.Count - 1;
this.Servers.Add(server);
return this.Servers.Count - 1;
}
public void Remove(Server server, bool deleteProfile)
{
if (server == null)
return;
// save the profile before deleting, just in case something needed has changed
if (server.Profile != null)
server.Profile.Save(false, false, null);
if (deleteProfile)
{
var profileFile = server.Profile?.GetProfileFile();
if (!string.IsNullOrWhiteSpace(profileFile) && File.Exists(profileFile))
{
// set the file permissions
SecurityUtils.SetFileOwnershipForAllUsers(profileFile);
try
{
File.Delete(profileFile);
}
catch (Exception) { }
}
var profileIniDir = server.Profile?.GetProfileConfigDir_Old();
if (!string.IsNullOrWhiteSpace(profileIniDir) && Directory.Exists(profileIniDir))
{
// set the folder permissions
SecurityUtils.SetDirectoryOwnershipForAllUsers(profileIniDir);
try
{
Directory.Delete(profileIniDir, true);
}
catch (Exception) { }
}
}
server.Runtime?.DeleteFirewallRules();
server.Dispose();
this.Servers.Remove(server);
}
public void CheckProfiles()
{
var serverIds = new Dictionary<string, bool>();
foreach (var server in Servers)
{
if (server == null || server.Profile == null)
continue;
while (serverIds.ContainsKey(server.Profile.ProfileID))
{
server.Profile.ResetProfileId();
}
serverIds.Add(server.Profile.ProfileID, true);
}
}
public void SortServers()
{
Servers.Sort(s => s.Profile?.SortKey);
}
}
}

View file

@ -0,0 +1,246 @@
using ArkData;
using NLog;
using ServerManagerTool.Common.Model;
using ServerManagerTool.Common.Utils;
using ServerManagerTool.Enums;
using ServerManagerTool.Lib.ViewModel.RCON;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace ServerManagerTool.Lib
{
public class ServerPlayers : DependencyObject
{
private const int PLAYER_LIST_INTERVAL = 5000;
private const int STEAM_UPDATE_INTERVAL = 60;
public event EventHandler PlayersCollectionUpdated;
public static readonly DependencyProperty PlayersProperty = DependencyProperty.Register(nameof(Players), typeof(SortableObservableCollection<PlayerInfo>), typeof(ServerPlayers), new PropertyMetadata(null));
public static readonly DependencyProperty CountPlayersProperty = DependencyProperty.Register(nameof(CountPlayers), typeof(int), typeof(ServerPlayers), new PropertyMetadata(0));
public static readonly DependencyProperty CountInvalidPlayersProperty = DependencyProperty.Register(nameof(CountInvalidPlayers), typeof(int), typeof(ServerPlayers), new PropertyMetadata(0));
private readonly ConcurrentDictionary<string, PlayerInfo> _players = new ConcurrentDictionary<string, PlayerInfo>();
private readonly object _updatePlayerCollectionLock = new object();
private CancellationTokenSource _cancellationTokenSource = null;
private PlayerListParameters _playerListParameters;
private Logger _allLogger;
private Logger _eventLogger;
private Logger _debugLogger;
private Logger _errorLogger;
private bool _disposed = false;
public ServerPlayers(PlayerListParameters parameters)
{
this.Players = new SortableObservableCollection<PlayerInfo>();
_playerListParameters = parameters;
_allLogger = App.GetProfileLogger(_playerListParameters.ProfileId, "PlayerList_All", LogLevel.Info, LogLevel.Info);
_eventLogger = App.GetProfileLogger(_playerListParameters.ProfileId, "PlayerList_Event", LogLevel.Info, LogLevel.Info);
_debugLogger = App.GetProfileLogger(_playerListParameters.ProfileId, "PlayerList_Debug", LogLevel.Trace, LogLevel.Debug);
_errorLogger = App.GetProfileLogger(_playerListParameters.ProfileId, "PlayerList_Error", LogLevel.Error, LogLevel.Fatal);
UpdatePlayersAsync().DoNotWait();
}
public void Dispose()
{
if (_cancellationTokenSource != null)
{
_cancellationTokenSource.Cancel();
}
_disposed = true;
}
public SortableObservableCollection<PlayerInfo> Players
{
get { return (SortableObservableCollection<PlayerInfo>)GetValue(PlayersProperty); }
set { SetValue(PlayersProperty, value); }
}
public int CountPlayers
{
get { return (int)GetValue(CountPlayersProperty); }
set { SetValue(CountPlayersProperty, value); }
}
public int CountInvalidPlayers
{
get { return (int)GetValue(CountInvalidPlayersProperty); }
set { SetValue(CountInvalidPlayersProperty, value); }
}
private void LogEvent(LogEventType eventType, string message)
{
switch (eventType)
{
case LogEventType.All:
_allLogger?.Info(message);
return;
case LogEventType.Event:
_eventLogger?.Info(message);
return;
}
}
protected void OnPlayerCollectionUpdated()
{
PlayersCollectionUpdated?.Invoke(this, EventArgs.Empty);
}
private async Task UpdatePlayersAsync()
{
if (_disposed)
return;
_cancellationTokenSource = new CancellationTokenSource();
var token = _cancellationTokenSource.Token;
await UpdatePlayerDetailsAsync(_cancellationTokenSource.Token)
.ContinueWith(async t1 =>
{
await TaskUtils.RunOnUIThreadAsync(() =>
{
UpdatePlayerCollection();
});
}, TaskContinuationOptions.NotOnCanceled)
.ContinueWith(t2 =>
{
var cancelled = _cancellationTokenSource.IsCancellationRequested;
_cancellationTokenSource.Dispose();
_cancellationTokenSource = null;
if (!cancelled)
Task.Delay(PLAYER_LIST_INTERVAL).ContinueWith(t3 => UpdatePlayersAsync());
});
}
private async Task UpdatePlayerDetailsAsync(CancellationToken token)
{
if (!string.IsNullOrWhiteSpace(_playerListParameters.InstallDirectory))
{
var savedPath = ServerProfile.GetProfileSavePath(_playerListParameters.InstallDirectory, _playerListParameters.AltSaveDirectoryName, _playerListParameters.PGM_Enabled, _playerListParameters.PGM_Name);
DataContainer dataContainer = null;
DateTime lastSteamUpdateUtc = DateTime.MinValue;
try
{
// load the player data from the files.
dataContainer = await DataContainer.CreateAsync(savedPath, savedPath);
}
catch (Exception ex)
{
_errorLogger?.Error($"{nameof(UpdatePlayerDetailsAsync)} - Error: CreateAsync. {ex.Message}\r\n{ex.StackTrace}");
return;
}
token.ThrowIfCancellationRequested();
await Task.Run(() =>
{
// update the player data with the latest steam update value from the players collection
foreach (var playerData in dataContainer.Players)
{
var id = playerData.PlayerId;
if (string.IsNullOrWhiteSpace(id))
continue;
_players.TryGetValue(id, out PlayerInfo player);
player?.UpdatePlatformData(playerData);
}
}, token);
try
{
// load the player data from steam
lastSteamUpdateUtc = await dataContainer.LoadSteamAsync(SteamUtils.SteamWebApiKey, STEAM_UPDATE_INTERVAL);
}
catch (Exception ex)
{
_errorLogger?.Error($"{nameof(UpdatePlayerDetailsAsync)} - Error: LoadSteamAsync. {ex.Message}\r\n{ex.StackTrace}");
}
token.ThrowIfCancellationRequested();
var totalPlayers = dataContainer.Players.Count;
foreach (var playerData in dataContainer.Players)
{
token.ThrowIfCancellationRequested();
await Task.Run(async () =>
{
var id = playerData.PlayerId;
if (!string.IsNullOrWhiteSpace(id))
{
var validPlayer = new PlayerInfo()
{
PlayerId = playerData.PlayerId,
PlayerName = playerData.PlayerName,
IsValid = true,
};
_players.AddOrUpdate(id, validPlayer, (k, v) => { v.PlayerName = playerData.PlayerName; v.IsValid = true; return v; });
}
else
{
id = Path.GetFileNameWithoutExtension(playerData.Filename);
if (!string.IsNullOrWhiteSpace(id))
{
var invalidPlayer = new PlayerInfo()
{
PlayerId = id,
PlayerName = "< corrupted profile >",
IsValid = false,
};
_players.AddOrUpdate(id, invalidPlayer, (k, v) => { v.PlayerName = "< corrupted profile >"; v.IsValid = false; return v; });
}
else
{
_debugLogger?.Debug($"{nameof(UpdatePlayerDetailsAsync)} - Error: corrupted profile.\r\n{playerData.Filename}.");
}
}
if (_players.TryGetValue(id, out PlayerInfo player) && player != null)
{
player.UpdateData(playerData);
await TaskUtils.RunOnUIThreadAsync(() =>
{
player.IsAdmin = _playerListParameters?.Server?.Profile?.ServerFilesAdmins?.Any(u => u.PlayerId.Equals(player.PlayerId, StringComparison.OrdinalIgnoreCase)) ?? false;
player.IsWhitelisted = _playerListParameters?.Server?.Profile?.ServerFilesWhitelisted?.Any(u => u.PlayerId.Equals(player.PlayerId, StringComparison.OrdinalIgnoreCase)) ?? false;
});
}
}, token);
}
token.ThrowIfCancellationRequested();
// remove any players that do not have a player file.
var droppedPlayers = _players.Values.Where(p => dataContainer.Players.FirstOrDefault(pd => pd.PlayerId.Equals(p.PlayerId, StringComparison.OrdinalIgnoreCase)) == null).ToArray();
foreach (var droppedPlayer in droppedPlayers)
{
_players.TryRemove(droppedPlayer.PlayerId, out PlayerInfo player);
}
}
}
private void UpdatePlayerCollection()
{
lock (_updatePlayerCollectionLock)
{
this.Players = new SortableObservableCollection<PlayerInfo>(_players.Values);
this.CountPlayers = this.Players.Count;
this.CountInvalidPlayers = this.Players.Count(p => !p.IsValid);
OnPlayerCollectionUpdated();
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,116 @@
using ServerManagerTool.Utils;
using System;
using System.Collections.Generic;
using System.Net;
namespace ServerManagerTool.Lib
{
public class ServerProfileSnapshot
{
public string ProfileId;
public string ProfileName;
public string InstallDirectory;
public string AltSaveDirectoryName;
public bool PGM_Enabled;
public string PGM_Name;
public string AdminPassword;
public string ServerName;
public string ServerArgs;
public string ServerIP;
public int ServerPort;
public int ServerPeerPort;
public int QueryPort;
public bool RCONEnabled;
public int RCONPort;
public string ServerMap;
public string ServerMapModId;
public string TotalConversionModId;
public List<string> ServerModIds;
public string MOTD;
public int MotDDuration;
public bool MOTDIntervalEnabled;
public int MOTDInterval;
public bool ForceRespawnDinos;
public string BranchName;
public string BranchPassword;
public string SchedulerKey;
public bool EnableAutoBackup;
public bool EnableAutoUpdate;
public bool EnableAutoShutdown1;
public bool RestartAfterShutdown1;
public bool UpdateAfterShutdown1;
public bool EnableAutoShutdown2;
public bool RestartAfterShutdown2;
public bool UpdateAfterShutdown2;
public bool AutoRestartIfShutdown;
public bool SotFEnabled;
public int MaxPlayerCount;
public bool ServerUpdated;
public string LastInstalledVersion;
public DateTime LastStarted;
public static ServerProfileSnapshot Create(ServerProfile profile)
{
return new ServerProfileSnapshot
{
ProfileId = profile.ProfileID,
ProfileName = profile.ProfileName,
InstallDirectory = profile.InstallDirectory,
AltSaveDirectoryName = profile.AltSaveDirectoryName,
PGM_Enabled = profile.PGM_Enabled,
PGM_Name = profile.PGM_Name,
AdminPassword = profile.AdminPassword,
ServerName = profile.ServerName,
ServerArgs = profile.GetServerArgs(),
ServerIP = string.IsNullOrWhiteSpace(profile.ServerIP) ? IPAddress.Loopback.ToString() : profile.ServerIP.Trim(),
ServerPort = profile.ServerPort,
ServerPeerPort = profile.ServerPeerPort,
QueryPort = profile.QueryPort,
RCONEnabled = profile.RCONEnabled,
RCONPort = profile.RCONPort,
ServerMap = ServerProfile.GetProfileMapName(profile),
ServerMapModId = ServerProfile.GetProfileMapModId(profile),
TotalConversionModId = profile.TotalConversionModId ?? string.Empty,
ServerModIds = ModUtils.GetModIdList(profile.ServerModIds),
MOTD = profile.MOTD,
MotDDuration = Math.Max(profile.MOTDDuration, 10),
MOTDIntervalEnabled = profile.MOTDInterval.HasValue && !string.IsNullOrWhiteSpace(profile.MOTD),
MOTDInterval = Math.Max(1, Math.Min(int.MaxValue, profile.MOTDInterval.Value)),
ForceRespawnDinos = profile.ForceRespawnDinos,
BranchName = profile.BranchName,
BranchPassword = profile.BranchPassword,
SchedulerKey = profile.GetProfileKey(),
EnableAutoBackup = profile.EnableAutoBackup,
EnableAutoUpdate = profile.EnableAutoUpdate,
EnableAutoShutdown1 = profile.EnableAutoShutdown1,
RestartAfterShutdown1 = profile.RestartAfterShutdown1,
UpdateAfterShutdown1 = profile.UpdateAfterShutdown1,
EnableAutoShutdown2 = profile.EnableAutoShutdown2,
RestartAfterShutdown2 = profile.RestartAfterShutdown2,
UpdateAfterShutdown2 = profile.UpdateAfterShutdown2,
AutoRestartIfShutdown = profile.AutoRestartIfShutdown,
SotFEnabled = profile.SOTF_Enabled,
MaxPlayerCount = profile.MaxPlayers,
ServerUpdated = false,
LastInstalledVersion = profile.LastInstalledVersion ?? new Version(0, 0).ToString(),
LastStarted = profile.LastStarted,
};
}
public void Update(ServerProfile profile)
{
profile.LastInstalledVersion = LastInstalledVersion;
profile.LastStarted = LastStarted;
}
}
}

View file

@ -0,0 +1,628 @@
using ArkData;
using NLog;
using ServerManagerTool.Common.Interfaces;
using ServerManagerTool.Common.Lib;
using ServerManagerTool.Common.Model;
using ServerManagerTool.Common.Utils;
using ServerManagerTool.Enums;
using ServerManagerTool.Lib.ViewModel;
using ServerManagerTool.Lib.ViewModel.RCON;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using WPFSharp.Globalizer;
namespace ServerManagerTool.Lib
{
public class ServerRCON : DependencyObject, IAsyncDisposable
{
public event EventHandler PlayersCollectionUpdated;
private const int STEAM_UPDATE_INTERVAL = 60;
private const int PLAYER_LIST_INTERVAL = 5000;
private const int GET_CHAT_INTERVAL = 1000;
private const string NoResponseMatch = "Server received, But no response!!";
public const string NoResponseOutput = "NO_RESPONSE";
public const string RCON_COMMAND_BROADCAST = "broadcast";
public const string RCON_COMMAND_LISTPLAYERS = "listplayers";
public const string RCON_COMMAND_GETCHAT = "getchat";
public const string RCON_COMMAND_SERVERCHAT = "serverchat";
public const string RCON_COMMAND_WILDDINOWIPE = "DestroyWildDinos";
[TypeConverter(typeof(EnumDescriptionTypeConverter))]
public enum ConsoleStatus
{
Disconnected,
Connected,
};
public class ConsoleCommand
{
public ConsoleStatus status;
public string rawCommand;
public string command;
public string args;
public bool suppressCommand;
public bool suppressOutput;
public IEnumerable<string> lines = new string[0];
};
private class CommandListener : IDisposable
{
public Action<ConsoleCommand> Callback { get; set; }
public Action<CommandListener> DisposeAction { get; set; }
public void Dispose()
{
DisposeAction(this);
}
}
public static readonly DependencyProperty StatusProperty = DependencyProperty.Register(nameof(Status), typeof(ConsoleStatus), typeof(ServerRCON), new PropertyMetadata(ConsoleStatus.Disconnected));
public static readonly DependencyProperty PlayersProperty = DependencyProperty.Register(nameof(Players), typeof(SortableObservableCollection<PlayerInfo>), typeof(ServerRCON), new PropertyMetadata(null));
public static readonly DependencyProperty CountPlayersProperty = DependencyProperty.Register(nameof(CountPlayers), typeof(int), typeof(ServerRCON), new PropertyMetadata(0));
public static readonly DependencyProperty CountInvalidPlayersProperty = DependencyProperty.Register(nameof(CountInvalidPlayers), typeof(int), typeof(ServerRCON), new PropertyMetadata(0));
public static readonly DependencyProperty CountOnlinePlayersProperty = DependencyProperty.Register(nameof(CountOnlinePlayers), typeof(int), typeof(ServerRCON), new PropertyMetadata(0));
private static readonly char[] lineSplitChars = new char[] { '\n' };
private static readonly char[] argsSplitChars = new char[] { ' ' };
private readonly ActionQueue commandProcessor = new ActionQueue(TaskScheduler.Default);
private readonly ActionQueue outputProcessor = new ActionQueue(TaskScheduler.FromCurrentSynchronizationContext());
private readonly List<CommandListener> commandListeners = new List<CommandListener>();
private readonly RCONParameters rconParams;
private QueryMaster.Rcon console;
private int maxCommandRetries = 3;
private readonly ConcurrentDictionary<string, PlayerInfo> players = new ConcurrentDictionary<string, PlayerInfo>();
private readonly object updatePlayerCollectionLock = new object();
private CancellationTokenSource cancellationTokenSource = null;
private readonly Logger _chatLogger;
private readonly Logger _allLogger;
private readonly Logger _eventLogger;
private readonly Logger _debugLogger;
private readonly Logger _errorLogger;
private bool _disposed = false;
public ServerRCON(RCONParameters parameters)
{
this.rconParams = parameters;
this.Players = new SortableObservableCollection<PlayerInfo>();
_allLogger = App.GetProfileLogger(this.rconParams.ProfileId, "RCON_All", LogLevel.Info, LogLevel.Info);
_chatLogger = App.GetProfileLogger(this.rconParams.ProfileId, "RCON_Chat", LogLevel.Info, LogLevel.Info);
_eventLogger = App.GetProfileLogger(this.rconParams.ProfileId, "RCON_Event", LogLevel.Info, LogLevel.Info);
_debugLogger = App.GetProfileLogger(this.rconParams.ProfileId, "RCON_Debug", LogLevel.Trace, LogLevel.Debug);
_errorLogger = App.GetProfileLogger(this.rconParams.ProfileId, "RCON_Error", LogLevel.Error, LogLevel.Fatal);
}
public async Task DisposeAsync()
{
if (cancellationTokenSource != null)
{
cancellationTokenSource.Cancel();
}
await this.commandProcessor.DisposeAsync();
await this.outputProcessor.DisposeAsync();
for (int index = this.commandListeners.Count - 1; index >= 0; index--)
{
this.commandListeners[index].Dispose();
}
_disposed = true;
}
#region Properties
public ConsoleStatus Status
{
get { return (ConsoleStatus)GetValue(StatusProperty); }
set { SetValue(StatusProperty, value); }
}
public SortableObservableCollection<PlayerInfo> Players
{
get { return (SortableObservableCollection<PlayerInfo>)GetValue(PlayersProperty); }
set { SetValue(PlayersProperty, value); }
}
public int CountPlayers
{
get { return (int)GetValue(CountPlayersProperty); }
set { SetValue(CountPlayersProperty, value); }
}
public int CountInvalidPlayers
{
get { return (int)GetValue(CountInvalidPlayersProperty); }
set { SetValue(CountInvalidPlayersProperty, value); }
}
public int CountOnlinePlayers
{
get { return (int)GetValue(CountOnlinePlayersProperty); }
set { SetValue(CountOnlinePlayersProperty, value); }
}
#endregion
#region Methods
public void Initialize()
{
commandProcessor.PostAction(AutoPlayerList);
commandProcessor.PostAction(AutoGetChat);
UpdatePlayersAsync().DoNotWait();
}
private void LogEvent(LogEventType eventType, string message)
{
switch (eventType)
{
case LogEventType.All:
_allLogger?.Info(message);
return;
case LogEventType.Chat:
_chatLogger?.Info(message);
return;
case LogEventType.Event:
_eventLogger?.Info(message);
return;
}
}
internal void OnPlayerCollectionUpdated()
{
PlayersCollectionUpdated?.Invoke(this, EventArgs.Empty);
}
private bool Reconnect()
{
if (this.console != null)
{
this.console.Dispose();
this.console = null;
}
var endpoint = new IPEndPoint(this.rconParams.RCONHostIP, this.rconParams.RCONPort);
var server = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endpoint);
this.console = server.GetControl(this.rconParams.AdminPassword);
return this.console != null;
}
public IDisposable RegisterCommandListener(Action<ConsoleCommand> callback)
{
var listener = new CommandListener { Callback = callback, DisposeAction = UnregisterCommandListener };
this.commandListeners.Add(listener);
return listener;
}
private void UnregisterCommandListener(CommandListener listener)
{
this.commandListeners.Remove(listener);
}
#endregion
#region Process Methods
private Task AutoPlayerList()
{
return commandProcessor.PostAction(() =>
{
ProcessInput(new ConsoleCommand() { rawCommand = RCON_COMMAND_LISTPLAYERS, suppressCommand = true, suppressOutput = true });
Task.Delay(PLAYER_LIST_INTERVAL).ContinueWith(t => commandProcessor.PostAction(AutoPlayerList)).DoNotWait();
});
}
private Task AutoGetChat()
{
return commandProcessor.PostAction(() =>
{
ProcessInput(new ConsoleCommand() { rawCommand = RCON_COMMAND_GETCHAT, suppressCommand = true, suppressOutput = true });
Task.Delay(GET_CHAT_INTERVAL).ContinueWith(t => commandProcessor.PostAction(AutoGetChat)).DoNotWait();
});
}
private bool ProcessInput(ConsoleCommand command)
{
try
{
if (!command.suppressCommand)
{
LogEvent(LogEventType.All, command.rawCommand);
}
var args = command.rawCommand.Split(argsSplitChars, 2);
command.command = args[0];
if (args.Length > 1)
{
command.args = args[1];
}
var result = SendCommand(command.rawCommand);
if (result == null)
{
_debugLogger.Debug($"SendCommand '{command.rawCommand}' do not return any results.");
}
else
{
var lines = result.Split(lineSplitChars, StringSplitOptions.RemoveEmptyEntries).Select(l => l.Trim()).ToArray();
if (!command.suppressOutput)
{
foreach (var line in lines)
{
LogEvent(LogEventType.All, line);
}
}
if (lines.Length == 1 && lines[0].StartsWith(NoResponseMatch))
{
lines[0] = NoResponseOutput;
}
command.lines = lines;
}
command.status = ConsoleStatus.Connected;
this.outputProcessor.PostAction(() => ProcessOutput(command));
return true;
}
catch (Exception ex)
{
_errorLogger.Error($"Failed to send command '{command.rawCommand}'. {ex.Message}");
command.status = ConsoleStatus.Disconnected;
this.outputProcessor.PostAction(() => ProcessOutput(command));
return false;
}
}
// This is bound to the UI thread
private void ProcessOutput(ConsoleCommand command)
{
//
// Handle results
//
HandleCommand(command);
NotifyCommand(command);
}
public Task<bool> IssueCommand(string userCommand)
{
return this.commandProcessor.PostAction(() => ProcessInput(new ConsoleCommand() { rawCommand = userCommand }));
}
// This is bound to the UI thread
private void HandleCommand(ConsoleCommand command)
{
//
// Change the connection state as appropriate
//
this.Status = command.status;
//
// Perform per-command special processing to extract data
//
if (command.command.Equals(RCON_COMMAND_LISTPLAYERS, StringComparison.OrdinalIgnoreCase))
{
//
// Update the visible player list
//
command.suppressOutput = false;
command.lines = HandleListPlayersCommand(command.lines);
}
else if (command.command.Equals(RCON_COMMAND_GETCHAT, StringComparison.OrdinalIgnoreCase))
{
// TODO: Extract the player name from the chat
var lines = command.lines.Where(l => !String.IsNullOrEmpty(l) && l != NoResponseOutput).ToArray();
if (lines.Length == 0 && command.suppressCommand)
{
command.suppressOutput = true;
}
else
{
command.suppressOutput = false;
command.lines = lines;
foreach (var line in lines)
{
LogEvent(LogEventType.Chat, line);
LogEvent(LogEventType.All, line);
}
}
}
else if (command.command.Equals(RCON_COMMAND_BROADCAST, StringComparison.OrdinalIgnoreCase))
{
LogEvent(LogEventType.Chat, command.rawCommand);
command.suppressOutput = true;
}
else if (command.command.Equals(RCON_COMMAND_SERVERCHAT, StringComparison.OrdinalIgnoreCase))
{
LogEvent(LogEventType.Chat, command.rawCommand);
command.suppressOutput = true;
}
}
// This is bound to the UI thread
private List<string> HandleListPlayersCommand(IEnumerable<string> commandLines)
{
var output = new List<string>();
if (commandLines != null)
{
var onlinePlayers = new List<PlayerInfo>();
foreach (var line in commandLines)
{
var elements = line.Split(',');
if (elements.Length != 2)
// Invalid data. Ignore it.
continue;
var id = elements[1]?.Trim();
if (id.Any(c => !char.IsDigit(c)))
// Invalid data. Ignore it.
continue;
if (onlinePlayers.FirstOrDefault(p => p.PlayerId.Equals(id, StringComparison.OrdinalIgnoreCase)) != null)
// Duplicate data. Ignore it.
continue;
var newPlayer = new PlayerInfo()
{
PlayerId = id,
PlayerName = elements[0].Substring(elements[0].IndexOf('.') + 1).Trim(),
IsOnline = true,
};
onlinePlayers.Add(newPlayer);
var playerJoined = false;
this.players.AddOrUpdate(newPlayer.PlayerId, (k) => { playerJoined = true; return newPlayer; }, (k, v) => { playerJoined = !v.IsOnline; v.IsOnline = true; return v; });
if (playerJoined)
{
var messageFormat = GlobalizedApplication.Instance.GetResourceString("Player_Join") ?? "Player '{0}' joined the game.";
var message = string.Format(messageFormat, newPlayer.PlayerName);
output.Add(message);
LogEvent(LogEventType.Event, message);
LogEvent(LogEventType.All, message);
}
}
var droppedPlayers = this.players.Values.Where(p => onlinePlayers.FirstOrDefault(np => np.PlayerId.Equals(p.PlayerId, StringComparison.OrdinalIgnoreCase)) == null).ToArray();
foreach (var droppedPlayer in droppedPlayers)
{
if (droppedPlayer.IsOnline)
{
droppedPlayer.IsOnline = false;
var messageFormat = GlobalizedApplication.Instance.GetResourceString("Player_Leave") ?? "Player '{0}' left the game.";
var message = string.Format(messageFormat, droppedPlayer.PlayerName);
output.Add(message);
LogEvent(LogEventType.Event, message);
LogEvent(LogEventType.All, message);
}
}
UpdatePlayerCollection();
}
return output;
}
// This is bound to the UI thread
private void NotifyCommand(ConsoleCommand command)
{
foreach (var listener in commandListeners)
{
try
{
listener.Callback(command);
}
catch (Exception ex)
{
_errorLogger.Error("Exception in command listener: {0}\n{1}", ex.Message, ex.StackTrace);
}
}
}
private string SendCommand(string command)
{
const int RETRY_DELAY = 100;
Exception lastException = null;
int retries = 0;
while (retries < maxCommandRetries)
{
if (this.console != null)
{
try
{
return this.console.SendCommand(command);
}
catch (Exception ex)
{
// we will simply retry
lastException = ex;
}
Task.Delay(RETRY_DELAY).Wait();
}
try
{
Reconnect();
}
catch (Exception ex)
{
lastException = ex;
}
retries++;
}
this.maxCommandRetries = 10;
_errorLogger.Error($"Failed to connect to RCON at {this.rconParams.RCONHostIP}:{this.rconParams.RCONPort} with {this.rconParams.AdminPassword}. {lastException.Message}");
throw new Exception($"Command failed to send after {maxCommandRetries} attempts. Last exception: {lastException.Message}", lastException);
}
#endregion
private async Task UpdatePlayersAsync()
{
if (this._disposed)
return;
cancellationTokenSource = new CancellationTokenSource();
var token = cancellationTokenSource.Token;
await UpdatePlayerDetailsAsync(cancellationTokenSource.Token)
.ContinueWith(async t1 =>
{
await TaskUtils.RunOnUIThreadAsync(() =>
{
UpdatePlayerCollection();
});
}, TaskContinuationOptions.NotOnCanceled)
.ContinueWith(t2 =>
{
var cancelled = cancellationTokenSource.IsCancellationRequested;
cancellationTokenSource.Dispose();
cancellationTokenSource = null;
if (!cancelled)
Task.Delay(PLAYER_LIST_INTERVAL).ContinueWith(t3 => UpdatePlayersAsync());
});
}
private async Task UpdatePlayerDetailsAsync(CancellationToken token)
{
if (!string.IsNullOrWhiteSpace(rconParams.InstallDirectory))
{
var savedPath = ServerProfile.GetProfileSavePath(rconParams.InstallDirectory, rconParams.AltSaveDirectoryName, rconParams.PGM_Enabled, rconParams.PGM_Name);
DataContainer dataContainer = null;
DateTime lastSteamUpdateUtc = DateTime.MinValue;
try
{
// load the player data from the files.
dataContainer = await DataContainer.CreateAsync(savedPath, savedPath);
}
catch (Exception ex)
{
_errorLogger.Error($"{nameof(UpdatePlayerDetailsAsync)} - Error: CreateAsync. {ex.Message}\r\n{ex.StackTrace}");
return;
}
token.ThrowIfCancellationRequested();
await Task.Run(() =>
{
// update the player data with the latest update value from the players collection
foreach (var playerData in dataContainer.Players)
{
var id = playerData.PlayerId;
if (string.IsNullOrWhiteSpace(id))
continue;
this.players.TryGetValue(id, out PlayerInfo player);
player?.UpdatePlatformData(playerData);
}
}, token);
try
{
// load the player data from steam
lastSteamUpdateUtc = await dataContainer.LoadSteamAsync(SteamUtils.SteamWebApiKey, STEAM_UPDATE_INTERVAL);
}
catch (Exception ex)
{
_errorLogger.Error($"{nameof(UpdatePlayerDetailsAsync)} - Error: LoadSteamAsync. {ex.Message}\r\n{ex.StackTrace}");
}
token.ThrowIfCancellationRequested();
var totalPlayers = dataContainer.Players.Count;
foreach (var playerData in dataContainer.Players)
{
token.ThrowIfCancellationRequested();
await Task.Run(async () =>
{
var id = playerData.PlayerId;
if (!string.IsNullOrWhiteSpace(id))
{
var validPlayer = new PlayerInfo()
{
PlayerId = playerData.PlayerId,
PlayerName = playerData.PlayerName,
IsValid = true,
};
this.players.AddOrUpdate(id, validPlayer, (k, v) => { v.PlayerName = playerData.PlayerName; v.IsValid = true; return v; });
}
else
{
id = Path.GetFileNameWithoutExtension(playerData.Filename);
if (string.IsNullOrWhiteSpace(id))
{
var invalidPlayer = new PlayerInfo()
{
PlayerId = id,
PlayerName = "< corrupted profile >",
IsValid = false,
};
this.players.AddOrUpdate(id, invalidPlayer, (k, v) => { v.PlayerName = "< corrupted profile >"; v.IsValid = false; return v; });
}
else
{
_debugLogger.Debug($"{nameof(UpdatePlayerDetailsAsync)} - Error: corrupted profile.\r\n{playerData.Filename}.");
}
}
if (this.players.TryGetValue(id, out PlayerInfo player) && player != null)
{
player.UpdateData(playerData);
await TaskUtils.RunOnUIThreadAsync(() =>
{
player.IsAdmin = rconParams?.Server?.Profile?.ServerFilesAdmins?.Any(u => u.PlayerId.Equals(player.PlayerId, StringComparison.OrdinalIgnoreCase)) ?? false;
player.IsWhitelisted = rconParams?.Server?.Profile?.ServerFilesWhitelisted?.Any(u => u.PlayerId.Equals(player.PlayerId, StringComparison.OrdinalIgnoreCase)) ?? false;
});
}
}, token);
}
token.ThrowIfCancellationRequested();
// remove any players that do not have a player file.
var droppedPlayers = this.players.Values.Where(p => dataContainer.Players.FirstOrDefault(pd => pd.PlayerId.Equals(p.PlayerId, StringComparison.OrdinalIgnoreCase)) == null).ToArray();
foreach (var droppedPlayer in droppedPlayers)
{
players.TryRemove(droppedPlayer.PlayerId, out PlayerInfo player);
}
}
}
private void UpdatePlayerCollection()
{
lock (updatePlayerCollectionLock)
{
this.Players = new SortableObservableCollection<PlayerInfo>(players.Values);
this.CountPlayers = this.Players.Count;
this.CountInvalidPlayers = this.Players.Count(p => !p.IsValid);
this.CountOnlinePlayers = this.Players.Count(p => p.IsOnline);
OnPlayerCollectionUpdated();
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,381 @@
using ServerManagerTool.Common.Interfaces;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
namespace ServerManagerTool.Lib
{
using NLog;
using ServerManagerTool;
using ServerManagerTool.Common.Utils;
using ServerManagerTool.Enums;
using StatusCallback = Action<IAsyncDisposable, ServerStatusWatcher.ServerStatusUpdate>;
public class ServerStatusWatcher
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public struct ServerStatusUpdate
{
public Process Process;
public WatcherServerStatus Status;
public QueryMaster.ServerInfo ServerInfo;
public int OnlinePlayerCount;
}
private class ServerStatusUpdateRegistration : IAsyncDisposable
{
public string InstallDirectory;
public IPEndPoint LocalEndpoint;
public IPEndPoint SteamEndpoint;
public StatusCallback UpdateCallback;
public Func<Task> UnregisterAction;
public string AsmId;
public string ProfileId;
public async Task DisposeAsync()
{
await UnregisterAction();
}
}
private readonly List<ServerStatusUpdateRegistration> _serverRegistrations = new List<ServerStatusUpdateRegistration>();
private readonly ActionBlock<Func<Task>> _eventQueue;
private readonly Dictionary<string, DateTime> _nextExternalStatusQuery = new Dictionary<string, DateTime>();
private ServerStatusWatcher()
{
_eventQueue = new ActionBlock<Func<Task>>(async f => await f.Invoke(), new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1 });
_eventQueue.Post(DoLocalUpdate);
}
static ServerStatusWatcher()
{
ServerStatusWatcher.Instance = new ServerStatusWatcher();
}
public static ServerStatusWatcher Instance
{
get;
private set;
}
public IAsyncDisposable RegisterForUpdates(string installDirectory, string profileId, IPEndPoint localEndpoint, IPEndPoint steamEndpoint, Action<IAsyncDisposable, ServerStatusUpdate> updateCallback)
{
var registration = new ServerStatusUpdateRegistration
{
AsmId = Config.Default.ASMUniqueKey,
InstallDirectory = installDirectory,
ProfileId = profileId,
LocalEndpoint = localEndpoint,
SteamEndpoint = steamEndpoint,
UpdateCallback = updateCallback,
};
registration.UnregisterAction = async () =>
{
var tcs = new TaskCompletionSource<bool>();
_eventQueue.Post(() =>
{
if(_serverRegistrations.Contains(registration))
{
Logger.Debug($"{nameof(RegisterForUpdates)} Removing registration for L:{registration.LocalEndpoint} S:{registration.SteamEndpoint}");
_serverRegistrations.Remove(registration);
}
tcs.TrySetResult(true);
return Task.FromResult(true);
});
await tcs.Task;
};
_eventQueue.Post(() =>
{
if (!_serverRegistrations.Contains(registration))
{
Logger.Debug($"{nameof(RegisterForUpdates)} Adding registration for L:{registration.LocalEndpoint} S:{registration.SteamEndpoint}");
_serverRegistrations.Add(registration);
var registrationKey = registration.SteamEndpoint.ToString();
_nextExternalStatusQuery[registrationKey] = DateTime.MinValue;
}
return Task.FromResult(true);
}
);
return registration;
}
private static ServerProcessStatus GetServerProcessStatus(ServerStatusUpdateRegistration updateContext, out Process serverProcess)
{
serverProcess = null;
if (String.IsNullOrWhiteSpace(updateContext.InstallDirectory))
{
return ServerProcessStatus.NotInstalled;
}
var serverExePath = Path.Combine(updateContext.InstallDirectory, Config.Default.ServerBinaryRelativePath, Config.Default.ServerExe);
if(!File.Exists(serverExePath))
{
return ServerProcessStatus.NotInstalled;
}
//
// The server appears to be installed, now determine if it is running or stopped.
//
try
{
foreach (var process in Process.GetProcessesByName(Config.Default.ServerProcessName))
{
var commandLine = ProcessUtils.GetCommandLineForProcess(process.Id)?.ToLower();
if (commandLine != null && commandLine.Contains(updateContext.InstallDirectory.ToLower()) && commandLine.Contains(Config.Default.ServerExe.ToLower()))
{
// Does this match our server exe and port?
var serverArgMatch = String.Format(Config.Default.ServerCommandLineArgsMatchFormat, updateContext.LocalEndpoint.Port).ToLower();
if (commandLine.Contains(serverArgMatch))
{
// Was an IP set on it?
var anyIpArgMatch = String.Format(Config.Default.ServerCommandLineArgsIPMatchFormat, String.Empty).ToLower();
if (commandLine.Contains(anyIpArgMatch))
{
// If we have a specific IP, check for it.
var ipArgMatch = String.Format(Config.Default.ServerCommandLineArgsIPMatchFormat, updateContext.LocalEndpoint.Address.ToString()).ToLower();
if (!commandLine.Contains(ipArgMatch))
{
// Specific IP set didn't match
continue;
}
// Specific IP matched
}
// Either specific IP matched or no specific IP was set and we will claim this is ours.
process.EnableRaisingEvents = true;
if (process.HasExited)
{
return ServerProcessStatus.Stopped;
}
serverProcess = process;
return ServerProcessStatus.Running;
}
}
}
}
catch(Exception ex)
{
Logger.Error($"{nameof(GetServerProcessStatus)}. {ex.Message}\r\n{ex.StackTrace}");
}
return ServerProcessStatus.Stopped;
}
private async Task DoLocalUpdate()
{
try
{
foreach (var registration in this._serverRegistrations)
{
ServerStatusUpdate statusUpdate = new ServerStatusUpdate();
try
{
Logger.Info($"{nameof(DoLocalUpdate)} Start: {registration.LocalEndpoint}");
statusUpdate = await GenerateServerStatusUpdateAsync(registration);
PostServerStatusUpdate(registration, registration.UpdateCallback, statusUpdate);
}
catch (Exception ex)
{
// We don't want to stop other registration queries or break the ActionBlock
Logger.Error($"{nameof(DoLocalUpdate)} - Exception in local update. {ex.Message}\r\n{ex.StackTrace}");
Debugger.Break();
}
finally
{
Logger.Info($"{nameof(DoLocalUpdate)} End: {registration.LocalEndpoint}: {statusUpdate.Status}");
}
}
}
finally
{
Task.Delay(Config.Default.ServerStatusWatcher_LocalStatusQueryDelay).ContinueWith(_ => _eventQueue.Post(DoLocalUpdate)).DoNotWait();
}
}
private void PostServerStatusUpdate(ServerStatusUpdateRegistration registration, StatusCallback callback, ServerStatusUpdate statusUpdate)
{
_eventQueue.Post(() =>
{
if (this._serverRegistrations.Contains(registration))
{
try
{
callback(registration, statusUpdate);
}
catch (Exception ex)
{
DebugUtils.WriteFormatThreadSafeAsync("Exception during local status update callback: {0}\n{1}", ex.Message, ex.StackTrace).DoNotWait();
}
}
return TaskUtils.FinishedTask;
});
}
private async Task<ServerStatusUpdate> GenerateServerStatusUpdateAsync(ServerStatusUpdateRegistration registration)
{
var registrationKey = registration.SteamEndpoint.ToString();
//
// First check the process status
//
var processStatus = GetServerProcessStatus(registration, out Process process);
switch(processStatus)
{
case ServerProcessStatus.NotInstalled:
return new ServerStatusUpdate { Status = WatcherServerStatus.NotInstalled };
case ServerProcessStatus.Stopped:
return new ServerStatusUpdate { Status = WatcherServerStatus.Stopped };
case ServerProcessStatus.Unknown:
return new ServerStatusUpdate { Status = WatcherServerStatus.Unknown };
case ServerProcessStatus.Running:
break;
default:
Debugger.Break();
break;
}
var currentStatus = WatcherServerStatus.Initializing;
//
// If the process was running do we then perform network checks.
//
Logger.Info($"{nameof(GenerateServerStatusUpdateAsync)} Checking server local network status at {registration.LocalEndpoint}");
// get the server information direct from the server using local connection.
GetLocalNetworkStatus(registration.LocalEndpoint, out QueryMaster.ServerInfo localInfo, out int onlinePlayerCount);
if (localInfo != null)
{
currentStatus = WatcherServerStatus.RunningLocalCheck;
//
// Now that it's running, we can check the publication status.
//
Logger.Info($"{nameof(GenerateServerStatusUpdateAsync)} Checking server public status direct at {registration.SteamEndpoint}");
// get the server information direct from the server using public connection.
var serverStatus = CheckServerStatusDirect(registration.SteamEndpoint);
// check if the server returned the information.
if (!serverStatus)
{
// server did not return any information
var nextExternalStatusQuery = _nextExternalStatusQuery.ContainsKey(registrationKey) ? _nextExternalStatusQuery[registrationKey] : DateTime.MinValue;
if (DateTime.Now >= nextExternalStatusQuery)
{
currentStatus = WatcherServerStatus.RunningExternalCheck;
if (!string.IsNullOrWhiteSpace(Config.Default.ServerStatusUrlFormat))
{
Logger.Info($"{nameof(GenerateServerStatusUpdateAsync)} Checking server public status via api at {registration.SteamEndpoint}");
// get the server information direct from the server using external connection.
var uri = new Uri(string.Format(Config.Default.ServerStatusUrlFormat, Config.Default.ServerManagerCode, App.Instance.Version, registration.SteamEndpoint.Address, registration.SteamEndpoint.Port));
serverStatus = await NetworkUtils.CheckServerStatusViaAPI(uri, registration.SteamEndpoint);
}
_nextExternalStatusQuery[registrationKey] = DateTime.Now.AddMilliseconds(Config.Default.ServerStatusWatcher_RemoteStatusQueryDelay);
}
}
// check if the server returned the information.
if (serverStatus)
{
currentStatus = WatcherServerStatus.Published;
}
}
var statusUpdate = new ServerStatusUpdate
{
Process = process,
Status = currentStatus,
ServerInfo = localInfo,
OnlinePlayerCount = onlinePlayerCount
};
return await Task.FromResult(statusUpdate);
}
private static bool GetLocalNetworkStatus(IPEndPoint endpoint, out QueryMaster.ServerInfo serverInfo, out int onlinePlayerCount)
{
serverInfo = null;
onlinePlayerCount = 0;
try
{
using (var server = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endpoint))
{
try
{
serverInfo = server?.GetInfo();
}
catch (Exception)
{
serverInfo = null;
}
try
{
var players = server?.GetPlayers()?.Where(p => !string.IsNullOrWhiteSpace(p.Name?.Trim()));
onlinePlayerCount = players?.Count() ?? 0;
}
catch (Exception)
{
onlinePlayerCount = 0;
}
}
}
catch (SocketException ex)
{
Logger.Debug($"{nameof(GetLocalNetworkStatus)} failed: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
// Common when the server is unreachable. Ignore it.
}
return true;
}
private static bool CheckServerStatusDirect(IPEndPoint endpoint)
{
try
{
QueryMaster.ServerInfo serverInfo;
using (var server = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endpoint))
{
serverInfo = server.GetInfo();
}
return serverInfo != null;
}
catch (Exception ex)
{
Logger.Debug($"{nameof(CheckServerStatusDirect)} - Failed checking status direct for: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
return false;
}
}
}
}

View file

@ -0,0 +1,28 @@
using System;
using System.Windows.Data;
namespace ServerManagerTool.Lib.ViewModel
{
public class DifficultyOffsetValueConverter : IValueConverter
{
public const double MinValue = 50;
public const double MaxValue = 400;
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double scaledValue = System.Convert.ToDouble(value); ;
var sliderValue = MinValue + (scaledValue * (MaxValue - MinValue));
sliderValue = Math.Max(MinValue, sliderValue);
return sliderValue;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var sliderValue = System.Convert.ToDouble(value);
sliderValue = (double)sliderValue - (double)MinValue;
var scaledValue = sliderValue / (double)(MaxValue - MinValue);
scaledValue = Math.Max(0.01, scaledValue);
return scaledValue;
}
}
}

View file

@ -0,0 +1,20 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Lib.ViewModel
{
public class DinoNameValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var strVal = value as string;
return strVal.Substring(0, strVal.IndexOf('_'));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,38 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Lib.ViewModel
{
public class EngramClassNameToDisplayNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Convert(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public static object Convert(object value)
{
try
{
var strVal = value as string;
var name = GameData.FriendlyNameForClass(strVal);
if (!string.IsNullOrWhiteSpace(name) && !name.Equals(strVal))
return name;
var firstIndex = strVal.IndexOf('_') + 1;
var length = strVal.LastIndexOf('_') - firstIndex;
return strVal.Substring(firstIndex, length);
}
catch
{
return value;
}
}
}
}

View file

@ -0,0 +1,32 @@
using System;
using System.ComponentModel;
using WPFSharp.Globalizer;
namespace ServerManagerTool.Lib.ViewModel
{
public class EnumDescriptionTypeConverter : EnumConverter
{
public EnumDescriptionTypeConverter(Type type)
: base(type)
{
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string))
{
if (value != null)
{
var strType = value.GetType().Name;
var strVal = value.ToString();
return GlobalizedApplication.Instance.GetResourceString($"{strType}_{strVal}") ?? strVal;
}
return string.Empty;
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
}

View file

@ -0,0 +1,26 @@
using ServerManagerTool.Utils;
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Lib.ViewModel
{
public class ExtinctionEventDateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double scaledValue = System.Convert.ToInt32(value);
if (scaledValue <= 0)
return string.Empty;
var displayValue = ModUtils.UnixTimeStampToDateTime(scaledValue);
return displayValue.ToString(CultureInfo.CurrentCulture);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,32 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Lib.ViewModel
{
public class ExtinctionEventTimeIntervalConverter : IValueConverter
{
public const int MIN_VALUE = 1;
public const int MAX_VALUE = 1000;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double scaledValue = System.Convert.ToInt32(value);
var sliderValue = (int)TimeSpan.FromSeconds(scaledValue).TotalDays;
sliderValue = Math.Max(MIN_VALUE, sliderValue);
sliderValue = Math.Min(MAX_VALUE, sliderValue);
return sliderValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var sliderValue = System.Convert.ToInt32(value);
sliderValue = Math.Max(MIN_VALUE, sliderValue);
sliderValue = Math.Min(MAX_VALUE, sliderValue);
var scaledValue = (int)TimeSpan.FromDays(sliderValue).TotalSeconds;
return scaledValue;
}
}
}

View file

@ -0,0 +1,32 @@
using System;
using System.Windows.Data;
namespace ServerManagerTool.Lib.ViewModel
{
public class PlayerLevelIndexToDisplayLevelConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (int)value + 2;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class DinoLevelIndexToDisplayLevelConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (int)value + 1;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,46 @@
using ServerManagerTool.Utils;
using System;
using System.Globalization;
using System.Windows.Data;
using WPFSharp.Globalizer;
namespace ServerManagerTool.Lib.ViewModel
{
public class MapNameValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
var valueString = value as string;
if (valueString == null)
return string.Empty;
var name = GlobalizedApplication.Instance.GetResourceString(valueString);
if (!string.IsNullOrWhiteSpace(name))
return name;
var mapName = ModUtils.GetMapName(valueString);
// check if the name is stored in the globalization file
name = GlobalizedApplication.Instance.GetResourceString(mapName);
if (!string.IsNullOrWhiteSpace(name))
return name;
if (!string.IsNullOrWhiteSpace(mapName))
return mapName;
return valueString;
}
catch
{
return value ?? string.Empty;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,32 @@
using System;
using System.Windows.Data;
namespace ServerManagerTool.Lib.ViewModel
{
public class OfficialDifficultyValueConverter : IValueConverter
{
public const double DINO_LEVELS = 30.0f;
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var scaledValue = System.Convert.ToDouble(value);
scaledValue = Math.Max(1.0, scaledValue);
var sliderValue = scaledValue * DINO_LEVELS;
sliderValue = Math.Max(DINO_LEVELS, sliderValue);
return (int)sliderValue;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var sliderValue = System.Convert.ToDouble(value);
sliderValue = Math.Max(DINO_LEVELS, sliderValue);
var scaledValue = sliderValue / DINO_LEVELS;
scaledValue = Math.Max(1.0, scaledValue);
return scaledValue;
}
}
}

View file

@ -0,0 +1,38 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Lib.ViewModel
{
public class PrimalItemClassNameToDisplayNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Convert(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public static object Convert(object value)
{
try
{
var strVal = value as string;
var name = GameData.FriendlyNameForClass(strVal);
if (!string.IsNullOrWhiteSpace(name) && !name.Equals(strVal))
return name;
var firstIndex = strVal.IndexOf('_');
var lastIndex = strVal.LastIndexOf('_');
return strVal.Substring(firstIndex + 1, lastIndex - firstIndex - 1).Replace('_', ' ');
}
catch
{
return value;
}
}
}
}

View file

@ -0,0 +1,38 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Lib.ViewModel
{
public class ResourceNameValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Convert(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public static object Convert(object value)
{
try
{
var strVal = value as string;
var name = GameData.FriendlyNameForClass(strVal);
if (!string.IsNullOrWhiteSpace(name) && !name.Equals(strVal))
return name;
var firstIndex = strVal.IndexOf('_');
var lastIndex = strVal.LastIndexOf('_');
return strVal.Substring(firstIndex + 1, lastIndex - firstIndex - 1).Replace('_', ' ');
}
catch
{
return value;
}
}
}
}

View file

@ -0,0 +1,38 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Lib.ViewModel
{
public class SupplyCrateClassNameToDisplayNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Convert(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public static object Convert(object value)
{
try
{
var strVal = value as string;
var name = GameData.FriendlyNameForClass(strVal);
if (!string.IsNullOrWhiteSpace(name) && !name.Equals(strVal))
return name;
var firstIndex = strVal.IndexOf('_');
var lastIndex = strVal.LastIndexOf('_');
return strVal.Substring(0, lastIndex - firstIndex - 1).Replace('_', ' ');
}
catch
{
return value;
}
}
}
}

View file

@ -0,0 +1,32 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Lib.ViewModel
{
public class TributeExpirationConverter : IValueConverter
{
public const int MIN_VALUE = 1;
public const int MAX_VALUE = 20000;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double scaledValue = System.Convert.ToInt32(value);
var sliderValue = (int)TimeSpan.FromSeconds(scaledValue).TotalMinutes;
sliderValue = Math.Max(MIN_VALUE, sliderValue);
sliderValue = Math.Min(MAX_VALUE, sliderValue);
return sliderValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var sliderValue = System.Convert.ToInt32(value);
sliderValue = Math.Max(MIN_VALUE, sliderValue);
sliderValue = Math.Min(MAX_VALUE, sliderValue);
var scaledValue = (int)TimeSpan.FromMinutes(sliderValue).TotalSeconds;
return scaledValue;
}
}
}

View file

@ -0,0 +1,132 @@
using ServerManagerTool.Enums;
using System;
using System.Windows;
namespace ServerManagerTool.Lib.ViewModel
{
//
// This class aggregates many settings related to dinos
//
public class DinoSettings : DependencyObject
{
public static readonly DependencyProperty ClassNameProperty = DependencyProperty.Register(nameof(ClassName), typeof(string), typeof(DinoSettings), new PropertyMetadata(String.Empty));
public static readonly DependencyProperty ModProperty = DependencyProperty.Register(nameof(Mod), typeof(string), typeof(DinoSettings), new PropertyMetadata(String.Empty));
public static readonly DependencyProperty KnownDinoProperty = DependencyProperty.Register(nameof(KnownDino), typeof(bool), typeof(DinoSettings), new PropertyMetadata(false));
public static readonly DependencyProperty CanTameProperty = DependencyProperty.Register(nameof(CanTame), typeof(bool), typeof(DinoSettings), new PropertyMetadata(true));
public static readonly DependencyProperty CanSpawnProperty = DependencyProperty.Register(nameof(CanSpawn), typeof(bool), typeof(DinoSettings), new PropertyMetadata(true));
public static readonly DependencyProperty ReplacementClassProperty = DependencyProperty.Register(nameof(ReplacementClass), typeof(string), typeof(DinoSettings), new PropertyMetadata(String.Empty));
public static readonly DependencyProperty SpawnWeightMultiplierProperty = DependencyProperty.Register(nameof(SpawnWeightMultiplier), typeof(float), typeof(DinoSettings), new PropertyMetadata(DinoSpawn.DEFAULT_SPAWN_WEIGHT_MULTIPLIER));
public static readonly DependencyProperty OverrideSpawnLimitPercentageProperty = DependencyProperty.Register(nameof(OverrideSpawnLimitPercentage), typeof(bool), typeof(DinoSettings), new PropertyMetadata(DinoSpawn.DEFAULT_OVERRIDE_SPAWN_LIMIT_PERCENTAGE));
public static readonly DependencyProperty SpawnLimitPercentageProperty = DependencyProperty.Register(nameof(SpawnLimitPercentage), typeof(float), typeof(DinoSettings), new PropertyMetadata(DinoSpawn.DEFAULT_SPAWN_LIMIT_PERCENTAGE));
public static readonly DependencyProperty TamedDamageMultiplierProperty = DependencyProperty.Register(nameof(TamedDamageMultiplier), typeof(float), typeof(DinoSettings), new PropertyMetadata(ClassMultiplier.DEFAULT_MULTIPLIER));
public static readonly DependencyProperty TamedResistanceMultiplierProperty = DependencyProperty.Register(nameof(TamedResistanceMultiplier), typeof(float), typeof(DinoSettings), new PropertyMetadata(ClassMultiplier.DEFAULT_MULTIPLIER));
public static readonly DependencyProperty WildDamageMultiplierProperty = DependencyProperty.Register(nameof(WildDamageMultiplier), typeof(float), typeof(DinoSettings), new PropertyMetadata(ClassMultiplier.DEFAULT_MULTIPLIER));
public static readonly DependencyProperty WildResistanceMultiplierProperty = DependencyProperty.Register(nameof(WildResistanceMultiplier), typeof(float), typeof(DinoSettings), new PropertyMetadata(ClassMultiplier.DEFAULT_MULTIPLIER));
public string ClassName
{
get { return (string)GetValue(ClassNameProperty); }
set { SetValue(ClassNameProperty, value); }
}
public string Mod
{
get { return (string)GetValue(ModProperty); }
set { SetValue(ModProperty, value); }
}
public bool KnownDino
{
get { return (bool)GetValue(KnownDinoProperty); }
set { SetValue(KnownDinoProperty, value); }
}
public bool CanTame
{
get { return (bool)GetValue(CanTameProperty); }
set { SetValue(CanTameProperty, value); }
}
public bool CanSpawn
{
get { return (bool)GetValue(CanSpawnProperty); }
set { SetValue(CanSpawnProperty, value); }
}
public string ReplacementClass
{
get { return (string)GetValue(ReplacementClassProperty); }
set { SetValue(ReplacementClassProperty, value); }
}
public float SpawnWeightMultiplier
{
get { return (float)GetValue(SpawnWeightMultiplierProperty); }
set { SetValue(SpawnWeightMultiplierProperty, value); }
}
public bool OverrideSpawnLimitPercentage
{
get { return (bool)GetValue(OverrideSpawnLimitPercentageProperty); }
set { SetValue(OverrideSpawnLimitPercentageProperty, value); }
}
public float SpawnLimitPercentage
{
get { return (float)GetValue(SpawnLimitPercentageProperty); }
set { SetValue(SpawnLimitPercentageProperty, value); }
}
public float TamedDamageMultiplier
{
get { return (float)GetValue(TamedDamageMultiplierProperty); }
set { SetValue(TamedDamageMultiplierProperty, value); }
}
public float TamedResistanceMultiplier
{
get { return (float)GetValue(TamedResistanceMultiplierProperty); }
set { SetValue(TamedResistanceMultiplierProperty, value); }
}
public float WildDamageMultiplier
{
get { return (float)GetValue(WildDamageMultiplierProperty); }
set { SetValue(WildDamageMultiplierProperty, value); }
}
public float WildResistanceMultiplier
{
get { return (float)GetValue(WildResistanceMultiplierProperty); }
set { SetValue(WildResistanceMultiplierProperty, value); }
}
public string DisplayName => GameData.FriendlyCreatureNameForClass(ClassName);
public string DisplayMod => GameData.FriendlyNameForClass($"Mod_{Mod}", true) ?? Mod;
public string NameTag { get; internal set; }
public bool HasNameTag { get; internal set; }
public bool HasClassName { get; internal set; }
public bool IsSpawnable { get; internal set; }
public DinoTamable IsTameable { get; internal set; }
public string DisplayReplacementName => GameData.FriendlyCreatureNameForClass(ReplacementClass);
public float OriginalSpawnWeightMultiplier { get; internal set; }
public bool OriginalOverrideSpawnLimitPercentage { get; internal set; }
public float OriginalSpawnLimitPercentage { get; internal set; }
#region Sort Properties
public string NameSort => $"{DisplayName}|{Mod}";
public string ModSort => $"{Mod}|{DisplayName}";
public string CanSpawnSort => $"{IsSpawnable}|{CanSpawn}|{DisplayName}|{Mod}";
public string CanTameSort => $"{IsTameable != DinoTamable.False}|{CanTame}|{DisplayName}|{Mod}";
public string ReplacementNameSort => $"{DisplayReplacementName}|{Mod}";
public string SpawnWeightMultiplierSort => $"{SpawnWeightMultiplier:0000000000.0000000000}|{DisplayName}|{Mod}";
public string OverrideSpawnLimitPercentageSort => $"{OverrideSpawnLimitPercentage}|{DisplayName}|{Mod}";
public string SpawnLimitPercentageSort => $"{SpawnLimitPercentage:0000000000.0000000000}|{DisplayName}|{Mod}";
public string TamedDamageMultiplierSort => $"{TamedDamageMultiplier:0000000000.0000000000}|{DisplayName}|{Mod}";
public string TamedResistanceMultiplierSort => $"{TamedResistanceMultiplier:0000000000.0000000000}|{DisplayName}|{Mod}";
public string WildDamageMultiplierSort => $"{WildDamageMultiplier:0000000000.0000000000}|{DisplayName}|{Mod}";
public string WildResistanceMultiplierSort => $"{WildResistanceMultiplier:0000000000.0000000000}|{DisplayName}|{Mod}";
#endregion
}
}

View file

@ -0,0 +1,316 @@
using ServerManagerTool.Common.Model;
using ServerManagerTool.Enums;
using System;
using System.Linq;
namespace ServerManagerTool.Lib.ViewModel
{
public class DinoSettingsList : SortableObservableCollection<DinoSettings>
{
public AggregateIniValueList<DinoSpawn> DinoSpawnWeightMultipliers { get; }
public StringIniValueList PreventDinoTameClassNames { get; }
public AggregateIniValueList<NPCReplacement> NpcReplacements { get; }
public AggregateIniValueList<ClassMultiplier> TamedDinoClassDamageMultipliers { get; }
public AggregateIniValueList<ClassMultiplier> TamedDinoClassResistanceMultipliers { get; }
public AggregateIniValueList<ClassMultiplier> DinoClassDamageMultipliers { get; }
public AggregateIniValueList<ClassMultiplier> DinoClassResistanceMultipliers { get; }
public DinoSettingsList()
{
Reset();
}
public DinoSettingsList(AggregateIniValueList<DinoSpawn> dinoSpawnWeightMultipliers, StringIniValueList preventDinoTameClassNames, AggregateIniValueList<NPCReplacement> npcReplacements,
AggregateIniValueList<ClassMultiplier> tamedDinoClassDamageMultipliers, AggregateIniValueList<ClassMultiplier> tamedDinoClassResistanceMultipliers,
AggregateIniValueList<ClassMultiplier> dinoClassDamageMultipliers, AggregateIniValueList<ClassMultiplier> dinoClassResistanceMultipliers)
{
this.DinoSpawnWeightMultipliers = dinoSpawnWeightMultipliers;
this.PreventDinoTameClassNames = preventDinoTameClassNames;
this.NpcReplacements = npcReplacements;
this.TamedDinoClassDamageMultipliers = tamedDinoClassDamageMultipliers;
this.TamedDinoClassResistanceMultipliers = tamedDinoClassResistanceMultipliers;
this.DinoClassDamageMultipliers = dinoClassDamageMultipliers;
this.DinoClassResistanceMultipliers = dinoClassResistanceMultipliers;
Reset();
}
private DinoSettings CreateDinoSetting(string className, string mod, bool knownDino, bool hasNameTag, bool hasClassName)
{
var nameTag = GameData.NameTagForClass(className);
var isSpawnable = GameData.IsSpawnableForClass(className);
var isTameable = GameData.IsTameableForClass(className);
return new DinoSettings()
{
ClassName = className,
Mod = mod,
KnownDino = knownDino,
NameTag = nameTag,
CanSpawn = true,
CanTame = isTameable != DinoTamable.False,
ReplacementClass = className,
SpawnWeightMultiplier = DinoSpawn.DEFAULT_SPAWN_WEIGHT_MULTIPLIER,
OverrideSpawnLimitPercentage = DinoSpawn.DEFAULT_OVERRIDE_SPAWN_LIMIT_PERCENTAGE,
SpawnLimitPercentage = DinoSpawn.DEFAULT_SPAWN_LIMIT_PERCENTAGE,
OriginalSpawnWeightMultiplier = DinoSpawn.DEFAULT_SPAWN_WEIGHT_MULTIPLIER,
OriginalOverrideSpawnLimitPercentage = DinoSpawn.DEFAULT_OVERRIDE_SPAWN_LIMIT_PERCENTAGE,
OriginalSpawnLimitPercentage = DinoSpawn.DEFAULT_SPAWN_LIMIT_PERCENTAGE,
TamedDamageMultiplier = ClassMultiplier.DEFAULT_MULTIPLIER,
TamedResistanceMultiplier = ClassMultiplier.DEFAULT_MULTIPLIER,
WildDamageMultiplier = ClassMultiplier.DEFAULT_MULTIPLIER,
WildResistanceMultiplier = ClassMultiplier.DEFAULT_MULTIPLIER,
HasClassName = hasClassName,
HasNameTag = hasNameTag,
IsSpawnable = isSpawnable,
IsTameable = isTameable,
};
}
public void Reset()
{
this.Clear();
var dinoSpawns = GameData.GetDinoSpawns();
foreach (var entry in dinoSpawns)
{
this.Add(CreateDinoSetting(entry.ClassName, entry.Mod, entry.KnownDino, entry.DinoNameTag != null, true));
}
Sort(d => d.NameSort);
}
public void RenderToView()
{
Reset();
foreach(var entry in this.DinoSpawnWeightMultipliers)
{
if (string.IsNullOrWhiteSpace(entry.DinoNameTag))
continue;
var dinoSettings = this.Where(vi => vi.NameTag == entry.DinoNameTag).ToArray();
if (dinoSettings == null || dinoSettings.Length == 0)
{
this.Add(CreateDinoSetting(entry.DinoNameTag, entry.Mod, entry.KnownDino, true, false));
}
dinoSettings = this.Where(vi => vi.NameTag == entry.DinoNameTag).ToArray();
foreach (var dinoSetting in dinoSettings)
{
dinoSetting.SpawnWeightMultiplier = entry.SpawnWeightMultiplier;
dinoSetting.OverrideSpawnLimitPercentage = entry.OverrideSpawnLimitPercentage;
dinoSetting.SpawnLimitPercentage = entry.SpawnLimitPercentage;
dinoSetting.OriginalSpawnWeightMultiplier = entry.SpawnWeightMultiplier;
dinoSetting.OriginalOverrideSpawnLimitPercentage = entry.OverrideSpawnLimitPercentage;
dinoSetting.OriginalSpawnLimitPercentage = entry.SpawnLimitPercentage;
}
}
foreach(var entry in this.PreventDinoTameClassNames)
{
if (string.IsNullOrWhiteSpace(entry))
continue;
var dinoSettings = this.Where(vi => vi.ClassName == entry).ToArray();
if (dinoSettings == null || dinoSettings.Length == 0)
{
this.Add(CreateDinoSetting(entry, GameData.MOD_UNKNOWN, false, false, true));
}
dinoSettings = this.Where(vi => vi.ClassName == entry).ToArray();
foreach (var dinoSetting in dinoSettings)
{
dinoSetting.CanTame = false;
}
}
foreach(var entry in this.NpcReplacements)
{
if (string.IsNullOrWhiteSpace(entry.FromClassName))
continue;
var dinoSettings = this.Where(vi => vi.ClassName == entry.FromClassName).ToArray();
if (dinoSettings == null || dinoSettings.Length == 0)
{
this.Add(CreateDinoSetting(entry.FromClassName, GameData.MOD_UNKNOWN, false, false, true));
}
dinoSettings = this.Where(vi => vi.ClassName == entry.FromClassName).ToArray();
foreach (var dinoSetting in dinoSettings)
{
dinoSetting.CanSpawn = !string.IsNullOrWhiteSpace(entry.ToClassName);
dinoSetting.ReplacementClass = dinoSetting.CanSpawn ? entry.ToClassName : dinoSetting.ClassName;
}
}
foreach (var entry in this.TamedDinoClassDamageMultipliers)
{
if (string.IsNullOrWhiteSpace(entry.ClassName))
continue;
var dinoSettings = this.Where(vi => vi.ClassName == entry.ClassName).ToArray();
if (dinoSettings == null || dinoSettings.Length == 0)
{
this.Add(CreateDinoSetting(entry.ClassName, GameData.MOD_UNKNOWN, false, false, true));
}
dinoSettings = this.Where(vi => vi.ClassName == entry.ClassName).ToArray();
foreach (var dinoSetting in dinoSettings)
{
dinoSetting.TamedDamageMultiplier = entry.Multiplier;
}
}
foreach(var entry in this.TamedDinoClassResistanceMultipliers)
{
if (string.IsNullOrWhiteSpace(entry.ClassName))
continue;
var dinoSettings = this.Where(vi => vi.ClassName == entry.ClassName).ToArray();
if (dinoSettings == null || dinoSettings.Length == 0)
{
this.Add(CreateDinoSetting(entry.ClassName, GameData.MOD_UNKNOWN, false, false, true));
}
dinoSettings = this.Where(vi => vi.ClassName == entry.ClassName).ToArray();
foreach (var dinoSetting in dinoSettings)
{
dinoSetting.TamedResistanceMultiplier = entry.Multiplier;
}
}
foreach (var entry in this.DinoClassDamageMultipliers)
{
if (string.IsNullOrWhiteSpace(entry.ClassName))
continue;
var dinoSettings = this.Where(vi => vi.ClassName == entry.ClassName).ToArray();
if (dinoSettings == null || dinoSettings.Length == 0)
{
this.Add(CreateDinoSetting(entry.ClassName, GameData.MOD_UNKNOWN, false, false, true));
}
dinoSettings = this.Where(vi => vi.ClassName == entry.ClassName).ToArray();
foreach (var dinoSetting in dinoSettings)
{
dinoSetting.WildDamageMultiplier = entry.Multiplier;
}
}
foreach (var entry in this.DinoClassResistanceMultipliers)
{
if (string.IsNullOrWhiteSpace(entry.ClassName))
continue;
var dinoSettings = this.Where(vi => vi.ClassName == entry.ClassName).ToArray();
if (dinoSettings == null || dinoSettings.Length == 0)
{
this.Add(CreateDinoSetting(entry.ClassName, GameData.MOD_UNKNOWN, false, false, true));
}
dinoSettings = this.Where(vi => vi.ClassName == entry.ClassName).ToArray();
foreach (var dinoSetting in dinoSettings)
{
dinoSetting.WildResistanceMultiplier = entry.Multiplier;
}
}
Sort(d => d.NameSort);
}
public void RenderToModel()
{
this.DinoSpawnWeightMultipliers.Clear();
this.PreventDinoTameClassNames.Clear();
this.PreventDinoTameClassNames.IsEnabled = true;
this.NpcReplacements.Clear();
this.NpcReplacements.IsEnabled = true;
this.TamedDinoClassDamageMultipliers.Clear();
this.TamedDinoClassResistanceMultipliers.Clear();
this.DinoClassDamageMultipliers.Clear();
this.DinoClassResistanceMultipliers.Clear();
foreach(var entry in this)
{
if (entry.HasNameTag && !string.IsNullOrWhiteSpace(entry.NameTag))
{
if (!entry.KnownDino ||
!entry.OverrideSpawnLimitPercentage.Equals(DinoSpawn.DEFAULT_OVERRIDE_SPAWN_LIMIT_PERCENTAGE) ||
!entry.SpawnLimitPercentage.Equals(DinoSpawn.DEFAULT_SPAWN_LIMIT_PERCENTAGE) ||
!entry.SpawnWeightMultiplier.Equals(DinoSpawn.DEFAULT_SPAWN_WEIGHT_MULTIPLIER))
{
var dinoSpawns = this.DinoSpawnWeightMultipliers.Where(d => d.DinoNameTag.Equals(entry.NameTag, StringComparison.OrdinalIgnoreCase)).ToArray();
if (dinoSpawns == null || dinoSpawns.Length == 0)
{
this.DinoSpawnWeightMultipliers.Add(new DinoSpawn()
{
ClassName = entry.ClassName,
DinoNameTag = entry.NameTag,
OverrideSpawnLimitPercentage = entry.OverrideSpawnLimitPercentage,
SpawnLimitPercentage = entry.SpawnLimitPercentage,
SpawnWeightMultiplier = entry.SpawnWeightMultiplier
});
}
else
{
foreach (var dinoSpawn in dinoSpawns)
{
if (entry.SpawnWeightMultiplier != entry.OriginalSpawnWeightMultiplier ||
entry.OverrideSpawnLimitPercentage != entry.OriginalOverrideSpawnLimitPercentage ||
entry.SpawnLimitPercentage != entry.OriginalSpawnLimitPercentage)
{
dinoSpawn.OverrideSpawnLimitPercentage = entry.OverrideSpawnLimitPercentage;
dinoSpawn.SpawnLimitPercentage = entry.SpawnLimitPercentage;
dinoSpawn.SpawnWeightMultiplier = entry.SpawnWeightMultiplier;
}
}
}
}
}
if (entry.HasClassName && !string.IsNullOrWhiteSpace(entry.ClassName))
{
if ((entry.IsTameable != DinoTamable.False) && !entry.CanTame)
{
this.PreventDinoTameClassNames.Add(entry.ClassName);
}
this.NpcReplacements.Add(new NPCReplacement() { FromClassName = entry.ClassName, ToClassName = entry.CanSpawn ? entry.ReplacementClass : string.Empty });
if (entry.IsTameable != DinoTamable.False)
{
// check if the value has changed.
if (!entry.TamedDamageMultiplier.Equals(ClassMultiplier.DEFAULT_MULTIPLIER))
this.TamedDinoClassDamageMultipliers.Add(new ClassMultiplier() { ClassName = entry.ClassName, Multiplier = entry.TamedDamageMultiplier });
// check if the value has changed.
if (!entry.TamedResistanceMultiplier.Equals(ClassMultiplier.DEFAULT_MULTIPLIER))
this.TamedDinoClassResistanceMultipliers.Add(new ClassMultiplier() { ClassName = entry.ClassName, Multiplier = entry.TamedResistanceMultiplier });
}
// check if the value has changed.
if (!entry.WildDamageMultiplier.Equals(ClassMultiplier.DEFAULT_MULTIPLIER))
this.DinoClassDamageMultipliers.Add(new ClassMultiplier() { ClassName = entry.ClassName, Multiplier = entry.WildDamageMultiplier });
// check if the value has changed.
if (!entry.WildResistanceMultiplier.Equals(ClassMultiplier.DEFAULT_MULTIPLIER))
this.DinoClassResistanceMultipliers.Add(new ClassMultiplier() { ClassName = entry.ClassName, Multiplier = entry.WildResistanceMultiplier });
}
}
}
public void UpdateForLocalization()
{
//foreach (var dinoSetting in this)
//{
// dinoSetting.FriendlyName = GameData.FriendlyNameForClass(dinoSetting.ClassName);
//}
}
}
}

View file

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace ServerManagerTool.Lib.ViewModel
{
public class Engram : DependencyObject
{
public static readonly DependencyProperty EngramClassNameProperty = DependencyProperty.Register(nameof(EngramClassName), typeof(string), typeof(Engram), new PropertyMetadata(String.Empty));
public static readonly DependencyProperty EngramLevelRequirementProperty = DependencyProperty.Register(nameof(EngramLevelRequirement), typeof(int), typeof(Engram), new PropertyMetadata(0));
public static readonly DependencyProperty EngramPointsCostProperty = DependencyProperty.Register(nameof(EngramPointsCost), typeof(int), typeof(Engram), new PropertyMetadata(0));
public static readonly DependencyProperty ModProperty = DependencyProperty.Register(nameof(Mod), typeof(string), typeof(Engram), new PropertyMetadata(String.Empty));
public static readonly DependencyProperty KnownEngramProperty = DependencyProperty.Register(nameof(KnownEngram), typeof(bool), typeof(Engram), new PropertyMetadata(false));
public static readonly DependencyProperty IsTekgramProperty = DependencyProperty.Register(nameof(IsTekgram), typeof(bool), typeof(EngramEntry), new PropertyMetadata(false));
public string EngramClassName
{
get { return (string)GetValue(EngramClassNameProperty); }
set { SetValue(EngramClassNameProperty, value); }
}
public int EngramLevelRequirement
{
get { return (int)GetValue(EngramLevelRequirementProperty); }
set { SetValue(EngramLevelRequirementProperty, value); }
}
public int EngramPointsCost
{
get { return (int)GetValue(EngramPointsCostProperty); }
set { SetValue(EngramPointsCostProperty, value); }
}
public string Mod
{
get { return (string)GetValue(ModProperty); }
set { SetValue(ModProperty, value); }
}
public bool KnownEngram
{
get { return (bool)GetValue(KnownEngramProperty); }
set { SetValue(KnownEngramProperty, value); }
}
public bool IsTekgram
{
get { return (bool)GetValue(IsTekgramProperty); }
set { SetValue(IsTekgramProperty, value); }
}
public string DisplayName => GameData.FriendlyEngramNameForClass(EngramClassName);
public string DisplayMod => GameData.FriendlyNameForClass($"Mod_{Mod}", true) ?? Mod;
public Engram Duplicate()
{
var properties = this.GetType().GetProperties();
var result = new Engram();
foreach (var prop in properties)
{
if (prop.CanWrite)
prop.SetValue(result, prop.GetValue(this));
}
return result;
}
}
}

View file

@ -0,0 +1,362 @@
using ServerManagerTool.Common.Model;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Windows;
namespace ServerManagerTool.Lib.ViewModel
{
[DataContract]
public class EngramSettingsList : SortableObservableCollection<EngramSettings>, INotifyPropertyChanged
{
internal EngramSettingsList()
{
Reset();
}
public EngramSettingsList(EngramEntryList overrideNamedEngramEntries, EngramAutoUnlockList engramEntryAutoUnlocks)
{
OverrideNamedEngramEntries = overrideNamedEngramEntries;
EngramEntryAutoUnlocks = engramEntryAutoUnlocks;
Reset();
}
public bool IsEnabled
{
get { return Get<bool>(); }
set { Set(value); }
}
[DataMember]
public bool OnlyAllowSpecifiedEngrams
{
get { return Get<bool>(); }
set { Set(value); }
}
public EngramEntryList OverrideNamedEngramEntries { get; }
public EngramAutoUnlockList EngramEntryAutoUnlocks { get; }
public EngramSettings CreateEngramSetting(string className, string mod, bool knownEngram, bool isTekgram)
{
return new EngramSettings()
{
EngramClassName = className,
Mod = mod,
KnownEngram = knownEngram,
IsTekgram = isTekgram,
};
}
public void Reset()
{
this.Clear();
IsEnabled = false;
var engrams = GameData.GetEngrams();
foreach (var engram in engrams)
{
var engramSetting = CreateEngramSetting(engram.EngramClassName, engram.Mod, engram.KnownEngram, engram.IsTekgram);
engramSetting.EngramLevelRequirement = engram.EngramLevelRequirement;
engramSetting.EngramPointsCost = engram.EngramPointsCost;
engramSetting.LevelToAutoUnlock = engram.EngramLevelRequirement;
this.Add(engramSetting);
}
}
public void RenderToView()
{
Reset();
if (this.OverrideNamedEngramEntries != null)
{
foreach (var entry in this.OverrideNamedEngramEntries)
{
if (string.IsNullOrWhiteSpace(entry.EngramClassName))
continue;
var engramSettings = this.Where(vi => vi.EngramClassName == entry.EngramClassName).ToArray();
if (engramSettings == null || engramSettings.Length == 0)
{
var engram = GameData.GetEngramForClass(entry.EngramClassName);
this.Add(CreateEngramSetting(entry.EngramClassName, engram?.Mod ?? GameData.MOD_UNKNOWN, engram?.KnownEngram ?? false, engram?.IsTekgram ?? false));
}
engramSettings = this.Where(vi => vi.EngramClassName == entry.EngramClassName).ToArray();
foreach (var engramSetting in engramSettings)
{
engramSetting.EngramLevelRequirement = entry.EngramLevelRequirement;
engramSetting.EngramPointsCost = entry.EngramPointsCost;
engramSetting.EngramHidden = entry.EngramHidden;
engramSetting.RemoveEngramPreReq = entry.RemoveEngramPreReq;
engramSetting.LevelToAutoUnlock = entry.EngramLevelRequirement;
engramSetting.SaveEngramOverride = true;
if (engramSetting.IsTekgram)
{
// always make sure that the tekgrams have default values.
engramSetting.EngramLevelRequirement = 0;
engramSetting.EngramPointsCost = 0;
engramSetting.LevelToAutoUnlock = 0;
}
IsEnabled = true;
}
}
}
if (this.EngramEntryAutoUnlocks != null)
{
foreach (var entry in this.EngramEntryAutoUnlocks)
{
if (string.IsNullOrWhiteSpace(entry.EngramClassName))
continue;
var engramSettings = this.Where(vi => vi.EngramClassName == entry.EngramClassName).ToArray();
if (engramSettings == null || engramSettings.Length == 0)
{
var engram = GameData.GetEngramForClass(entry.EngramClassName);
this.Add(CreateEngramSetting(entry.EngramClassName, engram?.Mod ?? GameData.MOD_UNKNOWN, engram?.KnownEngram ?? false, engram?.IsTekgram ?? false));
}
engramSettings = this.Where(vi => vi.EngramClassName == entry.EngramClassName).ToArray();
foreach (var engramSetting in engramSettings)
{
engramSetting.EngramAutoUnlock = true;
engramSetting.LevelToAutoUnlock = entry.LevelToAutoUnlock;
engramSetting.SaveEngramOverride = true;
IsEnabled = true;
}
}
}
}
public void RenderToModel()
{
if (this.OverrideNamedEngramEntries != null)
{
this.OverrideNamedEngramEntries.Clear();
this.OverrideNamedEngramEntries.IsEnabled = false;
}
if (this.EngramEntryAutoUnlocks != null)
{
this.EngramEntryAutoUnlocks.Clear();
this.EngramEntryAutoUnlocks.IsEnabled = false;
}
if (!IsEnabled)
return;
foreach (var entry in this)
{
if (!entry.IsValid)
continue;
if (!string.IsNullOrWhiteSpace(entry.EngramClassName))
{
if (this.OverrideNamedEngramEntries != null && entry.ShouldSaveEngramEntry(OnlyAllowSpecifiedEngrams))
{
this.OverrideNamedEngramEntries.Add(entry.GetEngramEntry());
this.OverrideNamedEngramEntries.IsEnabled = true;
}
if (this.EngramEntryAutoUnlocks != null && entry.ShouldSaveEngramAutoUnlock(OnlyAllowSpecifiedEngrams))
{
this.EngramEntryAutoUnlocks.Add(entry.GetEngramAutoUnlock());
this.EngramEntryAutoUnlocks.IsEnabled = true;
}
}
}
}
public void UpdateForLocalization()
{
}
#region INotifyPropertyChanged
private Dictionary<string, object> _properties = new Dictionary<string, object>();
protected T Get<T>([CallerMemberName] string name = null)
{
object value = null;
if (_properties?.TryGetValue(name, out value) ?? false)
return value == null ? default : (T)value;
return default;
}
protected void Set<T>(T value, [CallerMemberName] string name = null)
{
if (Equals(value, Get<T>(name)))
return;
if (_properties == null)
_properties = new Dictionary<string, object>();
_properties[name] = value;
OnPropertyChanged(new PropertyChangedEventArgs(name));
}
#endregion
}
[DataContract]
public class EngramSettings : DependencyObject
{
public static readonly DependencyProperty EngramClassNameProperty = DependencyProperty.Register(nameof(EngramClassName), typeof(string), typeof(EngramSettings), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty ModProperty = DependencyProperty.Register(nameof(Mod), typeof(string), typeof(EngramSettings), new PropertyMetadata(GameData.MOD_UNKNOWN));
public static readonly DependencyProperty KnownEngramProperty = DependencyProperty.Register(nameof(KnownEngram), typeof(bool), typeof(EngramSettings), new PropertyMetadata(false));
public static readonly DependencyProperty IsTekgramProperty = DependencyProperty.Register(nameof(IsTekgram), typeof(bool), typeof(EngramSettings), new PropertyMetadata(false));
public static readonly DependencyProperty EngramLevelRequirementProperty = DependencyProperty.Register(nameof(EngramLevelRequirement), typeof(int), typeof(EngramSettings), new PropertyMetadata(0));
public static readonly DependencyProperty EngramPointsCostProperty = DependencyProperty.Register(nameof(EngramPointsCost), typeof(int), typeof(EngramSettings), new PropertyMetadata(0));
public static readonly DependencyProperty EngramHiddenProperty = DependencyProperty.Register(nameof(EngramHidden), typeof(bool), typeof(EngramSettings), new PropertyMetadata(false));
public static readonly DependencyProperty RemoveEngramPreReqProperty = DependencyProperty.Register(nameof(RemoveEngramPreReq), typeof(bool), typeof(EngramSettings), new PropertyMetadata(false));
public static readonly DependencyProperty EngramAutoUnlockProperty = DependencyProperty.Register(nameof(EngramAutoUnlock), typeof(bool), typeof(EngramSettings), new PropertyMetadata(false));
public static readonly DependencyProperty LevelToAutoUnlockProperty = DependencyProperty.Register(nameof(LevelToAutoUnlock), typeof(int), typeof(EngramSettings), new PropertyMetadata(0));
public static readonly DependencyProperty SaveEngramOverrideProperty = DependencyProperty.Register(nameof(SaveEngramOverride), typeof(bool), typeof(EngramSettings), new PropertyMetadata(false));
[DataMember]
public string EngramClassName
{
get { return (string)GetValue(EngramClassNameProperty); }
set { SetValue(EngramClassNameProperty, value); }
}
[DataMember]
public string Mod
{
get { return (string)GetValue(ModProperty); }
set { SetValue(ModProperty, value); }
}
public bool KnownEngram
{
get { return (bool)GetValue(KnownEngramProperty); }
set { SetValue(KnownEngramProperty, value); }
}
[DataMember]
public bool IsTekgram
{
get { return (bool)GetValue(IsTekgramProperty); }
set { SetValue(IsTekgramProperty, value); }
}
public bool IsValid => !string.IsNullOrWhiteSpace(EngramClassName);
[DataMember]
public int EngramLevelRequirement
{
get { return (int)GetValue(EngramLevelRequirementProperty); }
set { SetValue(EngramLevelRequirementProperty, value); }
}
[DataMember]
public int EngramPointsCost
{
get { return (int)GetValue(EngramPointsCostProperty); }
set { SetValue(EngramPointsCostProperty, value); }
}
[DataMember]
public bool EngramHidden
{
get { return (bool)GetValue(EngramHiddenProperty); }
set { SetValue(EngramHiddenProperty, value); }
}
[DataMember]
public bool RemoveEngramPreReq
{
get { return (bool)GetValue(RemoveEngramPreReqProperty); }
set { SetValue(RemoveEngramPreReqProperty, value); }
}
[DataMember]
public bool EngramAutoUnlock
{
get { return (bool)GetValue(EngramAutoUnlockProperty); }
set { SetValue(EngramAutoUnlockProperty, value); }
}
[DataMember]
public int LevelToAutoUnlock
{
get { return (int)GetValue(LevelToAutoUnlockProperty); }
set { SetValue(LevelToAutoUnlockProperty, value); }
}
[DataMember]
public bool SaveEngramOverride
{
get { return (bool)GetValue(SaveEngramOverrideProperty); }
set { SetValue(SaveEngramOverrideProperty, value); }
}
public string DisplayName => GameData.FriendlyEngramNameForClass(EngramClassName);
public string DisplayMod => GameData.FriendlyNameForClass($"Mod_{Mod}", true) ?? Mod;
public bool ShouldSaveEngramEntry(bool onlyAllowSpecifiedEngrams)
{
if (onlyAllowSpecifiedEngrams)
return SaveEngramOverride;
var engramEntry = GameData.GetEngramForClass(EngramClassName);
if (engramEntry == null)
engramEntry = new Engram();
var engramLevelRequirement = IsTekgram ? 0 : EngramLevelRequirement;
var engramPointsCost = IsTekgram ? 0 : EngramPointsCost;
var engramHidden = EngramHidden;
var removeEngramPreReq = RemoveEngramPreReq;
return (!engramLevelRequirement.Equals(engramEntry.EngramLevelRequirement) ||
!engramPointsCost.Equals(engramEntry.EngramPointsCost) ||
engramHidden ||
removeEngramPreReq);
}
public bool ShouldSaveEngramAutoUnlock(bool onlyAllowSpecifiedEngrams)
{
if (onlyAllowSpecifiedEngrams && !SaveEngramOverride)
return false;
return EngramAutoUnlock;
}
public EngramEntry GetEngramEntry()
{
var engramEntry = new EngramEntry() { EngramClassName = this.EngramClassName, EngramLevelRequirement = this.EngramLevelRequirement, EngramPointsCost = this.EngramPointsCost, EngramHidden = this.EngramHidden, RemoveEngramPreReq = this.RemoveEngramPreReq };
if (IsTekgram)
{
// always make sure that the tekgrams have default values.
engramEntry.EngramLevelRequirement = 0;
engramEntry.EngramPointsCost = 0;
}
return engramEntry;
}
public EngramAutoUnlock GetEngramAutoUnlock()
{
var engramEntry = new EngramAutoUnlock() { EngramClassName = this.EngramClassName, LevelToAutoUnlock = this.LevelToAutoUnlock };
return engramEntry;
}
#region Sort Properties
public string SaveEngramOverrideSort => $"{SaveEngramOverride}|{IsTekgram}|{DisplayName}|{Mod}";
public string NameSort => $"{DisplayName}|{Mod}";
public string ModSort => $"{Mod}|{IsTekgram}|{DisplayName}";
public string IsTekgramSort => $"{IsTekgram}|{DisplayName}|{Mod}";
public string EngramLevelRequirementSort => $"{EngramLevelRequirement:0000000000}|{IsTekgram}|{DisplayName}|{Mod}";
public string EngramPointsCostSort => $"{EngramPointsCost:0000000000}|{IsTekgram}|{DisplayName}|{Mod}";
public string EngramHiddenSort => $"{EngramHidden}|{IsTekgram}|{DisplayName}|{Mod}";
public string RemoveEngramPreReqSort => $"{RemoveEngramPreReq}|{IsTekgram}|{DisplayName}|{Mod}";
public string EngramAutoUnlockSort => $"{EngramAutoUnlock}|{IsTekgram}|{DisplayName}|{Mod}";
public string LevelToAutoUnlockSort => $"{LevelToAutoUnlock:0000000000}|{IsTekgram}|{DisplayName}|{Mod}";
#endregion
}
}

View file

@ -0,0 +1,48 @@
using System;
using System.Windows;
namespace ServerManagerTool.Lib.ViewModel
{
public class MapSpawner : DependencyObject
{
public static readonly DependencyProperty ClassNameProperty = DependencyProperty.Register(nameof(ClassName), typeof(string), typeof(MapSpawner), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty ModProperty = DependencyProperty.Register(nameof(Mod), typeof(string), typeof(MapSpawner), new PropertyMetadata(String.Empty));
public static readonly DependencyProperty KnownSpawnerProperty = DependencyProperty.Register(nameof(KnownSpawner), typeof(bool), typeof(MapSpawner), new PropertyMetadata(false));
public string ClassName
{
get { return (string)GetValue(ClassNameProperty); }
set { SetValue(ClassNameProperty, value); }
}
public string Mod
{
get { return (string)GetValue(ModProperty); }
set { SetValue(ModProperty, value); }
}
public bool KnownSpawner
{
get { return (bool)GetValue(KnownSpawnerProperty); }
set { SetValue(KnownSpawnerProperty, value); }
}
public string DisplayName => GameData.FriendlyMapSpawnerNameForClass(ClassName);
public string DisplayMod => GameData.FriendlyNameForClass($"Mod_{Mod}", true) ?? Mod;
public MapSpawner Duplicate()
{
var properties = this.GetType().GetProperties();
var result = new MapSpawner();
foreach (var prop in properties)
{
if (prop.CanWrite)
prop.SetValue(result, prop.GetValue(this));
}
return result;
}
}
}

View file

@ -0,0 +1,319 @@
using ServerManagerTool.Common.Model;
using ServerManagerTool.Enums;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
namespace ServerManagerTool.Lib.ViewModel
{
public class NPCSpawnSettingsList : SortableObservableCollection<NPCSpawnSettings>
{
public NPCSpawnContainerList<NPCSpawnContainer> ConfigAddNPCSpawnEntriesContainer { get; }
public NPCSpawnContainerList<NPCSpawnContainer> ConfigSubtractNPCSpawnEntriesContainer { get; }
public NPCSpawnContainerList<NPCSpawnContainer> ConfigOverrideNPCSpawnEntriesContainer { get; }
public NPCSpawnSettingsList()
{
Reset();
}
public NPCSpawnSettingsList(NPCSpawnContainerList<NPCSpawnContainer> configAddNPCSpawnEntriesContainer,
NPCSpawnContainerList<NPCSpawnContainer> configSubtractNPCSpawnEntriesContainer,
NPCSpawnContainerList<NPCSpawnContainer> configOverrideNPCSpawnEntriesContainer)
{
ConfigAddNPCSpawnEntriesContainer = configAddNPCSpawnEntriesContainer;
ConfigSubtractNPCSpawnEntriesContainer = configSubtractNPCSpawnEntriesContainer;
ConfigOverrideNPCSpawnEntriesContainer = configOverrideNPCSpawnEntriesContainer;
Reset();
}
public void Reset()
{
this.Clear();
}
public void RenderToView()
{
Reset();
foreach (var entry in this.ConfigAddNPCSpawnEntriesContainer)
{
if (!entry.IsValid)
continue;
var spawnSettings = new NPCSpawnSettings
{
UniqueId = entry.UniqueId,
ContainerType = NPCSpawnContainerType.Add,
NPCSpawnEntriesContainerClassString = entry.NPCSpawnEntriesContainerClassString,
};
foreach (var item in entry.NPCSpawnEntries)
{
spawnSettings.NPCSpawnEntrySettings.Add(new NPCSpawnEntrySettings
{
AnEntryName = item.AnEntryName,
NPCClassString = item.NPCsToSpawnStrings,
EntryWeight = item.EntryWeight,
});
}
foreach (var item in entry.NPCSpawnLimits)
{
var temp = spawnSettings.NPCSpawnEntrySettings.FirstOrDefault(i => i.NPCClassString.Equals(item.NPCClassString));
if (temp == null)
continue;
temp.MaxPercentageOfDesiredNumToAllow = item.MaxPercentageOfDesiredNumToAllow;
}
this.Add(spawnSettings);
}
foreach (var entry in this.ConfigSubtractNPCSpawnEntriesContainer)
{
if (!entry.IsValid)
continue;
var spawnSettings = new NPCSpawnSettings
{
UniqueId = entry.UniqueId,
ContainerType = NPCSpawnContainerType.Subtract,
NPCSpawnEntriesContainerClassString = entry.NPCSpawnEntriesContainerClassString,
};
foreach (var item in entry.NPCSpawnEntries)
{
spawnSettings.NPCSpawnEntrySettings.Add(new NPCSpawnEntrySettings
{
AnEntryName = item.AnEntryName,
NPCClassString = item.NPCsToSpawnStrings,
EntryWeight = item.EntryWeight,
});
}
foreach (var item in entry.NPCSpawnLimits)
{
var temp = spawnSettings.NPCSpawnEntrySettings.FirstOrDefault(i => i.NPCClassString.Equals(item.NPCClassString));
if (temp == null)
continue;
temp.MaxPercentageOfDesiredNumToAllow = item.MaxPercentageOfDesiredNumToAllow;
}
this.Add(spawnSettings);
}
foreach (var entry in this.ConfigOverrideNPCSpawnEntriesContainer)
{
if (!entry.IsValid)
continue;
var spawnSettings = new NPCSpawnSettings
{
UniqueId = entry.UniqueId,
ContainerType = NPCSpawnContainerType.Override,
NPCSpawnEntriesContainerClassString = entry.NPCSpawnEntriesContainerClassString,
};
foreach (var item in entry.NPCSpawnEntries)
{
spawnSettings.NPCSpawnEntrySettings.Add(new NPCSpawnEntrySettings
{
AnEntryName = item.AnEntryName,
NPCClassString = item.NPCsToSpawnStrings,
EntryWeight = item.EntryWeight,
});
}
foreach (var item in entry.NPCSpawnLimits)
{
var temp = spawnSettings.NPCSpawnEntrySettings.FirstOrDefault(i => i.NPCClassString.Equals(item.NPCClassString));
if (temp == null)
continue;
temp.MaxPercentageOfDesiredNumToAllow = item.MaxPercentageOfDesiredNumToAllow;
}
this.Add(spawnSettings);
}
}
public void RenderToModel()
{
this.ConfigAddNPCSpawnEntriesContainer.Clear();
this.ConfigSubtractNPCSpawnEntriesContainer.Clear();
this.ConfigOverrideNPCSpawnEntriesContainer.Clear();
this.ConfigAddNPCSpawnEntriesContainer.IsEnabled = false;
this.ConfigSubtractNPCSpawnEntriesContainer.IsEnabled = false;
this.ConfigOverrideNPCSpawnEntriesContainer.IsEnabled = false;
foreach (var entry in this)
{
if (!entry.IsValid)
continue;
var spawnContainer = new NPCSpawnContainer
{
UniqueId = entry.UniqueId,
NPCSpawnEntriesContainerClassString = entry.NPCSpawnEntriesContainerClassString,
};
spawnContainer.NPCSpawnEntries.AddRange(entry.NPCSpawnEntrySettings.Where(s => s.IsValid).Select(s => new NPCSpawnEntry
{
AnEntryName = string.IsNullOrWhiteSpace(s.AnEntryName) ? string.Empty : s.AnEntryName,
EntryWeight = s.EntryWeight,
NPCsToSpawnStrings = s.NPCClassString
}));
spawnContainer.NPCSpawnLimits.AddRange(entry.NPCSpawnEntrySettings.Where(s => s.IsValid).Select(s => new NPCSpawnLimit
{
NPCClassString = s.NPCClassString,
MaxPercentageOfDesiredNumToAllow = s.MaxPercentageOfDesiredNumToAllow
}));
switch (entry.ContainerType)
{
case NPCSpawnContainerType.Add:
this.ConfigAddNPCSpawnEntriesContainer.Add(spawnContainer);
this.ConfigAddNPCSpawnEntriesContainer.IsEnabled = true;
break;
case NPCSpawnContainerType.Subtract:
this.ConfigSubtractNPCSpawnEntriesContainer.Add(spawnContainer);
this.ConfigSubtractNPCSpawnEntriesContainer.IsEnabled = true;
break;
case NPCSpawnContainerType.Override:
this.ConfigOverrideNPCSpawnEntriesContainer.Add(spawnContainer);
this.ConfigOverrideNPCSpawnEntriesContainer.IsEnabled = true;
break;
}
}
}
public void UpdateForLocalization()
{
}
}
public class NPCSpawnSettings : DependencyObject, IEnumerable<NPCSpawnEntrySettings>
{
public NPCSpawnSettings()
{
NPCSpawnEntrySettings = new ObservableCollection<NPCSpawnEntrySettings>();
}
public Guid UniqueId = Guid.NewGuid();
public static readonly DependencyProperty ContainerTypeProperty = DependencyProperty.Register(nameof(ContainerType), typeof(NPCSpawnContainerType), typeof(NPCSpawnSettings), new PropertyMetadata(NPCSpawnContainerType.Override));
public NPCSpawnContainerType ContainerType
{
get { return (NPCSpawnContainerType)GetValue(ContainerTypeProperty); }
set
{
SetValue(ContainerTypeProperty, value);
SetShowColumns();
}
}
public static readonly DependencyProperty NPCSpawnEntriesContainerClassStringProperty = DependencyProperty.Register(nameof(NPCSpawnEntriesContainerClassString), typeof(string), typeof(NPCSpawnSettings), new PropertyMetadata(string.Empty));
public string NPCSpawnEntriesContainerClassString
{
get { return (string)GetValue(NPCSpawnEntriesContainerClassStringProperty); }
set { SetValue(NPCSpawnEntriesContainerClassStringProperty, value); }
}
public static readonly DependencyProperty NPCSpawnEntrySettingsProperty = DependencyProperty.Register(nameof(NPCSpawnEntrySettings), typeof(ObservableCollection<NPCSpawnEntrySettings>), typeof(NPCSpawnSettings), new PropertyMetadata(null));
public ObservableCollection<NPCSpawnEntrySettings> NPCSpawnEntrySettings
{
get { return (ObservableCollection<NPCSpawnEntrySettings>)GetValue(NPCSpawnEntrySettingsProperty); }
set { SetValue(NPCSpawnEntrySettingsProperty, value); }
}
public string DisplayName => GameData.FriendlyMapSpawnerNameForClass(NPCSpawnEntriesContainerClassString);
public bool IsValid => !string.IsNullOrWhiteSpace(NPCSpawnEntriesContainerClassString);
public static readonly DependencyProperty ShowEntryNameColumnProperty = DependencyProperty.Register(nameof(ShowEntryNameColumn), typeof(bool), typeof(NPCSpawnSettings), new PropertyMetadata(true));
public bool ShowEntryNameColumn
{
get { return (bool)GetValue(ShowEntryNameColumnProperty); }
set { SetValue(ShowEntryNameColumnProperty, value); }
}
public static readonly DependencyProperty ShowClassStringColumnProperty = DependencyProperty.Register(nameof(ShowClassStringColumn), typeof(bool), typeof(NPCSpawnSettings), new PropertyMetadata(true));
public bool ShowClassStringColumn
{
get { return (bool)GetValue(ShowClassStringColumnProperty); }
set { SetValue(ShowClassStringColumnProperty, value); }
}
public static readonly DependencyProperty ShowEntryWeightColumnProperty = DependencyProperty.Register(nameof(ShowEntryWeightColumn), typeof(bool), typeof(NPCSpawnSettings), new PropertyMetadata(true));
public bool ShowEntryWeightColumn
{
get { return (bool)GetValue(ShowEntryWeightColumnProperty); }
set { SetValue(ShowEntryWeightColumnProperty, value); }
}
public static readonly DependencyProperty ShowMaxPercentageColumnProperty = DependencyProperty.Register(nameof(ShowMaxPercentageColumn), typeof(bool), typeof(NPCSpawnSettings), new PropertyMetadata(true));
public bool ShowMaxPercentageColumn
{
get { return (bool)GetValue(ShowMaxPercentageColumnProperty); }
set { SetValue(ShowMaxPercentageColumnProperty, value); }
}
private void SetShowColumns()
{
ShowEntryNameColumn = ContainerType != NPCSpawnContainerType.Subtract;
ShowClassStringColumn = true;
ShowEntryWeightColumn = ContainerType != NPCSpawnContainerType.Subtract;
ShowMaxPercentageColumn = ContainerType != NPCSpawnContainerType.Subtract;
}
public IEnumerator<NPCSpawnEntrySettings> GetEnumerator()
{
return NPCSpawnEntrySettings.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return NPCSpawnEntrySettings.GetEnumerator();
}
}
public class NPCSpawnEntrySettings : DependencyObject
{
public static readonly DependencyProperty AnEntryNameProperty = DependencyProperty.Register(nameof(AnEntryName), typeof(string), typeof(NPCSpawnEntrySettings), new PropertyMetadata(string.Empty));
public string AnEntryName
{
get { return (string)GetValue(AnEntryNameProperty); }
set { SetValue(AnEntryNameProperty, value); }
}
public static readonly DependencyProperty NPCClassStringProperty = DependencyProperty.Register(nameof(NPCClassString), typeof(string), typeof(NPCSpawnEntrySettings), new PropertyMetadata(string.Empty));
public string NPCClassString
{
get { return (string)GetValue(NPCClassStringProperty); }
set { SetValue(NPCClassStringProperty, value); }
}
public static readonly DependencyProperty EntryWeightProperty = DependencyProperty.Register(nameof(EntryWeight), typeof(float), typeof(NPCSpawnEntrySettings), new PropertyMetadata(1.0f));
public float EntryWeight
{
get { return (float)GetValue(EntryWeightProperty); }
set { SetValue(EntryWeightProperty, value); }
}
public static readonly DependencyProperty MaxPercentageOfDesiredNumToAllowProperty = DependencyProperty.Register(nameof(MaxPercentageOfDesiredNumToAllow), typeof(float), typeof(NPCSpawnEntrySettings), new PropertyMetadata(1.0f));
public float MaxPercentageOfDesiredNumToAllow
{
get { return (float)GetValue(MaxPercentageOfDesiredNumToAllowProperty); }
set { SetValue(MaxPercentageOfDesiredNumToAllowProperty, value); }
}
public string DisplayName => GameData.FriendlyCreatureNameForClass(NPCClassString);
public bool IsValid => !string.IsNullOrWhiteSpace(NPCClassString);
}
}

View file

@ -0,0 +1,160 @@
using ArkData;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
namespace ServerManagerTool.Lib.ViewModel.RCON
{
public class PlayerInfo : INotifyPropertyChanged
{
public PlayerInfo()
{
PlayerId = string.Empty;
PlayerName = string.Empty;
CharacterName = string.Empty;
IsOnline = false;
IsAdmin = false;
IsWhitelisted = false;
TribeName = string.Empty;
LastUpdated = DateTime.MinValue;
IsValid = true;
PlayerData = null;
}
public string PlayerId
{
get { return Get<string>(); }
set { Set(value); }
}
public string PlayerName
{
get { return Get<string>(); }
set
{
Set(value);
PlayerNameFilterString = value?.ToLower();
}
}
public string PlayerNameFilterString
{
get;
private set;
}
public long CharacterId
{
get { return Get<long>(); }
set { Set(value); }
}
public string CharacterName
{
get { return Get<string>(); }
set
{
Set(value);
CharacterNameFilterString = value?.ToLower();
}
}
public string CharacterNameFilterString
{
get;
private set;
}
public bool IsOnline
{
get { return Get<bool>(); }
set { Set(value); }
}
public bool IsAdmin
{
get { return Get<bool>(); }
set { Set(value); }
}
public bool IsWhitelisted
{
get { return Get<bool>(); }
set { Set(value); }
}
public string TribeName
{
get { return Get<string>(); }
set
{
Set(value);
TribeNameFilterString = value?.ToLower();
}
}
public string TribeNameFilterString
{
get;
private set;
}
public DateTime LastUpdated
{
get { return Get<DateTime>(); }
set { Set(value); }
}
public bool IsValid
{
get { return Get<bool>(); }
set { Set(value); }
}
public PlayerData PlayerData
{
get { return Get<PlayerData>(); }
set { Set(value); }
}
public void UpdateData(PlayerData playerData)
{
this.PlayerData = playerData;
this.PlayerId = playerData?.PlayerId;
this.CharacterId = playerData?.CharacterId ?? 0L;
this.CharacterName = playerData?.CharacterName;
this.TribeName = playerData?.Tribe?.Name;
this.LastUpdated = playerData?.FileUpdated ?? DateTime.MinValue;
}
public void UpdatePlatformData(PlayerData playerData)
{
if (playerData == null)
return;
playerData.PlayerName = PlayerData?.PlayerName;
playerData.LastPlatformUpdateUtc = PlayerData?.LastPlatformUpdateUtc ?? DateTime.MinValue;
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private Dictionary<string, object> _properties = new Dictionary<string, object>();
protected T Get<T>([CallerMemberName] string name = null)
{
object value = null;
if (_properties?.TryGetValue(name, out value) ?? false)
return value == null ? default : (T)value;
return default;
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void Set<T>(T value, [CallerMemberName] string name = null)
{
if (Equals(value, Get<T>(name)))
return;
if (_properties == null)
_properties = new Dictionary<string, object>();
_properties[name] = value;
OnPropertyChanged(name);
}
#endregion
}
}

View file

@ -0,0 +1,56 @@
using ServerManagerTool.Enums;
using System;
using System.Windows;
namespace ServerManagerTool.Lib.ViewModel
{
public class PrimalItem : DependencyObject
{
public static readonly DependencyProperty ClassNameProperty = DependencyProperty.Register(nameof(ClassName), typeof(string), typeof(PrimalItem), new PropertyMetadata(String.Empty));
public static readonly DependencyProperty ModProperty = DependencyProperty.Register(nameof(Mod), typeof(string), typeof(PrimalItem), new PropertyMetadata(String.Empty));
public static readonly DependencyProperty KnownItemProperty = DependencyProperty.Register(nameof(KnownItem), typeof(bool), typeof(PrimalItem), new PropertyMetadata(false));
public static readonly DependencyProperty CategoryProperty = DependencyProperty.Register(nameof(Category), typeof(string), typeof(PrimalItem), new PropertyMetadata(String.Empty));
public string ClassName
{
get { return (string)GetValue(ClassNameProperty); }
set { SetValue(ClassNameProperty, value); }
}
public string Mod
{
get { return (string)GetValue(ModProperty); }
set { SetValue(ModProperty, value); }
}
public bool KnownItem
{
get { return (bool)GetValue(KnownItemProperty); }
set { SetValue(KnownItemProperty, value); }
}
public string Category
{
get { return (string)GetValue(CategoryProperty); }
set { SetValue(CategoryProperty, value); }
}
public string DisplayName => GameData.FriendlyItemNameForClass(ClassName);
public string DisplayMod => GameData.FriendlyNameForClass($"Mod_{Mod}", true) ?? Mod;
public PrimalItem Duplicate()
{
var properties = this.GetType().GetProperties();
var result = new PrimalItem();
foreach (var prop in properties)
{
if (prop.CanWrite)
prop.SetValue(result, prop.GetValue(this));
}
return result;
}
}
}

View file

@ -0,0 +1,48 @@
using System;
using System.Windows;
namespace ServerManagerTool.Lib.ViewModel
{
public class SupplyCrate : DependencyObject
{
public static readonly DependencyProperty ClassNameProperty = DependencyProperty.Register(nameof(ClassName), typeof(string), typeof(SupplyCrate), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty ModProperty = DependencyProperty.Register(nameof(Mod), typeof(string), typeof(SupplyCrate), new PropertyMetadata(String.Empty));
public static readonly DependencyProperty KnownSupplyCrateProperty = DependencyProperty.Register(nameof(KnownSupplyCrate), typeof(bool), typeof(SupplyCrate), new PropertyMetadata(false));
public string ClassName
{
get { return (string)GetValue(ClassNameProperty); }
set { SetValue(ClassNameProperty, value); }
}
public string Mod
{
get { return (string)GetValue(ModProperty); }
set { SetValue(ModProperty, value); }
}
public bool KnownSupplyCrate
{
get { return (bool)GetValue(KnownSupplyCrateProperty); }
set { SetValue(KnownSupplyCrateProperty, value); }
}
public string DisplayName => GameData.FriendlySupplyCrateNameForClass(ClassName);
public string DisplayMod => GameData.FriendlyNameForClass($"Mod_{Mod}", true) ?? Mod;
public SupplyCrate Duplicate()
{
var properties = this.GetType().GetProperties();
var result = new SupplyCrate();
foreach (var prop in properties)
{
if (prop.CanWrite)
prop.SetValue(result, prop.GetValue(this));
}
return result;
}
}
}

View file

@ -0,0 +1,25 @@
using System.Windows;
namespace ServerManagerTool.Lib.ViewModel
{
public class SupplyCrateItemEntrySettings : DependencyObject
{
public static readonly DependencyProperty ItemClassStringProperty = DependencyProperty.Register(nameof(ItemClassString), typeof(string), typeof(SupplyCrateItemEntrySettings), new PropertyMetadata(string.Empty));
public string ItemClassString
{
get { return (string)GetValue(ItemClassStringProperty); }
set { SetValue(ItemClassStringProperty, value); }
}
public static readonly DependencyProperty ItemWeightProperty = DependencyProperty.Register(nameof(ItemWeight), typeof(float), typeof(SupplyCrateItemEntrySettings), new PropertyMetadata(1.0f));
public float ItemWeight
{
get { return (float)GetValue(ItemWeightProperty); }
set { SetValue(ItemWeightProperty, value); }
}
public string DisplayName => GameData.FriendlySupplyCrateNameForClass(ItemClassString);
public bool IsValid => !string.IsNullOrWhiteSpace(ItemClassString);
}
}