Skip to content

2. Helpers

Venomaus edited this page Aug 23, 2024 · 34 revisions

Here you will find an overview of all lib helper implementations.

These can all be accessed via the namespace: SOD.Common.Lib.{classname}

GameMessage

Contains various helper methods related to displaying messages in-game.

Methods:

  • Broadcast: Broadcasts a message on the screen.
  • ShowPlayerSpeech: Queues a message on the bottom of the screen resembling the player's internal monologue.

Time

Contains various helper methods and events related to the in-game time.

Events:

  • OnGamePaused: Invoked when the game is paused.
  • OnGameResumed: Invoked when the game is resumed from a paused state.
  • OnMinuteChanged: Invoked when an in-game minute passes.
  • OnHourChanged: Invoked when an in-game hour passes.
  • OnDayChanged: Invoked when an in-game day passes.
  • OnMonthChanged: Invoked when an in-game month passes.
  • OnYearChanged: Invoked when an in-game year passes.
  • OnTimeInitialized: Invoked once when the time manager is ready to calculate time. (on game load/init)

Structs exposed:

  • Time.TimeData: Contains (year, month, day, hour, minute) properties.

Properties:

  • IsGamePaused: True/False depending if the game is currently paused
  • IsInitialized: True/False depending if the time manager is ready to calculate time.
  • CurrentDateTime: Returns a TimeData struct with all properties filled in.
  • CurrentDate: Returns a TimeData struct with only (year, month, day) filled in.
  • CurrentDayEnum: Returns the game's SessionData.WeekDay enum of the current week day.
  • CurrentMonthEnum: Returns the game's SessionData.Month enum of the current month.

Methods:

  • ResumeGame: Resumes a paused game.
  • PauseGame: Pauses the game.

SaveGame

Contains various helper methods and events related to saving and loading the game.

Events:

  • OnBeforeSave: Invoked before the game is saved.
  • OnAfterSave: Invoked after the game has finished saving.
  • OnBeforeLoad: Invoked before a save is loaded.
  • OnAfterLoad: Invoked after a save is finished loading.
  • OnBeforeDelete: Invoked before a save is deleted.
  • OnAfterDelete: Invoked after a save has been deleted.
  • OnBeforeNewGame: Invoked when clicking the new game button.
  • OnAfterNewGame: Invokved when the new game is loaded. (only for new games)

Methods:

  • GetUniqueString(saveFilePath): Returns a unique string (which is the same for the provided path) that can be used to add to your filename.
  • GetSavestoreDirectoryPath(assembly): Returns the location path to plugins/YourMod/Savestore where you can store your custom files. (fixed as of v2.0.1)
  • GetSavestoreDirectoryPath(assembly, fileName): Same as GetSavestoreDirectoryPath(assembly) but also combines a filename with the path.

Note: The saveFilePath can be obtained from the EventArgs FilePath property on the events described above.

Example:

var savecode = Lib.SaveGame.GetUniqueString(saveFilePath);
var fileName = $"ModJsonData_{savecode}.json";
return Lib.SaveGame.GetSavestoreDirectoryPath(Assembly.GetExecutingAssembly(), fileName);

InputDetection

Contains various helper methods and events related to detecting input events from the game.

Events:

  • OnButtonStateChanged: Invoked when a button is pressed. (both down and up states are known)

Interaction

Contains various helper methods and events related to detecting player interaction events while in-game.

Events:

  • OnBeforeActionStarted: Raised just prior to when the player starts an action, whether the action is long or immediate.
  • OnAfterActionStarted: Raised just after when the player starts an action, whether the action is long or immediate.
  • OnAfterLongActionCancelled: Raised just after the player cancels a long action like lockpicking or searching.
  • OnAfterLongActionCompleted: Raised just after the player completes a long action like lockpicking or searching.

SyncDisks

Contains a various events related to sync disk installation / upgrade / uninstallation. Also contains a sync disk builder, which you can use to create and initialize sync disks into the game.

Events:

  • OnBeforeSyncDiskInstalled: Raised before a sync disk is installed on the player.
  • OnAfterSyncDiskInstalled: Raised after a sync disk is installed on the player.
  • OnBeforeSyncDiskUpgraded: Raised before a sync disk is upgraded on the player.
  • OnAfterSyncDiskUpgraded: Raised after a sync disk is upgraded on the player.
  • OnBeforeSyncDiskUninstalled: Raised before a sync disk is uninstalled on the player.
  • OnAfterSyncDiskUninstalled: Raised after a sync disk is uninstalled on the player.

Example of how to use the builder:

_ = Lib.SyncDisks.Builder("DiskName", "PluginGuidHere", reRaiseEventsOnSaveLoad: true)
	.SetPrice(100)
	.SetManufacturer(SyncDiskPreset.Manufacturer.Kaizen)
	.SetRarity(SyncDiskPreset.Rarity.common)
	.AddEffect("Effect One", "Adds a special effect", out int effectId)
	.AddSideEffect("Side effect", "Adds a side effect", out int sideEffectId)
	.AddSaleLocation(SyncDiskBuilder.SyncDiskSaleLocation.PoliceAutomat)
	.AddUpgradeOption(new SyncDiskBuilder.Options("Upgrade one", "Upgrade 2"), out SyncDiskBuilder.OptionIds optionIds)
	.CreateAndRegister();

Note: AddEffect, AddSideEffect and AddUpgradeOption are all optional. AddEffect and AddUpgradeOption can be each called 3 times (3 effects, 1 upgrade option set per effect)

The effectId, sideEffectId and optionIds returned from the methods are unique ids that the events will also return when this disk is installed, upgraded or deleted, based on these unique ids you can hook your custom logic.

DdsStrings

Contains various helper methods used to modify the in-game dds entries. This can be useful if you don't want to use a ddsloader and have ddsfiles part of your mod.

Methods:

  • AddOrUpdate: Adds or updates a dds entry
  • Remove: Removes an existing dds entry
  • Get: Gets an existing dds entry
  • AddOrUpdateEntries: Add's or updates multiple dds entries at once
  • RemoveEntries: Remove(s multiple dds entries at once

You can also use the indexer of the helper, here is an example: It follows a pattern like so: "(dictionary, key) = value"

Lib.DdsStrings["computer", "stockmarketpreset"] = "Stock Market";

or to delete a dds entry:

Lib.DdsStrings["computer", "stockmarketpreset"] = null;

Dialogs

Dialog helper works similar to the Sync Disk helper. It uses a builder to build the dialog, and it should be registered in the load of your plugin. Example usage of a new dialog creation:

_ = Lib.Dialogs.Builder()
	.SetText("The main text of the dialog option.")
	// Custom response can be raised like citizen.speechController.Speak(_positiveResponse)
	.AddCustomResponse("Text, can also be dynamic using lambda as shown below", out _positiveResponse)
	// Regular response is automatically connected to the dialog
	.AddResponse("Non-dynamic text.", isSuccesful: true)
	.AddResponse(() => $"Dynamic text with lambda! {Lib.Time.CurrentDateTime}", isSuccesful: false)
	.ModifyDialogOptions((a) =>
	{
		// Can modify the preset directly here
		a.useSuccessTest = true;
		a.ranking = int.MaxValue;
	})
        // Allows triggering custom code, and setting rules for when it should be shown
	.SetDialogLogic(Some_Custom_IDialogLogic_Implementation)
	.CreateAndRegister();

PluginDetection

Contains helpers to detect loaded BepInEx plugins and their config settings.

Events:

  • OnAllPluginsFinishedLoading: Raised right after the BepInEx chainloader finishes loading the last plugin.

Properties:

  • AllPluginsFinishedLoading: True if the BepInEx chainloader has finished loading all plugins, false otherwise (is set to true after OnAllPluginsFinishedLoading).

Methods:

  • IsPluginLoaded: Check if a BepInEx plugin is loaded given the plugin GUID.
  • TryGetPluginInfo: Gets the plugin info (incompatibilities, version, user-friendly name, etc.) of a BepInEx plugin given its GUID.
  • GetPluginInfo: Gets the plugin info (incompatibilities, version, user-friendly name, etc.) of a BepInEx plugin given its GUID.
  • GetPlugin: Returns the actual BasePlugin object of the PluginInfo
  • GetPluginConfigEntryValue: Gets the currently assigned value of a specified config setting for a BepInEx plugin given its GUID.
  • SetPluginConfigEntryValue: Sets a new value into the currently assigned value of specified config setting for a BepInEx plugin given its GUID.
  • AddPluginConfigEntryChangedListener: Adds a listener to the SettingChanged event handler of a BepInEx plugin's configuration manager given its GUID. Allows plugins to respond to changes in the config settings of other plugins.

Note: Most or all of the methods should be called in response to OnAllPluginsFinishedLoading.

var guid = "DialogAdditions";
Log.LogInfo(Lib.PluginDetection.IsPluginLoaded(guid));
Log.LogInfo(Lib.PluginDetection.AllPluginsFinishedLoading);

BepInPlugin metadata = Lib.PluginDetection.GetPluginInfo(guid).Metadata;
Log.LogInfo(metadata.GUID);
Log.LogInfo(metadata.Name);
Log.LogInfo(metadata.Version);

var value = Lib.PluginDetection.GetPluginConfigEntryValue<bool>(guid, "Talk to Partner", "Can asking for the partner fail?");
Log.LogInfo(value);

// To respond to in-game changes in plugin config
Lib.PluginDetection.AddPluginConfigEntryChangedListener(guid, DialogAdditionsConfigSettingChanged);

private void DialogAdditionsConfigSettingChanged(SettingChangedEventArgs args) {
    Log.LogInfo(args.ChangedSetting.Definition.Section);
    Log.LogInfo(args.ChangedSetting.Definition.Key);
    Log.LogInfo(args.ChangedSetting.Description.Description);
    if (args.ChangedSetting.Definition.Key == "Example") {
        var value = (float)args.ChangedSetting.BoxedValue;
        // ...
    }
}

PlayerStatus

Contains helper methods regarding in-game player statuses such as illegal status.

Note: It is highly recommended that mod authors use this helper to set illegal status, as there are a variety of issues that can arise from competing conditions when multiple plugins attempt to manually control illegal status during gameplay (including accounting for base game illegal status events).

Events:

  • OnBeforeSetIllegalStatus: Raised right before illegal action status will be set (either enabled or disabled).
  • OnAfterSetIllegalStatus: Raised right after illegal action status is successfully set (either enabled or disabled).

Methods:

  • SetIllegalStatusModifier: Sets an illegal status modifier with an optional duration. The modifier will cause the Player to have an Illegal Action status while it or any other modifier is present. At the end of the duration (if provided), the modifier will be automatically removed.
  • RemoveIllegalStatusModifier: Removes an illegal status modifier, if present.
  • ModifierExists: Determines if a modifier exists with the given key, and optionally returns the time left.

Illegal status modifiers are set using a key (which can be any string including e.g. your plugin's guid, or your plugin's guid plus a suffix). You can use the same key for lookups when calling the ModifierExists and RemoveIllegalStatusModifier methods.

Example:

// Lasts 3.0 seconds, and since overwrite == true the timer will
// "reset" if the statement is repeated before the 3.0s is up.
Lib.PlayerStatus.SetIllegalStatusModifier(MyPluginInfo.PLUGIN_GUID, duration: TimeSpan.FromSeconds(3.0), overwrite: true);
// Good for when the player should only have illegal status
// while a condition is met.
Lib.PlayerStatus.RemoveIllegalStatusModifier(MyPluginInfo.PLUGIN_GUID);
// Can be used when various illegal status modifiers may be active
// and need to be managed in response to an event, or when
// interfacing with other plugins
var isIllegalStatusActive = Lib.PlayerStatus.ModifierExists(MyPluginInfo.PLUGIN_GUID);
// Can get the time left
if (Lib.PlayerStatus.ModifierExists(MyPluginInfo.PLUGIN_GUID, out var timeLeft)) {
    if (timeLeft.HasValue) {
        var timeLeftInSec = timeLeft.Value.Seconds;
    }
}

Gameplay

Contains helper methods regarding most of the general gameplay functionalities.

Events:

  • OnVictimReported: Raises when a victim is reported by a civilian, and provides some arguments related to this.
  • OnVictimKilled: Raises when a victim is killed by the murderer, and provides some arguments related to this.
  • OnInteractablePickup: Raises when an interactable is picked up by the player.
  • OnInteractableDropped: Raises when an interactable is dropped or thrown by the player.

Methods:

  • AirVentExistsInHouse: Checks if an airvent exist in a house, returns true/false and outs the airvents found.
  • InteractableExistsInHouse: Checks if a certain interactable exists in a house, returns true/false and outs the interactables found.
  • AddInteractableToHouse: Add's a new interactable to a house.
  • GetInteractablePresetByName: Get's an interactable preset by name.
  • HasInteractableInInventory: Check's if the player has a certain interactable in their inventory and returns them if available.

CaseObjectives

Contains methods to help create and trigger new objectives for cases.

Events:

  • OnObjectiveCreated: Raised when a new objective is created.
  • OnObjectiveCompleted: Raised when an objective is completed.
  • OnObjectiveCanceled: Raised when an objective is canceled.

Methods:

  • Builder: Return's a basic objective builder object, to help you build a new objective.

An example of how the builder works:

// Create's an objective to go to a screwdriver interactable
// The "PredefinedTrigger" class contains a bunch of static methods that create a predefined trigger
// However you can also manually create a custom trigger using the basegame Objective.ObjectiveTrigger instead
var objectiveOne = Lib.CaseObjectives.Builder(e.Case)
	.SetText("Look around for a screwdriver to open the air vent")
	.SetIcon(InterfaceControls.Icon.lookingGlass)
	.SetPointer(ScrewDriverForVent.GetWorldPosition())
	.SetCompletionTrigger(PredefinedTrigger.GoToNode(ScrewDriverForVent.node)); // Complete when we reach the node.

//You can also create child objectives which will be triggered when the parent objective is completed/canceled using:
objectiveOne.AddChild(anotherObjectiveBuilder, ObjectiveBuilder.ChildTrigger.OnCompletion);
objectiveOne.AddChild(anotherObjectiveBuilder, ObjectiveBuilder.ChildTrigger.OnCancelation);

// To create the objective in the game you can call Register()
// Child objectives don't need to be registered, it will be handled automatically
objectiveOne.Register();