Extractables
This page uses GameObject from Unity. The glossary says what each one is.
What it is
An extractable is a thing in the world that the player breaks apart with the right tool to get items out of it. It has health, and each hit takes some off. When the health runs out, the game spawns the items and removes the object. This API lets your mod list the extractables in the scene you are in, and read their health. It can also hit one as if the player had, and tells you when one is broken open.
Extractables are not the same as resource nodes, which hold a stock of something to take out. See Resources for those.
When to use it
- Count the extractables left in a scene.
- Show or log a message when the player breaks one open.
- Hit an extractable from your own code, for a quest or a scripted event.
Quick example
This mod writes a log line each time an extractable is broken open. Once a save is loaded, it also logs how many extractables are in the scene and how much health they have left in total.
using ObenseuerCore;
[ModInfo("example.extractwatch", "Extract Watch", "0.1.0")]
[ModDependency("obenseuer.moddingframework", "0.11.0")]
public sealed class ExtractWatch : FrameworkMod
{
protected override void OnLoad()
{
Extractables.Extracted += args => Log.Info("Broken open: " + args.Id);
Events.WhenReady(() =>
{
int health = 0;
foreach (ExtractableInfo extractable in Extractables.All())
health += extractable.Health;
Log.Info(Extractables.All().Count + " extractables here, " + health + " health in total.");
});
}
}
Extracted is an event: the framework calls your code each time it happens. See Using events for more on events and WhenReady.
Common tasks
Hit one extractable by its id. Damage returns false when nothing was hit, so check the result:
foreach (ExtractableInfo extractable in Extractables.All())
{
if (Extractables.Damage(extractable.Id)) Log.Info("Hit " + extractable.Name);
break;
}
Read the health of one extractable you saved the id of earlier:
int health = Extractables.Health("some-extractable-id");
Log.Info("Health left: " + health);
Check that the break-open event works before you rely on it:
if (!Extractables.IsAvailable) Log.Warn("The Extracted event is off in this game version.");
Reference
This is the full list of what the API gives you. Text in brackets at the end of a note is extra detail you can skip on a first read.
Listing and hitting extractables
Extractables finds the extractables in the scene you are in. Each one is an ExtractableInfo, a snapshot of it at the moment you asked. The snapshot does not update by itself, so ask again for fresh values.
Extractables lists and hits extractables
This is the class you start from. All() lists the extractables in the scene, Get(id) finds one by its id, and Damage(id) hits one as the player would.
public static class Extractables
{
public static List<ExtractableInfo> All();
public static ExtractableInfo Get(string id);
public static int Health(string id);
public static bool Damage(string id);
}
| Method | Returns | What it does |
|---|---|---|
All() | List<ExtractableInfo> | Every extractable in the active scene. |
Get(id) | ExtractableInfo | The one with this id. null when there is none. |
Health(id) | int | Its health. 0 when there is none. |
Damage(id) | bool | Hits it once as the player would. Returns true when the hit took health off. |
ExtractableInfo a snapshot of one extractable
Extractables.All() and Extractables.Get(id) give you this. It is a copy of the extractable as it was when you asked, so ask again to see a new Health. (It is filled from the game’s Extractable component and the object’s name.)
public sealed class ExtractableInfo
{
public string Id { get; }
public string Name { get; }
public int Health { get; }
}
| Property | Type | What it means |
|---|---|---|
Id | string | Its save id, or when it has none a text path of where it sits in the scene. |
Name | string | The name of the object in the scene. |
Health | int | The health it had when you asked. |
Things to know
All()lists the extractables in the scene you are in. Extractables that are switched off, or in another scene, are not listed. It returns an empty list when no scene is loaded, for example on the main menu.Idis the object’s save id, or a text path when it has none. A path changes if the object is moved or renamed, so do not keep it for long. (The id is theExtractable.GUIDfield, or a scene path whenGUIDis empty.Nameis theGameObjectname.)Get(id)andHealth(id)returnnulland0for an id nobody has. If you need to know whether the extractable exists, useGetand check fornull.- A hit that takes the last health breaks the extractable open. The game spawns the items, plays the effect and sound, and removes the object, the same as when the player does it.
Limits
Damage(id)can’t pick how much damage to do. Every hit takes the same amount of health, set by the game. The framework could only change it by writing the health directly, and the game never does that. (The game’sExtractable.Damage()always removes 25 health, soDamagetakes only the id.)Damage(id)only works if the player is holding the right tool. Each extractable accepts certain tools. If the player is not holding one of them, the game does nothing and shows no message, andDamagereturnsfalse. Equip the tool first, or hand the player one. (The game checksInventory.CheckIfPlayerWieldsItem(Tools).Damagereturnstrueonly whenHealthis lower after the call.)Damage(id)returnsfalsein other cases too. It returnsfalsefor an id nobody has, and for an extractable that is already broken open and about to be removed (its health is below 1). It also returnsfalsewhile a save is loading or being written. (It is theSaveGate.Busycheck. A refused hit does not changeHealth.)
The break-open event
Extracted tells your mod when an extractable has just been broken open.
Extractables the break-open event
Extracted is the event on this class. IsAvailable tells you whether the event works in this game version.
public static class Extractables
{
public static event Action<ExtractedArgs> Extracted;
public static bool IsAvailable { get; }
}
| Property | Type | What it means |
|---|---|---|
IsAvailable | bool | false when the event could not be set up. |
| Event | Gives you | When it fires |
|---|---|---|
Extracted | ExtractedArgs: the extractable’s id. | An extractable was just broken open. |
ExtractedArgs what the event tells you
Extracted hands you this. Its Id is the same as the Id of the ExtractableInfo for that extractable. The framework builds it from a hook on the game’s Extractable.Damage, so it is the framework’s own type.
public sealed class ExtractedArgs
{
public string Id { get; }
}
| Property | Type | What it means |
|---|---|---|
Id | string | The same id as ExtractableInfo.Id. |
Things to know
Extractedfires once, right after the game has spawned the items. It fires for a hit by the player and for a hit made withDamage. Your handler runs inside the game’s own call, so keep it short. (It is raised synchronously from a Harmony postfix (a change that runs after a game method) onExtractable.Damage, when health went from 1 or more to below 1.)IsAvailabletells you whether the event works. It isfalsewhen the framework could not set up the event, or when its feature group was turned off.All,Get,HealthandDamagekeep working when it isfalse.
Limits
Extracteddoes not fire for extractables that were broken open earlier. When a save loads, the game removes those quietly, so no event is raised for them. (They are removed on load by the game’sDestructibleList, not throughDamage.)Extracteddoes not fire while a save is loading.
Details
Target: Obenseuer 0.5.08 (buildid 25969064), Unity 6000.0.77f1 Mono, BepInEx 6 Unity.Mono (be.788, the tested build) or BepInEx 5 (5.4.23 or later). Namespace: ObenseuerCore.
Everything not listed in this reference is internal and may change without notice.
The framework changes one of the game’s methods when it starts, so it can tell your mod when an extractable is broken open. This page calls that a feature group: a named set of the framework’s changes for one feature. Its feature group is obenseuer.moddingframework.extractables, the name you will see in the log.
When you can call it
- Call everything from your mod’s normal code (
OnLoad, event handlers,Update), not from a background thread you started. The game and Unity only run safely on the main thread (see the glossary). - It is safe to call at any time, even on the main menu. With no scene loaded, reads return an empty list,
nullor0, andDamagereturnsfalse. - Nothing here throws an error to your code. If the game itself fails while the framework reads, you get the same empty answer, and the first failure of each member goes to the log.
- Your event handlers run inside the game’s own call, one at a time. If a handler throws an error, the framework logs it and still runs the other handlers.
If something fails to set up
The framework changes some of the game’s methods when it starts. If a game update breaks one of them, the framework turns off the feature group that depends on it, and writes error lines and a warning to the group’s log file in BepInEx\logs. The rest of the framework keeps working.
- If the change to
Extractable.Damagecannot be made, only theExtractedevent stops.Extractables.IsAvailablebecomesfalseand error lines and a warning go to the log.All,Get,HealthandDamagekeep working. (The warning reads “extractable hooks incomplete, Extracted event is disabled”.)
Save loads
- The framework does not raise
Extractedwhile a save is loading. A handler that should also ignore events raised while a save is being written can checkSaveData.Busy, which istruewhile a save is loading or being written.