Cleaning
This page uses Vector3 from Unity. The glossary says what each one is.
What it is
The tenement’s apartments get dirty. The game keeps a cleaning timer for each apartment: a number of days that must pass before the apartment is ready. While the timer runs, the game shows a timer marker in the apartment. When the timer ends, the game takes away the thing that was blocking the apartment. This API lets your mod read that timer for any apartment. It also lists the piles of trash lying around in the scene you are in, and what is inside each pile.
The API only reads. It never starts a timer and never cleans anything. The apartment rules (tenants, rent, evictions) are on the Housing page.
When to use it
- Show or log whether an apartment is waiting on its cleaning timer, and on which day it ends.
- Count the trash piles in the scene, or look inside them for a particular item.
- Find out where the trash is, so your mod can point the player to it.
Quick example
This mod waits for a save to load. Then it logs the cleaning timer of every apartment and counts the trash piles in the scene.
using ObenseuerCore;
[ModInfo("example.cleaningwatch", "Cleaning Watch", "0.1.0")]
[ModDependency("obenseuer.moddingframework", "0.11.0")]
public sealed class CleaningWatch : FrameworkMod
{
protected override void OnLoad()
{
Events.WhenReady(() =>
{
foreach (ApartmentInfo apartment in Housing.AllApartments())
{
CleaningTimerInfo timer = Cleaning.Timer(apartment.Id);
if (timer != null) Log.Info("Apartment " + apartment.Id + ": " + timer.State);
}
Log.Info("There are " + Cleaning.TrashItems().Count + " trash piles in this scene.");
});
}
}
Housing.AllApartments() gives you the apartment numbers to ask about. Timer returns null for a number the building does not have, which is why the example checks for it. See Using events for more on WhenReady.
Common tasks
Check whether one apartment is still waiting on its timer, and when the timer ends:
CleaningTimerInfo timer = Cleaning.Timer(1);
if (timer != null && timer.State == CleaningTimerState.Running)
Log.Info("The timer ends on day " + timer.CompleteDay);
Log what is in every trash pile, and where the pile is:
foreach (TrashInfo pile in Cleaning.TrashItems())
foreach (ItemStackInfo stack in pile.Items)
Log.Info("item " + stack.ItemId + " x" + stack.Count + " at " + pile.Position);
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.
Cleaning timers
Cleaning.Timer(apartmentId) tells you where an apartment is in its cleaning timer. The answer is a CleaningTimerInfo, a snapshot of the timer at the moment you asked. The snapshot does not update by itself, so ask again for fresh values.
Cleaning read the cleaning timers
Call Timer with an apartment number. It returns null when the building has no apartment with that number.
public static class Cleaning
{
public static CleaningTimerInfo Timer(int apartmentId);
}
| Method | Returns | What it does |
|---|---|---|
Timer(apartmentId) | CleaningTimerInfo | The timer for this apartment. null when the building has no such apartment. |
CleaningTimerInfo a snapshot of one apartment's cleaning timer
Cleaning.Timer gives you one of these for an apartment. Read State first, because CompleteDay only means something while it is Running.
public sealed class CleaningTimerInfo
{
public int ApartmentId { get; }
public CleaningTimerState State { get; }
public int CompleteDay { get; }
}
| Property | Type | What it means |
|---|---|---|
ApartmentId | int | The apartment number you asked about. |
State | CleaningTimerState | Where the timer is. |
CompleteDay | int | The game day the timer ends. 0 unless State is Running. |
CleaningTimerState where a cleaning timer is
CleaningTimerInfo.State holds one of these. The framework works it out from the game’s own timer day for the apartment.
public enum CleaningTimerState
{
NotStarted,
Running,
Done
}
| Value | Meaning |
|---|---|
NotStarted | no cleaning timer has been started for this apartment |
Running | the timer is counting down the days |
Done | the timer has ended and the game has removed what was blocking the apartment |
Things to know
Timergives you one of three states for the apartment.NotStartedmeans nobody has started a timer.Runningmeans the timer is counting andCompleteDayis the game day it ends.Donemeans it has ended. (the value is the apartment’scleaningTimerCompleteDay(on the game’sTenementApartment).-1isNotStarted. A day number above0isRunning, andCompleteDayis that day.0isDone: the game’sTenementController.OnCleaningTimerDayChangedsets it when the day arrives and removes the blocker.)
Limits
Timerreturnsnullfor an apartment number the building does not have. It also returnsnullwhen no save is loaded, for example on the main menu.- You can’t start a cleaning timer. The game only starts one from its own story scripts, and it does not give mods a safe way to start one. For now you can only read the timer. (the only game entry point is
TenementController.StartApartmentCleaningTimer, which the game registers for its Lua scripts. The framework does not call it, because it is a write that the game drives through Lua.) - You can’t read how much of an apartment’s furniture has been cleared. The game keeps that as a separate measure from the timer, and this page does not cover it. (the game’s
TenementApartment.FurnitureClearPercent.)
Trash piles
Cleaning.TrashItems() lists the piles of trash in the scene you are in. Each pile is a TrashInfo, a snapshot of the pile and the items inside it.
Cleaning list the trash piles
Call TrashItems() to list the trash piles in the scene you are standing in.
public static class Cleaning
{
public static List<TrashInfo> TrashItems();
}
| Method | Returns | What it does |
|---|---|---|
TrashItems() | List<TrashInfo> | Every trash pile in the active scene. |
TrashInfo one pile of trash in the scene
Cleaning.TrashItems() gives you one of these for each pile. A pile does not say which apartment it is in, so use Position to work out where it is. (It is built from the game’s FurnitureTrash objects in the scene.)
public sealed class TrashInfo
{
public string Id { get; }
public Vector3 Position { get; }
public List<ItemStackInfo> Items { get; }
}
| Property | Type | What it means |
|---|---|---|
Id | string | The pile’s save id. Can be null. |
Position | Vector3 | Where the pile is, in world coordinates. |
Items | List<ItemStackInfo> | What is in the pile. Empty stacks are left out. |
Things to know
- Each pile lists its items the same way
Containers.GetItemsdoes. Empty stacks are left out, so a pile with nothing in it has an emptyItemslist.Sloton these stacks is-1, so do not pass them to a call that takes a slot. - A pile does not say which apartment it is in. The game does not link a pile to an apartment. Use
Positionto work out where it is. Idcan benull. Not every pile has a save id. Do not use it as a key unless you check fornullfirst. (it is the object’sFurnitureTrash.GUID.)
Limits
TrashItems()only lists piles in the scene you are standing in. Piles in other scenes are not listed. It returns an empty list when no save is loaded. (it lists everyFurnitureTrashobject in the active scene. Objects that are switched off are not included.)- You can’t clean up or take trash with this API. The game removes trash one object at a time, when the player uses its cleaning mode. There is no call that cleans a whole apartment. (cleaning mode is
BuildingSystemMenu.GetButtonInfoCleaning. Taking trash isFurniturePlaceable.Take, which takes one object and has no apartment argument. The player triggers it with the Place Take key.)
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.
This page changes none of the game’s methods, so it has no feature group and nothing here can turn off after a game update.
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 save loaded,
TimerreturnsnullandTrashItemsreturns an empty list. - Nothing here throws an error to your code, and nothing changes the game. If the game itself fails while the framework reads, you get
nullor an empty list, and the first failure of each member goes to the log.