private void Log(string text, LogLevel level) { if (Configuration?.Current.LogLevel <= level) { ModApi.Log(text); } }
private void Application_OnPlayfieldUnloading(IPlayfield playfield) { ScriptingModScriptsInfoData.TryRemove(playfield.Name, out _); if (!PlayfieldData.TryRemove(playfield.Name, out var data)) { return; } data.Playfield.OnEntityLoaded -= data.Playfield_OnEntityLoaded; data.Playfield.OnEntityUnloaded -= data.Playfield_OnEntityUnloaded; ModApi.Log($"PauseScripts for {playfield.Name} {(data.PauseScripts ? "always stopped" : "scripts running")}"); data.PauseScripts = true; DisplayScriptInfos(); data.ScriptExecQueue?.Clear(); data.LcdCompileCache?.Clear(); data.PersistendData?.Clear(); var stores = data.EventStore?.Values.ToArray(); data.EventStore?.Clear(); stores?.ForEach(S => ((EventStore)S).Dispose()); }
private void Application_OnPlayfieldLoaded(IPlayfield playfield) { PlayfieldScriptData data = null; InitGameDependedData(ModApi.Application.Mode == ApplicationMode.SinglePlayer); PlayfieldData.TryAdd(playfield.Name, data = new PlayfieldScriptData(this) { PlayfieldName = playfield.Name, Playfield = playfield, }); UpdateScriptingModInfoData(); ModApi.Log($"StartScripts for {playfield.Name} pending"); TaskTools.Delay(Configuration.Current.DelayStartForNSecondsOnPlayfieldLoad, () => { ModApi.Log($"StartScripts for {playfield.Name}"); data.PauseScripts = false; if (ModApi.Application.Mode == ApplicationMode.SinglePlayer) { ModApi.Log(playfield.Entities?.Aggregate($"Player:{playfield.Players.FirstOrDefault().Value?.Name} PlayerDriving:{playfield.Players.FirstOrDefault().Value?.DrivingEntity?.Name}", (L, E) => L + $" {E.Key}:{E.Value.Name}")); data.AddEntity(playfield.Players.FirstOrDefault().Value?.DrivingEntity); playfield.Entities?.ForEach(E => data.AddEntity(E.Value)); } }); data.Playfield.OnEntityLoaded += data.Playfield_OnEntityLoaded; data.Playfield.OnEntityUnloaded += data.Playfield_OnEntityUnloaded; }
private void OnGameLoopGameLaunched(object s, EventArgs e) { this.Helper.Events.GameLoop.GameLaunched -= this.OnGameLoopGameLaunched; try { this.Monitor.StartTimer("TypeId", "Initializing TypeId..."); // Register typeId's, both for vanilla and any mods that we explicitly support (if loaded) var euApi = EntoUtilsApi.Instance; Data.Init(); this.Monitor.Log("Initializing SDV TypeId support..."); euApi.RegisterItemTypeHandler("sdv.object", TypeHandlers.StardewObject); euApi.RegisterItemTypeHandler("sdv.craftable", TypeHandlers.StardewCraftable); euApi.RegisterItemTypeHandler("sdv.boots", TypeHandlers.StardewBoots); euApi.RegisterItemTypeHandler("sdv.furniture", TypeHandlers.StardewFurniture); euApi.RegisterItemTypeHandler("sdv.hat", TypeHandlers.StardewHat); euApi.RegisterItemTypeHandler("sdv.ring", TypeHandlers.StardewRing); euApi.RegisterItemTypeHandler("sdv.floor", TypeHandlers.StardewFloor); euApi.RegisterItemTypeHandler("sdv.wallpaper", TypeHandlers.StardewWallpaper); euApi.RegisterItemTypeHandler("sdv.weapon", TypeHandlers.StardewWeapon); euApi.RegisterItemTypeHandler("sdv.clothing", TypeHandlers.StardewClothing); euApi.RegisterItemTypeHandler("sdv.tool", TypeHandlers.StardewTool); euApi.RegisterItemTypeHandler("sdv.artisan", TypeHandlers.StardewArtisan); euApi.RegisterItemTypeResolver(TypeResolvers.StardewResolver); /** * Build-in compatibility for mods with public API's that the TypeId registry can hook into * Mods which do not provide a public API will need to provide TypeId support from their end */ if (ModApi.IsLoadedAndApiAvailable <IJsonAssetsApi>("spacechase0.JsonAssets", out var jaApi)) { this.Monitor.Log("JsonAssets detected, initializing TypeId support..."); Data.JaApi = jaApi; euApi.RegisterItemTypeHandler("ja.object", TypeHandlers.JsonAssetsObject); euApi.RegisterItemTypeHandler("ja.craftable", TypeHandlers.JsonAssetsCraftable); euApi.RegisterItemTypeHandler("ja.hat", TypeHandlers.JsonAssetsHat); euApi.RegisterItemTypeHandler("ja.weapon", TypeHandlers.JsonAssetsWeapon); euApi.RegisterItemTypeHandler("ja.clothing", TypeHandlers.JsonAssetsClothing); euApi.RegisterItemTypeResolver(TypeResolvers.JsonAssetsResolver); } if (ModApi.IsLoadedAndApiAvailable <ICustomFarmingApi>("Platonymous.CustomFarming", out var cfApi)) { this.Monitor.Log("CustomFarmingRedux detected, initializing TypeId support..."); Data.CfApi = cfApi; euApi.RegisterItemTypeHandler("cf.machine", TypeHandlers.CustomFarmingMachine); } if (ModApi.IsLoadedAndApiAvailable <IPrismaticToolsApi>("stokastic.PrismaticTools", out var ptApi)) { this.Monitor.Log("PrismaticTools detected, initializing TypeId support..."); Data.PtApi = ptApi; euApi.RegisterItemTypeHandler("pt.item", TypeHandlers.PrismaticToolsItem); euApi.RegisterItemTypeResolver(TypeResolvers.PrismaticToolsResolver); } this.Monitor.StopTimer("TypeId", "TypeId initialization took {{TIME}} milliseconds."); } catch (Exception err) { this.Monitor.Log("TypeId failed to load due to a exception being thrown: \n" + err, LogLevel.Error); } this.OnLocationListChanged(null, null); }
public static void RestartAllScriptsForPlayfieldServer() { StopScriptsEvent?.Invoke(EmpyrionScriptingInstance, EventArgs.Empty); EmpyrionScriptingInstance.PauseScripts = false; Configuration.Load(); ModApi?.Log($"EmpyrionScripting Mod.Restart Threads: {EmpyrionScriptingInstance.LastAlive} <-> {DateTime.Now} : {Configuration.Current.LogLevel}"); EmpyrionScriptingInstance.StartAllScriptsForPlayfieldServer(); }
private void Application_OnPlayfieldLoaded(string playfieldName) { ModApi.Log($"StartScripts for {playfieldName} pending"); TaskTools.Delay(Configuration.Current.DelayStartForNSecondsOnPlayfieldLoad, () => { ModApi.Log($"StartScripts for {playfieldName}"); PauseScripts = false; }); }
private void Application_GameEntered(bool hasEntered) { ModApi.Log($"Application_GameEntered {hasEntered}"); if (hasEntered) { InitGameDependedData(false); } ModApi.Log("Application_GameEntered init finish"); }
/// <summary>Sets up initial values needed for Animal Skinner.</summary> private void Setup(object sender, SaveLoadedEventArgs e) { ModApi.RegisterDefaultTypes(); IntegrateMods(); LoadAssets(); // Remove the Setup from the loop, so that it isn't done twice when the player returns to the title screen and loads again this.Helper.Events.GameLoop.SaveLoaded -= this.Setup; }
private void Application_OnPlayfieldUnloaded(string playfieldName) { ModApi.Log($"PauseScripts for {playfieldName} {(PauseScripts ? "always stopped" : "scripts running")}"); PauseScripts = true; DisplayScriptInfos(); ScriptExecQueue.Clear(); LcdCompileCache.Clear(); PersistendData.Clear(); }
protected override async Task <ApiModInfo?> ResolveCacheMiss(string key) { try { return(await ModApi.RequestModInfoAsync(key)); } catch (ResourceNotFoundException) { return(null); } }
private void CsCompiler_ConfigurationChanged(object sender, EventArgs e) { PlayfieldData.ForEach(P => { ModApi.Log($"CsCompiler_ConfigurationChanged: {P.Key} {(P.Value == null ? "null" : (P.Value.PauseScripts ? "always stopped" : "scripts running"))}"); DisplayScriptInfos(); P.Value?.ScriptExecQueue?.Clear(); P.Value?.LcdCompileCache?.Clear(); }); }
public void StartAllScriptsForPlayfieldServer() { ModApi.Log($"StartAllScriptsForPlayfieldServer: InGame:{Configuration.Current.InGameScriptsIntervallMS}ms SaveGame:{Configuration.Current.SaveGameScriptsIntervallMS}ms "); StartScriptIntervall(Configuration.Current.InGameScriptsIntervallMS, () => { PlayfieldData.Values.ForEach(PF => { Log($"InGameScript: {PF.PauseScripts}", LogLevel.Debug); LastAlive = DateTime.Now; if (PF.PauseScripts) { return; } InGameScriptsCount = UpdateScripts(PF, ProcessAllInGameScripts, "InGameScript"); PF.ScriptExecQueue.ScriptsCount = InGameScriptsCount + SaveGameScriptsCount; }); }, "InGameScript"); StartScriptIntervall(Configuration.Current.SaveGameScriptsIntervallMS, () => { PlayfieldData.Values.ForEach(PF => { Log($"SaveGameScript: {PF.PauseScripts}", LogLevel.Debug); LastAlive = DateTime.Now; if (PF.PauseScripts) { return; } SaveGameScriptsCount = UpdateScripts(PF, ProcessAllSaveGameScripts, "SaveGameScript"); PF.ScriptExecQueue.ScriptsCount = InGameScriptsCount + SaveGameScriptsCount; }); }, "SaveGameScript"); StartScriptIntervall(60000, () => { PlayfieldData.Values.ForEach(PF => { Log($"ScriptInfos: Pause:{PF.PauseScripts} {PF.ScriptExecQueue.ScriptRunInfo.Count} ExecQueue:{PF.ScriptExecQueue.ExecQueue.Count} WaitForExec:{PF.ScriptExecQueue.WaitForExec.Count}", LogLevel.Debug); LastAlive = DateTime.Now; if (PF.PauseScripts || Configuration.Current.LogLevel > LogLevel.Message) { return; } DisplayScriptInfos(); PF.ScriptExecQueue.CheckForEmergencyRestart(PF); }); }, "ScriptInfos"); }
private int UpdateScripts(PlayfieldScriptData playfieldData, Func <PlayfieldScriptData, IEntity, int> process, string name) { try { if (playfieldData.Playfield == null) { ModApi.Log($"UpdateScripts no Playfield"); return(0); } if (playfieldData.Playfield.Entities == null) { ModApi.Log($"UpdateScripts no Entities"); return(0); } var timer = new Stopwatch(); timer.Start(); playfieldData.AllEntities = playfieldData.Playfield.Entities.Values.ToArray(); playfieldData.CurrentEntities = playfieldData.AllEntities .Where(E => E.Type == EntityType.BA || E.Type == EntityType.CV || E.Type == EntityType.SV || E.Type == EntityType.HV) .ToArray(); Log($"CurrentEntities: {playfieldData.CurrentEntities.Length}", LogLevel.Debug); playfieldData.EntityCultureInfo.Clear(); int count = 0; playfieldData.CurrentEntities.ForEach(E => count += process(playfieldData, E)); timer.Stop(); if (timer.Elapsed.TotalSeconds > 30) { Log($"UpdateScripts: {name} RUNS {timer.Elapsed} !!!!", LogLevel.Message); } else { Log($"UpdateScripts: {name} take {timer.Elapsed}", LogLevel.Debug); } return(count); } catch (Exception error) { ModApi.LogWarning("Next try because: " + ErrorFilter(error)); return(0); } }
public static void Log(string text, LogLevel level) { if (Configuration?.Current.LogLevel <= level) { switch (level) { case LogLevel.Debug: ModApi?.Log(text); break; case LogLevel.Message: ModApi?.Log(text); break; case LogLevel.Error: ModApi?.LogError(text); break; default: ModApi?.Log(text); break; } } }
public void StartAllScriptsForPlayfieldServer() { ModApi.Log($"StartAllScriptsForPlayfieldServer: InGame:{Configuration.Current.InGameScriptsIntervallMS}ms SaveGame:{Configuration.Current.SaveGameScriptsIntervallMS}ms "); StartScriptIntervall(Configuration.Current.InGameScriptsIntervallMS, () => { Log($"InGameScript: {PauseScripts} #{CycleCounter}", LogLevel.Debug); LastAlive = DateTime.Now; if (PauseScripts) { return; } Interlocked.Increment(ref CycleCounter); InGameScriptsCount = UpdateScripts(ProcessAllInGameScripts, "InGameScript"); ScriptExecQueue.ScriptsCount = InGameScriptsCount + SaveGameScriptsCount; }, "InGameScript"); StartScriptIntervall(Configuration.Current.SaveGameScriptsIntervallMS, () => { Log($"SaveGameScript: {PauseScripts}", LogLevel.Debug); LastAlive = DateTime.Now; if (PauseScripts) { return; } SaveGameScriptsCount = UpdateScripts(ProcessAllSaveGameScripts, "SaveGameScript"); ScriptExecQueue.ScriptsCount = InGameScriptsCount + SaveGameScriptsCount; }, "SaveGameScript"); StartScriptIntervall(60000, () => { Log($"ScriptInfos: {ScriptExecQueue.ScriptRunInfo.Count} ExecQueue:{ScriptExecQueue.ExecQueue.Count} WaitForExec:{ScriptExecQueue.WaitForExec.Count}", LogLevel.Debug); LastAlive = DateTime.Now; if (PauseScripts || Configuration.Current.LogLevel > LogLevel.Message) { return; } DisplayScriptInfos(); }, "ScriptInfos"); }
private static void InitGameDependedData(bool forceInit) { if (forceInit || !AppFoldersLogged) { AppFoldersLogged = true; ModApi.Log($"InitGameDependedData [ForceInit:{forceInit}]:\n" + $"AppFolder.Content:{ModApi.Application?.GetPathFor(AppFolder.Content)}\n" + $"AppFolder.Mod:{ModApi.Application?.GetPathFor(AppFolder.Mod)}\n" + $"AppFolder.Root:{ModApi.Application?.GetPathFor(AppFolder.Root)}\n" + $"AppFolder.SaveGame:{ModApi.Application?.GetPathFor(AppFolder.SaveGame)}\n" + $"AppFolder.Dedicated:{ModApi.Application?.GetPathFor(AppFolder.Dedicated)}\n" + $"AppFolder.Cache:{ModApi.Application?.GetPathFor(AppFolder.Cache)}\n" + $"AppFolder.ActiveScenario:{ModApi.Application?.GetPathFor(AppFolder.ActiveScenario)} -> CurrentScenario:{CurrentScenario}"); } if (forceInit || Localization == null) { Localization = new Localization(ModApi.Application?.GetPathFor(AppFolder.Content), CurrentScenario); } if (forceInit || ConfigEcfAccess == null) { InitEcfConfigData(); } }
/// <summary>Load skin assets into AnimalSkinner</summary> private void LoadAssets() { // Gather handled types string validTypes = string.Join(", ", ModApi.GetHandledAllTypes()); foreach (FileInfo file in new DirectoryInfo(Path.Combine(this.Helper.DirectoryPath, "assets", "skins")).EnumerateFiles()) { // Check extension of file is handled by AnimalSkinner string extension = Path.GetExtension(file.Name); if (!this.ValidExtensions.Contains(extension)) { this.Monitor.Log($"Ignored skin `assets/skins/{file.Name}` with invalid extension (extension must be one of type {string.Join(", ", this.ValidExtensions)})", LogLevel.Warn); continue; } // Parse file name string[] nameParts = Path.GetFileNameWithoutExtension(file.Name).Split(new[] { '_' }, 2); string type = Sanitize(nameParts[0]); // Ensure creature type is handled by AnimalSkinner if (!PetAssets.ContainsKey(type) && !HorseAssets.ContainsKey(type) && !AnimalAssets.ContainsKey(type)) { this.Monitor.Log($"Ignored skin `assets/skins/{file.Name}` with invalid naming convention (can't parse {nameParts[0]} as an animal, pet, or horse. Expected one of type: {validTypes})", LogLevel.Warn); continue; } // Ensure both a type and skin ID can be found in the file name if (nameParts.Length != 2) { this.Monitor.Log($"Ignored skin `assets/skins/{file.Name} with invalid naming convention (no skin ID found)", LogLevel.Warn); continue; } // Ensure the skin ID is a number int skinID = 0; if (nameParts.Length == 2 && !int.TryParse(nameParts[1], out skinID)) { this.Monitor.Log($"Ignored skin `assets/skins/{file.Name}` with invalid skin ID (can't parse {nameParts[1]} as a number)", LogLevel.Warn); continue; } // Ensure the skin ID is not 0 or negative if (skinID <= 0) { this.Monitor.Log($"Ignored skin `assets/skins/{file.Name}` with skin ID of less than or equal to 0. Skins must have an ID of at least 1."); } // File naming is valid, add asset into system string assetKey = this.Helper.Content.GetActualAssetKey(Path.Combine("assets", "skins", extension.Equals("xnb") ? Path.Combine(Path.GetDirectoryName(file.Name), Path.GetFileNameWithoutExtension(file.Name)) : file.Name)); if (AnimalAssets.ContainsKey(type)) { AnimalAssets[type].Add(new AnimalSkin(type, skinID, assetKey)); } else if (HorseAssets.ContainsKey(type)) { HorseAssets[type].Add(new AnimalSkin(type, skinID, assetKey)); } else { PetAssets[type].Add(new AnimalSkin(type, skinID, assetKey)); } } // Sort each list AnimalSkin.Comparer comp = new AnimalSkin.Comparer(); foreach (string type in AnimalAssets.Keys) { AnimalAssets[type].Sort((p1, p2) => comp.Compare(p1, p2)); } foreach (string type in PetAssets.Keys) { PetAssets[type].Sort((p1, p2) => comp.Compare(p1, p2)); } foreach (string type in HorseAssets.Keys) { HorseAssets[type].Sort((p1, p2) => comp.Compare(p1, p2)); } // Print loaded assets to console StringBuilder summary = new StringBuilder(); summary.AppendLine( "Statistics:\n" + "\n Registered types: " + validTypes + "\n Animal Skins:" ); foreach (KeyValuePair <string, List <AnimalSkin> > pair in ModEntry.AnimalAssets) { if (pair.Value.Count > 0) { summary.AppendLine($" {pair.Key}: {pair.Value.Count} skins ({string.Join(", ", pair.Value.Select(p => Path.GetFileName(p.AssetKey)).OrderBy(p => p))})"); } } summary.AppendLine(" Pet Skins:"); foreach (KeyValuePair <string, List <AnimalSkin> > pair in ModEntry.PetAssets) { if (pair.Value.Count > 0) { summary.AppendLine($" {pair.Key}: {pair.Value.Count} skins ({string.Join(", ", pair.Value.Select(p => Path.GetFileName(p.AssetKey)).OrderBy(p => p))})"); } } summary.AppendLine(" Horse Skins:"); foreach (KeyValuePair <string, List <AnimalSkin> > pair in ModEntry.HorseAssets) { if (pair.Value.Count > 0) { summary.AppendLine($" {pair.Key}: {pair.Value.Count} skins ({string.Join(", ", pair.Value.Select(p => Path.GetFileName(p.AssetKey)).OrderBy(p => p))})"); } } this.Monitor.Log(summary.ToString(), LogLevel.Trace); }
public Support() { var a = new ModApi(); a.Thing(); }
public MyMod() { var a = new ModApi(); a.DoIt(); }
public void Dispose() { ModApi?.Log("EmpyrionScripting Mod: Dispose"); }
protected override Task <ApiModInfo> ResolveCacheMiss(string key) => ModApi.RequestModInfoAsync(key);
public void Game_Exit() { ModApi.Log("Mod exited:Game_Exit"); StopScriptsEvent?.Invoke(this, EventArgs.Empty); }
private int ProcessAllInGameScripts(IEntity entity) { Log($"ProcessAllInGameScripts: {entity.Name}:{entity.Type} Pause:{PauseScripts}", LogLevel.Debug); if (entity.Type == EntityType.Proxy || PauseScripts) { return(0); } try { var entityScriptData = new ScriptRootData(CurrentEntities, ModApi.Playfield, entity, DeviceLockAllowed, PersistendData); var deviceNames = entityScriptData.E.S.AllCustomDeviceNames.Where(N => N.StartsWith(ScriptKeyword)).ToArray(); Log($"ProcessAllInGameScripts: #{deviceNames.Length}", LogLevel.Debug); int count = 0; Parallel.ForEach(deviceNames, N => { if (PauseScripts) { return; } var lcd = entity.Structure.GetDevice <ILcd>(N); if (lcd == null) { return; } try { Log($"ProcessAllInGameScripts: {N}", LogLevel.Debug); var data = new ScriptRootData(entityScriptData) { Script = lcd.GetText(), Error = L, }; AddTargetsAndDisplayType(data, N.Substring(ScriptKeyword.Length)); if (Configuration.Current.ScriptTracking) { var trackfile = GetTrackingFileName(entity, data.Script.GetHashCode().ToString()); if (!File.Exists(trackfile)) { File.WriteAllText(trackfile, data.Script); } } data.ScriptId = entity.Id + "/" + N; ScriptExecQueue.Add(data); Interlocked.Increment(ref count); } catch (Exception lcdError) { if (Configuration.Current.LogLevel >= EmpyrionNetAPIDefinitions.LogLevel.Debug) { ModApi.Log($"UpdateLCDs ({entity.Id}/{entity.Name}):LCD: {lcdError}"); } } }); return(count); } catch (Exception error) { File.WriteAllText(GetTrackingFileName(entity, string.Empty) + ".error", error.ToString()); return(0); } }
/// <summary> /// Given the ID for an animal, pet, or horse, and that creature's type, return the AnimalSkin mapped to that creature. /// Return null if the creature type isn't handled. /// </summary> internal AnimalSkin GetSkin(Character creature) { switch (creature) { case Horse horse: // No horse skins are loaded if (HorseAssets[Sanitize(horse.GetType().Name)].Count == 0) { return(null); } // A wild horse is being checked if (horse.Manners == WildHorse.WildID) { this.Monitor.Log($"Wild ID: {Creator.HorseInfo.SkinID}", LogLevel.Info); return(GetSkinFromID(horse.GetType().Name, Creator.HorseInfo.SkinID)); } // Horse is not in system else if (horse.Manners == 0 || !HorseSkinMap.ContainsKey(horse.Manners)) { this.Monitor.Log($"Horse not in system: {horse.Name}", LogLevel.Error); return(null); } // Ensure skin ID given is a valid number for the given horse type int horseSkinID = HorseSkinMap[horse.Manners]; if (horseSkinID < 1 || horseSkinID > HorseAssets[Sanitize(horse.GetType().Name)].Count) { this.Monitor.Log($"{horse.Name}'s skin ID no longer exists in `/assets/skins`. Skin will be randomized.", LogLevel.Alert); horseSkinID = SetRandomSkin(horse); } // Horse has a skin. Return it. return(GetSkinFromID(horse.GetType().Name, horseSkinID)); case Pet pet: string petType = Sanitize(pet.GetType().Name); // Break out of unhandled types if (!ModApi.GetHandledPetTypes().Contains(petType)) { break; } else if (PetAssets[Sanitize(pet.GetType().Name)].Count == 0) { return(null); } // Pet is not in system if (pet.Manners == 0 || !PetSkinMap.ContainsKey(pet.Manners)) { this.Monitor.Log($"Pet not in system: {pet.Name}", LogLevel.Error); return(null); } // Ensure skin ID given is a current valid number for the given pet type int petSkinID = PetSkinMap[pet.Manners]; if (petSkinID < 1 || petSkinID > PetAssets[petType].Count) { this.Monitor.Log($"{pet.Name}'s skin ID no longer exists in `/assets/skins`. Skin will be randomized.", LogLevel.Alert); petSkinID = SetRandomSkin(pet); } return(GetSkinFromID(petType, petSkinID)); case FarmAnimal animal: string animalType = Sanitize(animal.type.Value); // Break out of unhandled types if (!ModApi.GetHandledAnimalTypes().Contains(animalType)) { break; } else if (AnimalAssets[Sanitize(animal.type.Value)].Count == 0) { return(null); } // Set sub-type if applicable if (ModApi.HasBabySprite(animalType) && animal.age.Value < animal.ageWhenMature.Value) { animalType = "baby" + animalType; } else if (ModApi.HasShearedSprite(animalType) && animal.currentProduce.Value <= 0) { animalType = "sheared" + animalType; } // Animal is not in system if (!AnimalSkinMap.ContainsKey(animal.myID.Value)) { return(null); } // Ensure skin ID given is a current valid number for the given animal type int animalSkinID = AnimalSkinMap[animal.myID.Value]; if (animalSkinID < 1 || animalSkinID > AnimalAssets[animalType].Count) { this.Monitor.Log($"{animal.Name}'s skin ID is no longer exists in `/assets/skins`. Skin will be randomized.", LogLevel.Alert); animalSkinID = SetRandomSkin(animal); } return(GetSkinFromID(animalType, animalSkinID)); default: break; } return(null); }
public void Shutdown() { ModApi.Log("Mod exited:Shutdown"); StopScriptsEvent.Invoke(this, EventArgs.Empty); }