/********* ** Public methods *********/ /// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides simplified APIs for writing mods.</param> public override void Entry(IModHelper helper) { // read config this.Config = helper.ReadConfig <ModConfig>(); this.Keys = this.Config.Controls.ParseControls(helper.Input, this.Monitor); // init I18n.Init(helper.Translation); this.TractorManager = new TractorManager(this.Config, this.Keys, this.Helper.Reflection); this.UpdateConfig(); // hook events IModEvents events = helper.Events; events.GameLoop.GameLaunched += this.OnGameLaunched; events.GameLoop.SaveLoaded += this.OnSaveLoaded; events.GameLoop.DayStarted += this.OnDayStarted; events.GameLoop.DayEnding += this.OnDayEnding; events.GameLoop.Saving += this.OnSaving; events.Display.Rendered += this.OnRendered; events.Display.MenuChanged += this.OnMenuChanged; events.Input.ButtonPressed += this.OnButtonPressed; events.World.NpcListChanged += this.OnNpcListChanged; events.World.LocationListChanged += this.OnLocationListChanged; events.GameLoop.UpdateTicked += this.OnUpdateTicked; events.Multiplayer.ModMessageReceived += this.OnModMessageReceived; events.Player.Warped += this.OnWarped; // validate translations if (!helper.Translation.GetTranslations().Any()) { this.Monitor.Log("The translation files in this mod's i18n folder seem to be missing. The mod will still work, but you'll see 'missing translation' messages. Try reinstalling the mod to fix this.", LogLevel.Warn); } }
/**** ** Helper methods ****/ /// <summary>Apply the mod configuration if it changed.</summary> private void UpdateConfig() { this.Keys = this.Config.Controls.ParseControls(this.Helper.Input, this.Monitor); var modRegistry = this.Helper.ModRegistry; var reflection = this.Helper.Reflection; var toolConfig = this.Config.StandardAttachments; this.TractorManager.UpdateConfig(this.Config, this.Keys, new IAttachment[] { new CustomAttachment(this.Config.CustomAttachments, modRegistry, reflection), // should be first so it can override default attachments new AxeAttachment(toolConfig.Axe, modRegistry, reflection), new FertilizerAttachment(toolConfig.Fertilizer, modRegistry, reflection), new GrassStarterAttachment(toolConfig.GrassStarter, modRegistry, reflection), new HoeAttachment(toolConfig.Hoe, modRegistry, reflection), new MeleeWeaponAttachment(toolConfig.MeleeWeapon, modRegistry, reflection), new MilkPailAttachment(toolConfig.MilkPail, modRegistry, reflection), new PickaxeAttachment(toolConfig.PickAxe, modRegistry, reflection), new ScytheAttachment(toolConfig.Scythe, modRegistry, reflection), new SeedAttachment(toolConfig.Seeds, modRegistry, reflection), modRegistry.IsLoaded(SeedBagAttachment.ModId) ? new SeedBagAttachment(toolConfig.SeedBagMod, modRegistry, reflection) : null, new ShearsAttachment(toolConfig.Shears, modRegistry, reflection), new SlingshotAttachment(toolConfig.Slingshot, modRegistry, reflection), new WateringCanAttachment(toolConfig.WateringCan, modRegistry, reflection) }); }
/********* ** Public methods *********/ /// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides simplified APIs for writing mods.</param> public override void Entry(IModHelper helper) { this.Config = helper.ReadConfig <ModConfig>(); this.Keys = this.Config.Controls.ParseControls(helper.Input, this.Monitor); helper.Events.GameLoop.UpdateTicked += this.OnUpdateTicked; }
/********* ** Public methods *********/ /// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides methods for interacting with the mod directory, such as read/writing a config file or custom JSON files.</param> public override void Entry(IModHelper helper) { // toggle mod compatibility bool hasBetterJunimos = helper.ModRegistry.IsLoaded("hawkfalcon.BetterJunimos"); bool hasAutoGrabberMod = helper.ModRegistry.IsLoaded("Jotser.AutoGrabberMod"); // init this.Config = helper.ReadConfig <ModConfig>(); this.Keys = this.Config.Controls.ParseControls(this.Monitor); this.Factory = new MachineGroupFactory(); this.Factory.Add(new AutomationFactory(this.Config.Connectors, this.Config.AutomateShippingBin, this.Monitor, helper.Reflection, hasBetterJunimos, hasAutoGrabberMod)); // hook events helper.Events.GameLoop.SaveLoaded += this.OnSaveLoaded; helper.Events.Player.Warped += this.OnWarped; helper.Events.World.LocationListChanged += this.World_LocationListChanged; helper.Events.World.ObjectListChanged += this.World_ObjectListChanged; helper.Events.GameLoop.UpdateTicked += this.OnUpdateTicked; helper.Events.Input.ButtonPressed += this.OnButtonPressed; if (this.Config.Connectors.Any(p => p.Type == ObjectType.Floor)) { helper.Events.World.TerrainFeatureListChanged += this.World_TerrainFeatureListChanged; } // log info this.Monitor.VerboseLog($"Initialised with automation every {this.Config.AutomationInterval} ticks."); }
/********* ** Public methods *********/ /// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides methods for interacting with the mod directory, such as read/writing a config file or custom JSON files.</param> public override void Entry(IModHelper helper) { // load config this.Config = this.Helper.ReadConfig <ModConfig>(); this.Keys = this.Config.Controls.ParseControls(helper.Input, this.Monitor); // load translations L10n.Init(helper.Translation); // load & validate database this.LoadMetadata(); this.IsDataValid = this.Metadata.LooksValid(); if (!this.IsDataValid) { this.Monitor.Log("The data.json file seems to be missing or corrupt. Lookups will be disabled.", LogLevel.Error); this.IsDataValid = false; } // validate translations if (!helper.Translation.GetTranslations().Any()) { this.Monitor.Log("The translation files in this mod's i18n folder seem to be missing. The mod will still work, but you'll see 'missing translation' messages. Try reinstalling the mod to fix this.", LogLevel.Warn); } // hook up events helper.Events.GameLoop.GameLaunched += this.OnGameLaunched; helper.Events.GameLoop.DayStarted += this.OnDayStarted; helper.Events.Display.RenderedHud += this.OnRenderedHud; helper.Events.Display.MenuChanged += this.OnMenuChanged; helper.Events.Input.ButtonPressed += this.OnButtonPressed; if (this.Config.HideOnKeyUp) { helper.Events.Input.ButtonReleased += this.OnButtonReleased; } }
/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="config">The mod settings.</param> /// <param name="keys">The configured key bindings.</param> /// <param name="translation">Provides translations from the mod's i18n folder.</param> /// <param name="reflection">Simplifies access to private game code.</param> public TractorManager(ModConfig config, ModConfigKeys keys, ITranslationHelper translation, IReflectionHelper reflection) { this.Config = config; this.Keys = keys; this.Translation = translation; this.Reflection = reflection; }
/********* ** Public methods *********/ /// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides methods for interacting with the mod directory, such as read/writing a config file or custom JSON files.</param> public override void Entry(IModHelper helper) { // init this.Config = helper.ReadConfig <ModConfig>(); this.Keys = this.Config.Controls.ParseControls(this.Monitor); this.Factory = new MachineGroupFactory(); this.Factory.Add(new AutomationFactory( connectors: this.Config.ConnectorNames, automateShippingBin: this.Config.AutomateShippingBin, monitor: this.Monitor, reflection: helper.Reflection, data: this.Helper.Data.ReadJsonFile <DataModel>("data.json"), betterJunimosCompat: this.Config.ModCompatibility.BetterJunimos && helper.ModRegistry.IsLoaded("hawkfalcon.BetterJunimos"), autoGrabberModCompat: this.Config.ModCompatibility.AutoGrabberMod && helper.ModRegistry.IsLoaded("Jotser.AutoGrabberMod") )); // hook events helper.Events.GameLoop.SaveLoaded += this.OnSaveLoaded; helper.Events.Player.Warped += this.OnWarped; helper.Events.World.BuildingListChanged += this.OnBuildingListChanged; helper.Events.World.LocationListChanged += this.OnLocationListChanged; helper.Events.World.ObjectListChanged += this.OnObjectListChanged; helper.Events.World.TerrainFeatureListChanged += this.OnTerrainFeatureListChanged; helper.Events.GameLoop.UpdateTicked += this.OnUpdateTicked; helper.Events.Input.ButtonPressed += this.OnButtonPressed; // log info this.Monitor.VerboseLog($"Initialised with automation every {this.Config.AutomationInterval} ticks."); }
/// <summary>The method invoked when the player presses a button.</summary> /// <param name="sender">The event sender.</param> /// <param name="e">The event arguments.</param> private void OnButtonPressed(object sender, ButtonPressedEventArgs e) { try { ModConfigKeys keys = this.Keys; // open menu if (keys.Toggle.Contains(e.Button)) { // open if no conflict if (Game1.activeClickableMenu == null) { this.OpenMenu(); } // open from inventory if it's safe to close the inventory screen else if (Game1.activeClickableMenu is GameMenu gameMenu && gameMenu.currentTab == GameMenu.inventoryTab) { IClickableMenu inventoryPage = this.Helper.Reflection.GetField <List <IClickableMenu> >(gameMenu, "pages").GetValue()[GameMenu.inventoryTab]; if (inventoryPage.readyToClose()) { this.OpenMenu(); } } } } catch (Exception ex) { this.HandleError(ex, "handling key input"); } }
/// <summary>The method invoked when the player presses a button.</summary> /// <param name="sender">The event sender.</param> /// <param name="e">The event data.</param> private void OnButtonPressed(object sender, ButtonPressedEventArgs e) { this.Monitor.InterceptErrors("handling your input", $"handling input '{e.Button}'", () => { ModConfigKeys keys = this.Keys; if (keys.ToggleSearch.JustPressedUnique()) { this.ToggleSearch(); } if (keys.ToggleLookup.JustPressedUnique()) { this.ToggleLookup(LookupMode.Cursor); } else if (keys.ToggleLookupInFrontOfPlayer.JustPressedUnique() && Context.IsWorldReady) { this.ToggleLookup(LookupMode.FacingPlayer); } else if (keys.ScrollUp.JustPressedUnique()) { (Game1.activeClickableMenu as LookupMenu)?.ScrollUp(); } else if (keys.ScrollDown.JustPressedUnique()) { (Game1.activeClickableMenu as LookupMenu)?.ScrollDown(); } else if (keys.ToggleDebug.JustPressedUnique() && Context.IsPlayerFree) { this.DebugInterface.Enabled = !this.DebugInterface.Enabled; } }); }
/********* ** Public methods *********/ /// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides simplified APIs for writing mods.</param> public override void Entry(IModHelper helper) { this.Config = helper.ReadConfig <ModConfig>(); this.Keys = this.Config.Controls.ParseControls(helper.Input, this.Monitor); helper.Events.GameLoop.UpdateTicked += this.OnUpdateTicked; LocalizedContentManager.OnLanguageChange += this.OnLocaleChanged; }
/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="config">The mod settings.</param> /// <param name="keys">The configured key bindings.</param> /// <param name="translation">Provides translations from the mod's i18n folder.</param> /// <param name="reflection">Simplifies access to private game code.</param> /// <param name="attachments">The tractor attachments to apply.</param> public TractorManager(ModConfig config, ModConfigKeys keys, ITranslationHelper translation, IReflectionHelper reflection, IEnumerable <IAttachment> attachments) { this.Config = config; this.Keys = keys; this.Translation = translation; this.Reflection = reflection; this.Attachments = attachments.ToArray(); this.AttachmentCooldowns = this.Attachments.Where(p => p.RateLimit > this.TicksPerAction).ToDictionary(p => p, p => 0); }
/********* ** Public methods *********/ /// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides methods for interacting with the mod directory, such as read/writing a config file or custom JSON files.</param> public override void Entry(IModHelper helper) { // read data file const string dataPath = "assets/data.json"; DataModel data = null; try { data = this.Helper.Data.ReadJsonFile <DataModel>(dataPath); if (data?.FloorNames == null) { this.Monitor.Log($"The {dataPath} file seems to be missing or invalid. Floor connectors will be disabled.", LogLevel.Error); } } catch (Exception ex) { this.Monitor.Log($"The {dataPath} file seems to be invalid. Floor connectors will be disabled.\n{ex}", LogLevel.Error); } // read config this.Config = this.LoadConfig(); // init this.Keys = this.Config.Controls.ParseControls(helper.Input, this.Monitor); this.Factory = new MachineGroupFactory(this.Config); this.Factory.Add(new AutomationFactory( connectors: this.Config.ConnectorNames, monitor: this.Monitor, reflection: helper.Reflection, data: data, betterJunimosCompat: this.Config.ModCompatibility.BetterJunimos && helper.ModRegistry.IsLoaded("hawkfalcon.BetterJunimos"), autoGrabberModCompat: this.Config.ModCompatibility.AutoGrabberMod && helper.ModRegistry.IsLoaded("Jotser.AutoGrabberMod"), pullGemstonesFromJunimoHuts: this.Config.PullGemstonesFromJunimoHuts )); this.CommandHandler = new CommandHandler(this.Monitor, this.Config, this.Factory, this.ActiveMachineGroups); // hook events helper.Events.GameLoop.SaveLoaded += this.OnSaveLoaded; helper.Events.Player.Warped += this.OnWarped; helper.Events.World.BuildingListChanged += this.OnBuildingListChanged; helper.Events.World.LocationListChanged += this.OnLocationListChanged; helper.Events.World.ObjectListChanged += this.OnObjectListChanged; helper.Events.World.TerrainFeatureListChanged += this.OnTerrainFeatureListChanged; helper.Events.GameLoop.UpdateTicked += this.OnUpdateTicked; helper.Events.Input.ButtonPressed += this.OnButtonPressed; helper.Events.Multiplayer.ModMessageReceived += this.OnModMessageReceived; // hook commands helper.ConsoleCommands.Add("automate", "Run commands from the Automate mod. Enter 'automate help' for more info.", this.CommandHandler.HandleCommand); // log info this.Monitor.VerboseLog($"Initialized with automation every {this.Config.AutomationInterval} ticks."); if (this.Config.ModCompatibility.WarnForMissingBridgeMod) { this.ReportMissingBridgeMods(data?.SuggestedIntegrations); } }
/********* ** Public methods *********/ /// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides methods for interacting with the mod directory, such as read/writing a config file or custom JSON files.</param> public override void Entry(IModHelper helper) { // read config this.Config = helper.ReadConfig <ModConfig>(); this.Keys = this.Config.Controls.ParseControls(helper.Input, this.Monitor); // hook events helper.Events.Input.ButtonPressed += this.OnButtonPressed; }
/// <summary>The method invoked when the player presses an input button.</summary> /// <param name="sender">The event sender.</param> /// <param name="e">The event arguments.</param> private void OnButtonPressed(object sender, ButtonPressedEventArgs e) { if (this.Layers == null) { return; } // perform bound action this.Monitor.InterceptErrors("handling your input", $"handling input '{e.Button}'", () => { // check context if (!this.CanOverlayNow()) { return; } bool overlayVisible = this.CurrentOverlay != null; ModConfigKeys keys = this.Keys; // toggle overlay if (keys.ToggleLayer.JustPressedUnique()) { if (overlayVisible) { this.CurrentOverlay.Dispose(); this.CurrentOverlay = null; } else { this.CurrentOverlay = new DataLayerOverlay(this.Helper.Events, this.Helper.Input, this.Helper.Reflection, this.Layers, this.CanOverlayNow, this.Config.CombineOverlappingBorders, this.Config.ShowGrid); } this.Helper.Input.Suppress(e.Button); } // cycle layers else if (overlayVisible && keys.NextLayer.JustPressedUnique()) { this.CurrentOverlay.NextLayer(); this.Helper.Input.Suppress(e.Button); } else if (overlayVisible && keys.PrevLayer.JustPressedUnique()) { this.CurrentOverlay.PrevLayer(); this.Helper.Input.Suppress(e.Button); } // shortcut to layer else if (overlayVisible) { ILayer layer = this.ShortcutMap.Where(p => p.Key.JustPressedUnique()).Select(p => p.Value).FirstOrDefault(); if (layer != null && layer != this.CurrentOverlay.CurrentLayer) { this.CurrentOverlay.SetLayer(layer); this.Helper.Input.Suppress(e.Button); } } }); }
/********* ** Public methods *********/ /// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides simplified APIs for writing mods.</param> public override void Entry(IModHelper helper) { // read config this.Config = helper.ReadConfig <ModConfig>(); this.Keys = this.Config.Controls.ParseControls(helper.Input, this.Monitor); // init tractor logic { IModRegistry modRegistry = this.Helper.ModRegistry; IReflectionHelper reflection = this.Helper.Reflection; StandardAttachmentsConfig toolConfig = this.Config.StandardAttachments; this.TractorManager = new TractorManager(this.Config, this.Keys, this.Helper.Translation, this.Helper.Reflection, attachments: new IAttachment[] { new CustomAttachment(this.Config.CustomAttachments, modRegistry, reflection), // should be first so it can override default attachments new AxeAttachment(toolConfig.Axe, modRegistry, reflection), new FertilizerAttachment(toolConfig.Fertilizer, modRegistry, reflection), new GrassStarterAttachment(toolConfig.GrassStarter, modRegistry, reflection), new HoeAttachment(toolConfig.Hoe, modRegistry, reflection), new MeleeWeaponAttachment(toolConfig.MeleeWeapon, modRegistry, reflection), new MilkPailAttachment(toolConfig.MilkPail, modRegistry, reflection), new PickaxeAttachment(toolConfig.PickAxe, modRegistry, reflection), new ScytheAttachment(toolConfig.Scythe, modRegistry, reflection), new SeedAttachment(toolConfig.Seeds, modRegistry, reflection), new SeedBagAttachment(toolConfig.SeedBagMod, modRegistry, reflection), new ShearsAttachment(toolConfig.Shears, modRegistry, reflection), new SlingshotAttachment(toolConfig.Slingshot, modRegistry, reflection), new WateringCanAttachment(toolConfig.WateringCan, modRegistry, reflection) }); } // hook events IModEvents events = helper.Events; events.GameLoop.GameLaunched += this.OnGameLaunched; events.GameLoop.SaveLoaded += this.OnSaveLoaded; events.GameLoop.DayStarted += this.OnDayStarted; events.GameLoop.DayEnding += this.OnDayEnding; events.GameLoop.Saving += this.OnSaving; if (this.Config.HighlightRadius) { events.Display.Rendered += this.OnRendered; } events.Display.MenuChanged += this.OnMenuChanged; events.Input.ButtonPressed += this.OnButtonPressed; events.World.NpcListChanged += this.OnNpcListChanged; events.World.LocationListChanged += this.OnLocationListChanged; events.GameLoop.UpdateTicked += this.OnUpdateTicked; events.Multiplayer.ModMessageReceived += this.OnModMessageReceived; // validate translations if (!helper.Translation.GetTranslations().Any()) { this.Monitor.Log("The translation files in this mod's i18n folder seem to be missing. The mod will still work, but you'll see 'missing translation' messages. Try reinstalling the mod to fix this.", LogLevel.Warn); } }
/********* ** Public methods *********/ /// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides methods for interacting with the mod directory, such as read/writing a config file or custom JSON files.</param> public override void Entry(IModHelper helper) { // read config this.Config = helper.ReadConfig <ModConfig>(); this.Keys = this.Config.Controls.ParseControls(this.Monitor); // hook up events helper.Events.GameLoop.GameLaunched += this.OnGameLaunched; helper.Events.GameLoop.ReturnedToTitle += this.OnReturnedToTitle; helper.Events.GameLoop.UpdateTicked += this.OnUpdateTicked; helper.Events.Input.ButtonPressed += this.OnButtonPressed; }
/// <summary>The method invoked when the player releases a button.</summary> /// <param name="sender">The event sender.</param> /// <param name="e">The event data.</param> private void OnButtonReleased(object sender, ButtonReleasedEventArgs e) { // perform bound action this.Monitor.InterceptErrors("handling your input", $"handling input release '{e.Button}'", () => { ModConfigKeys keys = this.Keys; if (keys.ToggleLookup.JustPressedUnique() || keys.ToggleLookupInFrontOfPlayer.JustPressedUnique()) { this.HideLookup(); } }); }
/********* ** Public methods *********/ /// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides methods for interacting with the mod directory, such as read/writing a config file or custom JSON files.</param> public override void Entry(IModHelper helper) { // read data file const string dataPath = "assets/data.json"; DataModel data = null; try { data = this.Helper.Data.ReadJsonFile <DataModel>(dataPath); if (data?.FloorNames == null) { this.Monitor.Log($"The {dataPath} file seems to be missing or invalid. Floor connectors will be disabled.", LogLevel.Error); } } catch (Exception ex) { this.Monitor.Log($"The {dataPath} file seems to be invalid. Floor connectors will be disabled.\n{ex}", LogLevel.Error); } // read config this.Config = helper.ReadConfig <ModConfig>(); this.Config.MachinePriority = new Dictionary <string, int>(this.Config.MachinePriority, StringComparer.OrdinalIgnoreCase); // init this.Keys = this.Config.Controls.ParseControls(helper.Input, this.Monitor); this.Factory = new MachineGroupFactory(this.Config); this.Factory.Add(new AutomationFactory( connectors: this.Config.ConnectorNames, automateShippingBin: this.Config.AutomateShippingBin, monitor: this.Monitor, reflection: helper.Reflection, data: data, betterJunimosCompat: this.Config.ModCompatibility.BetterJunimos && helper.ModRegistry.IsLoaded("hawkfalcon.BetterJunimos"), autoGrabberModCompat: this.Config.ModCompatibility.AutoGrabberMod && helper.ModRegistry.IsLoaded("Jotser.AutoGrabberMod"), pullGemstonesFromJunimoHuts: this.Config.PullGemstonesFromJunimoHuts )); // hook events helper.Events.GameLoop.SaveLoaded += this.OnSaveLoaded; helper.Events.Player.Warped += this.OnWarped; helper.Events.World.BuildingListChanged += this.OnBuildingListChanged; helper.Events.World.LocationListChanged += this.OnLocationListChanged; helper.Events.World.ObjectListChanged += this.OnObjectListChanged; helper.Events.World.TerrainFeatureListChanged += this.OnTerrainFeatureListChanged; helper.Events.GameLoop.UpdateTicked += this.OnUpdateTicked; helper.Events.Input.ButtonPressed += this.OnButtonPressed; helper.Events.Multiplayer.ModMessageReceived += this.OnModMessageReceived; // log info this.Monitor.VerboseLog($"Initialized with automation every {this.Config.AutomationInterval} ticks."); }
/// <summary>Update mod configuration if it changed.</summary> /// <param name="config">The new mod configuration.</param> /// <param name="keys">The new key bindings.</param> /// <param name="attachments">The tractor attachments to apply.</param> public void UpdateConfig(ModConfig config, ModConfigKeys keys, IEnumerable <IAttachment> attachments) { // update config this.Config = config; this.Keys = keys; this.Attachments = attachments.Where(p => p != null).ToArray(); this.AttachmentCooldowns = this.Attachments.Where(p => p.RateLimit > this.TicksPerAction).ToDictionary(p => p, p => 0); // clear buff so it's reapplied with new values Game1.buffsDisplay?.otherBuffs?.RemoveAll(p => p.which == this.BuffUniqueID); // reset cooldowns this.SkippedActionTicks = 0; }
/********* ** Public methods *********/ /// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides methods for interacting with the mod directory, such as read/writing a config file or custom JSON files.</param> public override void Entry(IModHelper helper) { // read config this.Config = helper.ReadConfig <ModConfig>(); this.Keys = this.Config.Controls.ParseControls(this.Monitor); // hook up events helper.Events.GameLoop.GameLaunched += this.OnGameLaunched; helper.Events.GameLoop.ReturnedToTitle += this.OnReturnedToTitle; helper.Events.GameLoop.UpdateTicked += this.OnUpdateTicked; helper.Events.Input.ButtonPressed += this.OnButtonPressed; // hook up commands var commandHandler = new CommandHandler(this.Monitor, () => this.CurrentOverlay?.CurrentLayer); helper.ConsoleCommands.Add(commandHandler.CommandName, $"Starts a Data Layers command. Type '{commandHandler.CommandName} help' for details.", (name, args) => commandHandler.Handle(args)); }
public override void Entry(IModHelper helper) { Config = helper.ReadConfig <ModConfig>(); Keys = Config.Controls.ParseControls(Monitor); helper.Events.Input.ButtonPressed += OnButtonPressed; SmoothPanningHelper.Initialize(helper); StaticReflectionHelper.Initialize(helper); _inputHelper = helper.Input; _keyHandlers = new IKeyHandler[] { new ChestKeyHandler(Keys.AddToExistingStacks), new PanScreenHandler(Keys.PanScreenScrollLeft, Keys.PanScreenScrollRight, Keys.PanScreenScrollUp, Keys.PanScreenScrollDown, Keys.PanScreenPreviousBuilding, Keys.PanScreenNextBuilding) }; }
/********* ** Public methods *********/ /// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides simplified APIs for writing mods.</param> public override void Entry(IModHelper helper) { this.Config = helper.ReadConfig <ModConfig>(); this.Keys = this.Config.Controls.ParseControls(this.Monitor); // init migrations IMigration[] migrations = this.Migrations(); // fetch content packs RawContentPack[] contentPacks = this.GetContentPacks(migrations).ToArray(); string[] installedMods = (contentPacks.Select(p => p.Manifest.UniqueID)) .Concat(helper.ModRegistry.GetAll().Select(p => p.Manifest.UniqueID)) .OrderByIgnoreCase(p => p) .ToArray(); // load content packs this.TokenManager = new TokenManager(helper.Content, installedMods); this.PatchManager = new PatchManager(this.Monitor, this.TokenManager, this.AssetValidators()); this.LoadContentPacks(contentPacks); // set initial context once patches & dynamic tokens are loaded this.UpdateContext(); // register patcher helper.Content.AssetLoaders.Add(this.PatchManager); helper.Content.AssetEditors.Add(this.PatchManager); // set up events if (this.Config.EnableDebugFeatures) { helper.Events.Input.ButtonPressed += this.OnButtonPressed; } helper.Events.GameLoop.ReturnedToTitle += this.OnReturnedToTitle; helper.Events.GameLoop.DayStarted += this.OnDayStarted; helper.Events.Player.Warped += this.OnWarped; helper.Events.Specialised.LoadStageChanged += this.OnLoadStageChanged; // set up commands this.CommandHandler = new CommandHandler(this.TokenManager, this.PatchManager, this.Monitor, () => this.UpdateContext()); helper.ConsoleCommands.Add(this.CommandHandler.CommandName, $"Starts a Content Patcher command. Type '{this.CommandHandler.CommandName} help' for details.", (name, args) => this.CommandHandler.Handle(args)); }
/// <summary>The method invoked when the player presses an input button.</summary> /// <param name="sender">The event sender.</param> /// <param name="e">The event arguments.</param> private void OnButtonPressed(object sender, ButtonPressedEventArgs e) { // perform bound action this.Monitor.InterceptErrors("handling your input", $"handling input '{e.Button}'", () => { // check context if (!this.CanOverlayNow()) { return; } bool overlayVisible = this.CurrentOverlay != null; ModConfigKeys keys = this.Keys; // toggle overlay if (keys.ToggleLayer.Contains(e.Button)) { if (overlayVisible) { this.CurrentOverlay.Dispose(); this.CurrentOverlay = null; } else { this.CurrentOverlay = new DataLayerOverlay(this.Helper.Events, this.Helper.Input, this.Layers, this.CanOverlayNow, this.Config.CombineOverlappingBorders); } this.Helper.Input.Suppress(e.Button); } // cycle layers else if (overlayVisible && keys.NextLayer.Contains(e.Button)) { this.CurrentOverlay.NextLayer(); this.Helper.Input.Suppress(e.Button); } else if (overlayVisible && keys.PrevLayer.Contains(e.Button)) { this.CurrentOverlay.PrevLayer(); this.Helper.Input.Suppress(e.Button); } }); }
/********* ** Public methods *********/ /// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides methods for interacting with the mod directory, such as read/writing a config file or custom JSON files.</param> public override void Entry(IModHelper helper) { // initialize this.Config = helper.ReadConfig <ModConfig>(); this.Config.AllowDangerousCommands = this.Config.AllowGameDebug && this.Config.AllowDangerousCommands; // normalize for convenience this.Keys = this.Config.Controls.ParseControls(this.Monitor); // hook events helper.Events.Input.ButtonPressed += this.OnButtonPressed; helper.Events.Display.Rendered += this.OnRendered; if (this.Config.AllowGameDebug) { helper.Events.Player.Warped += this.OnWarped; } // validate translations if (!helper.Translation.GetTranslations().Any()) { this.Monitor.Log("The translation files in this mod's i18n folder seem to be missing. The mod will still work, but you'll see 'missing translation' messages. Try reinstalling the mod to fix this.", LogLevel.Warn); } }
private void OnButtonsChanged(object sender, ButtonsChangedEventArgs e) { if (!Context.IsWorldReady) { return; } // perform bound action this.Monitor.InterceptErrors("handling your input", () => { ModConfigKeys keys = this.Keys; if (keys.ShiftToNext.JustPressed()) { this.RotateToolbar(true, this.Config.DeselectItemOnRotate); } else if (keys.ShiftToPrevious.JustPressed()) { this.RotateToolbar(false, this.Config.DeselectItemOnRotate); } }); }
/********* ** Public methods *********/ /// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides methods for interacting with the mod directory, such as read/writing a config file or custom JSON files.</param> public override void Entry(IModHelper helper) { // initialise this.Config = helper.ReadConfig <ModConfig>(); this.Keys = this.Config.Controls.ParseControls(this.Monitor); this.Data = helper.Data.ReadJsonFile <ModData>("data.json") ?? new ModData(); this.ChestFactory = new ChestFactory(helper.Translation, helper.Data, this.Config.EnableShippingBin); // hook events helper.Events.GameLoop.SaveLoaded += this.OnSaveLoaded; helper.Events.GameLoop.UpdateTicked += this.OnUpdateTicked; helper.Events.GameLoop.UpdateTicking += this.OnUpdateTicking; helper.Events.Display.RenderedHud += this.OnRenderedHud; helper.Events.Input.ButtonPressed += this.OnButtonPressed; // validate translations if (!helper.Translation.GetTranslations().Any()) { this.Monitor.Log("The translation files in this mod's i18n folder seem to be missing. The mod will still work, but you'll see 'missing translation' messages. Try reinstalling the mod to fix this.", LogLevel.Warn); } }
/// <summary>The method invoked when the player presses a button.</summary> /// <param name="sender">The event sender.</param> /// <param name="e">The event arguments.</param> private void OnButtonPressed(object sender, ButtonPressedEventArgs e) { if (!Context.IsWorldReady) { return; } try { ModConfigKeys keys = this.Keys; // open menu if (keys.Toggle.Contains(e.Button)) { // open if no conflict if (Game1.activeClickableMenu == null) { if (Context.IsPlayerFree && !Game1.player.UsingTool) { this.OpenMenu(); } } // open from inventory if it's safe to close the inventory screen else if (Game1.activeClickableMenu is GameMenu gameMenu && gameMenu.currentTab == GameMenu.inventoryTab) { IClickableMenu inventoryPage = gameMenu.pages[GameMenu.inventoryTab]; if (inventoryPage.readyToClose()) { this.OpenMenu(); } } } } catch (Exception ex) { this.HandleError(ex, "handling key input"); } }
/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="menu">The underlying chest menu.</param> /// <param name="chest">The selected chest.</param> /// <param name="chests">The available chests.</param> /// <param name="config">The mod configuration.</param> /// <param name="keys">The configured key bindings.</param> /// <param name="events">The SMAPI events available for mods.</param> /// <param name="input">An API for checking and changing input state.</param> /// <param name="reflection">Simplifies access to private code.</param> /// <param name="showAutomateOptions">Whether to show Automate options.</param> public ShopMenuOverlay(ShopMenu menu, ManagedChest chest, ManagedChest[] chests, ModConfig config, ModConfigKeys keys, IModEvents events, IInputHelper input, IReflectionHelper reflection, bool showAutomateOptions) : base(menu, chest, chests, config, keys, events, input, reflection, showAutomateOptions, keepAlive: () => Game1.activeClickableMenu is ShopMenu, topOffset: Game1.pixelZoom * 6) { this.Menu = menu; this.DefaultPurchaseFilter = menu.canPurchaseCheck; this.DefaultInventoryHighlighter = menu.inventory.highlightMethod; }
/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="menu">The underlying chest menu.</param> /// <param name="chest">The selected chest.</param> /// <param name="chests">The available chests.</param> /// <param name="config">The mod configuration.</param> /// <param name="keys">The configured key bindings.</param> /// <param name="events">The SMAPI events available for mods.</param> /// <param name="input">An API for checking and changing input state.</param> /// <param name="translations">Provides translations stored in the mod's folder.</param> /// <param name="showAutomateOptions">Whether to show Automate options.</param> public ChestOverlay(ItemGrabMenu menu, ManagedChest chest, ManagedChest[] chests, ModConfig config, ModConfigKeys keys, IModEvents events, IInputHelper input, ITranslationHelper translations, bool showAutomateOptions) : base(menu, chest, chests, config, keys, events, input, translations, showAutomateOptions, keepAlive: () => Game1.activeClickableMenu is ItemGrabMenu, topOffset: -Game1.pixelZoom * 9) { this.Menu = menu; this.MenuInventoryMenu = menu.ItemsToGrabMenu; this.DefaultChestHighlighter = menu.inventory.highlightMethod; this.DefaultInventoryHighlighter = this.MenuInventoryMenu.highlightMethod; }