private Creature ConvertGameObject(GameObject creatureObject, int?levelStep) { if (!Values.V.TryGetSpeciesByClassName(creatureObject.ClassString, out Species species)) { // species is unknown, creature cannot be imported. // use name-field to temporarily save the unknown classString to display in a messageBox return(new Creature { name = creatureObject.ClassString }); } GameObject statusObject = creatureObject.CharacterStatusComponent(); // error while deserializing that creature if (statusObject == null) { return(null); } string imprinterName = creatureObject.GetPropertyValue <string>("ImprinterName"); string owner = string.IsNullOrWhiteSpace(imprinterName) ? creatureObject.GetPropertyValue <string>("TamerString") : imprinterName; int[] wildLevels = Enumerable.Repeat(-1, Values.STATS_COUNT).ToArray(); // -1 is unknown int[] tamedLevels = new int[Values.STATS_COUNT]; for (int i = 0; i < Values.STATS_COUNT; i++) { wildLevels[i] = statusObject.GetPropertyValue <ArkByteValue>("NumberOfLevelUpPointsApplied", i)?.ByteValue ?? 0; } wildLevels[(int)StatNames.Torpidity] = statusObject.GetPropertyValue <int>("BaseCharacterLevel", defaultValue: 1) - 1; // torpor for (int i = 0; i < Values.STATS_COUNT; i++) { tamedLevels[i] = statusObject.GetPropertyValue <ArkByteValue>("NumberOfLevelUpPointsAppliedTamed", i)?.ByteValue ?? 0; } float ti = statusObject.GetPropertyValue <float>("TamedIneffectivenessModifier", defaultValue: float.NaN); double te = 1f / (1 + (!float.IsNaN(ti) ? ti : creatureObject.GetPropertyValue <float>("TameIneffectivenessModifier"))); var arkId = creatureObject.GetDinoId(); Creature creature = new Creature(species, creatureObject.GetPropertyValue <string>("TamedName"), owner, creatureObject.GetPropertyValue <string>("TribeName"), creatureObject.IsFemale() ? Sex.Female : Sex.Male, wildLevels, tamedLevels, te, !string.IsNullOrWhiteSpace(creatureObject.GetPropertyValue <string>("ImprinterName")), statusObject.GetPropertyValue <float>("DinoImprintingQuality"), levelStep ) { imprinterName = creatureObject.GetPropertyValue <string>("ImprinterName"), guid = Utils.ConvertArkIdToGuid(arkId), ArkId = arkId, ArkIdImported = true, ArkIdInGame = Utils.ConvertImportedArkIdToIngameVisualization(arkId), domesticatedAt = DateTime.Now, // TODO: possible to convert ingame-time to realtime? addedToLibrary = DateTime.Now, mutationsMaternal = creatureObject.GetPropertyValue <int>("RandomMutationsFemale"), mutationsPaternal = creatureObject.GetPropertyValue <int>("RandomMutationsMale"), flags = (creatureObject.GetPropertyValue <bool>("bNeutered") ? CreatureFlags.Neutered : CreatureFlags.None) | (creatureObject.GetPropertyValue <bool>("MutagenApplied") ? CreatureFlags.MutagenApplied : CreatureFlags.None) }; // If it's a baby and still growing, work out growingUntil float babyAge = creatureObject.GetPropertyValue <float>("BabyAge", defaultValue: 1); if (babyAge < 1) { double maturationDuration = species.breeding?.maturationTimeAdjusted ?? 0; float bornSecondsAgo = (float)maturationDuration * babyAge; if (bornSecondsAgo < maturationDuration - 120) // there seems to be a slight offset of one of these saved values, so don't display a creature as being in cooldown if it is about to leave it in the next 2 minutes { creature.growingUntil = DateTime.Now.Add(TimeSpan.FromSeconds(maturationDuration - bornSecondsAgo)); } } else { double nextMatingPossible = creatureObject.GetPropertyValue <double>("NextAllowedMatingTime"); if (_gameTime < nextMatingPossible) { creature.cooldownUntil = DateTime.Now.Add(TimeSpan.FromSeconds(nextMatingPossible - _gameTime)); } } // Ancestor linking is done later after entire collection is formed - here we just set the guids ArkArrayStruct femaleAncestors = creatureObject.GetPropertyValue <IArkArray, ArkArrayStruct>("DinoAncestors"); StructPropertyList femaleAncestor = (StructPropertyList)femaleAncestors?.LastOrDefault(); if (femaleAncestor != null) { creature.motherGuid = Utils.ConvertArkIdToGuid(Utils.ConvertArkIdsToLongArkId( femaleAncestor.GetPropertyValue <int>("FemaleDinoID1"), femaleAncestor.GetPropertyValue <int>("FemaleDinoID2"))); creature.motherName = femaleAncestor.GetPropertyValue <string>("FemaleName"); creature.isBred = true; } ArkArrayStruct maleAncestors = creatureObject.GetPropertyValue <IArkArray, ArkArrayStruct>("DinoAncestorsMale"); StructPropertyList maleAncestor = (StructPropertyList)maleAncestors?.LastOrDefault(); if (maleAncestor != null) { creature.fatherGuid = Utils.ConvertArkIdToGuid(GameObjectExtensions.CreateDinoId( maleAncestor.GetPropertyValue <int>("MaleDinoID1"), maleAncestor.GetPropertyValue <int>("MaleDinoID2"))); creature.fatherName = maleAncestor.GetPropertyValue <string>("MaleName"); creature.isBred = true; } creature.colors = new byte[Species.ColorRegionCount]; for (int i = 0; i < 6; i++) { creature.colors[i] = creatureObject.GetPropertyValue <ArkByteValue>("ColorSetIndices", i)?.ByteValue ?? 0; } bool isDead = creatureObject.GetPropertyValue <bool>("bIsDead"); if (isDead) { creature.Status = CreatureStatus.Dead; // dead is always dead } if (creatureObject.IsCryo) { creature.Status = CreatureStatus.Cryopod; } creature.RecalculateCreatureValues(levelStep); return(creature); }