Skip to content

Commit 55114fe

Browse files
authored
v1.2
- DLLs are now correctly versioned - Added default value constructor to SynchronisedMetadata - SynchronisedMetadata now implements IDisposable - Disconnect() is now obsolete but calls Dispose() - Added LobbyHosted event to SynchronisedMetadata - `ShopItem` now correctly uses localised item names whenever available - Items registered to the shop via the mod will now be considered when spawning random items in the Old World
2 parents a69beba + b9f45ea commit 55114fe

11 files changed

+175
-62
lines changed

Patches/LocalisationPatches.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,18 @@ private static bool GetLocalizedDisplayName(Item __instance, ref string __result
8585
return false;
8686
}
8787
}
88+
89+
[HarmonyPatch(typeof(ShopItem))]
90+
[HarmonyPatch(MethodType.Constructor, new Type[] { typeof(Item) })]
91+
internal class ShopItemPatches
92+
{
93+
[HarmonyPostfix]
94+
private static void ShopItem(ref ShopItem __instance, Item dbItem)
95+
{
96+
if (Shop.IsItemRegistered(dbItem))
97+
{
98+
__instance.DisplayName = __instance.Item.GetLocalizedDisplayName();
99+
}
100+
}
101+
}
88102
}

Patches/RoundSpawnerToolsPatch.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using ContentWarningShop;
2+
using HarmonyLib;
3+
using UnityEngine;
4+
5+
namespace ShopAPI.Patches
6+
{
7+
[HarmonyPatch(typeof(RoundSpawnerTools))]
8+
internal class RoundSpawnerToolsPatch
9+
{
10+
[HarmonyPatch(nameof(RoundSpawnerTools.Populate))]
11+
[HarmonyPostfix]
12+
static void Populate(RoundSpawnerTools __instance)
13+
{
14+
var customSpawnables = Shop.CustomItems.Where(item => item.spawnable && item.itemType == Item.ItemType.Tool);
15+
Debug.Log($"Added {customSpawnables.Count()} custom items marked as spawnable to {nameof(RoundSpawnerTools)}");
16+
__instance.possibleSpawns.AddRange(customSpawnables);
17+
}
18+
}
19+
}

README.md

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,26 @@ If you are using BepInEx as your modloader, make sure to add the `[BepInDependen
2828

2929
Once added as a reference to your project, all classes are available under the `ContentWarningShop` namespace.
3030

31+
#### Creating items
32+
33+
Ideally `Item`s should be preconfigured and packed into an [`AssetBundle`](https://docs.unity3d.com/Manual/AssetBundlesIntro.html), but you can also construct them at runtime if its easier.
34+
35+
Custom `Item`s should have their `persistentID`, `price`, `purchasable`, `Category`, and `icon` properties set to work.
36+
37+
If you would like your item to have a chance to be randomly spawned in the Old World like other items, set `spawnable` to `true`, and `itemType` to `Item.ItemType.Tool`.
38+
3139
### Registering items
3240

33-
Use the `RegisterItem` method to register an `Item` to the shop. Ideally the item instance is preconfigured and loaded from an AssetBundle, but you can also construct it during runtime.
34-
Make sure to set the `persistentID`, `price`, `purchasable`, `Category`, and `icon` properties at the very least to ensure the item will show up correctly in the store.
41+
Items can be registered via the `RegisterItem` method:
42+
43+
```csharp
44+
//using ContentWarningShop;
45+
46+
var yourCustomItem = yourAssetBundle.LoadAsset<Item>("yourItem");
47+
48+
Shop.RegisterItem(yourCustomItem);
49+
Shop.RegisterCustomDataEntries();
50+
```
3551

3652
> [!NOTE]
3753
> Item prices are automatically synchronised between players on lobby join. The price set by the lobby's host will be used for the entire lobby. Once a lobby has been created, the price of a registered item can be updated via `UpdateItemPrice`.
@@ -51,9 +67,9 @@ For example to synchronise a simple boolean setting with `false` as the initial
5167
```csharp
5268
public static readonly SynchronisedMetadata<bool> ExampleSetting = new("ExampleSetting", false);
5369
```
54-
`SynchronisedMetadata` instances remain valid between different lobbies, so once bound to a key they can be safely kept in a static property and used for the entire duration of the game.
70+
Instances will remain valid between different lobbies, so once bound to a key they can be safely kept in a static property and used for the entire duration of the game.
5571

56-
To update the value, call `SetValue(T value)`. Only the lobby's host may update the value of a key, so the method returns a boolean indicating if the set was allowed. If it was rejected, the instance's value isn't updated. Use the `CanSet` method to check if the current player has permission to update the setting.
72+
To update the value, call `SetValue(T value)`. Only the lobby's host may update the value of a key, so the method returns a boolean indicating if the set was allowed. If it was rejected, the instance's value isn't updated. The `CanSet` method can be used to check if the current player has permission to update the setting.
5773

5874
> [!IMPORTANT]
5975
> Values are converted to strings when passed on to the steam lobby, so make sure your type can be cast to string and back.
@@ -63,13 +79,21 @@ When a key is successfully updated either locally or remotely, the `ValueChanged
6379
> [!NOTE]
6480
> When not currently in a lobby, setting the value is permitted as if the current player was the host, and the `ValueChanged` event will still be raised.
6581
82+
In the scenario that you have separate player and lobby settings, and you want to apply the local player's settings when they host a new lobby, make sure to subscribe to the `LobbyHosted` event and overwrite the current value. This ensures that any values set by a previous lobby will be replaced with your player's settings:
83+
84+
```csharp
85+
ExampleSetting.LobbyHosted += () => {
86+
ExampleSetting.SetValue(SomeContentWarningSetting.Value);
87+
};
88+
```
89+
6690
### Localisation
6791

68-
The game's built-in localisation implementation is not extendable, so a custom solution is included with the mod under the `ContentWarningShop.Localisation` namespace. This patches `Item.GetLocalizedDisplayName` and `Item.GetTootipData`.
92+
The game's built-in localisation implementation is not extendable, so a custom solution is included with the mod under the `ContentWarningShop.Localisation` namespace. This patches `Item.GetLocalizedDisplayName`, `Item.GetTootipData`, and the `ShopItem`'s constructor.
6993

70-
Use the `ShopLocalisation` class to add localised strings to your items. Each string is represented as a key-value pair assigned to a specific locale. For built in strings such as display name and tooltips, the item's unity object name (filename) is used or prefixed. For example, to localise the Item "Spookbox" the key would be simply also "Spookbox".
94+
Use the `ShopLocalisation` class to add localised strings to your items. Each string is represented as a key-value pair assigned to a specific locale. For built in strings such as display name and tooltips, the item's unity object name (filename) is used or prefixed. For example, to localise an `Item` with the object name "Spookbox", the key would also be simply "Spookbox".
7195

72-
When adding locale strings, use the constants defined in the `LocaleKeys` static class to retrieve a locale used by the game via the `ShopLocalisation.TryGetLocale` method:
96+
When adding locale strings, use the constants defined in the `LocaleKeys` static class to retrieve a locale used by the game via the `ShopLocalisation.TryGetLocale` method. These locales are guaranteed to be available:
7397

7498
```csharp
7599
ShopLocalisation.TryGetLocale(LocaleKeys.English, out UnityEngine.Localization.Locale locale);
@@ -81,7 +105,7 @@ The returned standard Unity Locale object can then be used via the `AddLocaleStr
81105
locale?.AddLocaleString("Spookbox_ToolTips", $"{ShopLocalisation.UseGlyphString} Play;{ShopLocalisation.Use2GlyphString} Next Track");
82106
```
83107

84-
Note that when localising item tooltips the key must be the item's name, suffixed with `_ToolTips` (`ShopLocalisation.TooltipsSuffix`), and the value must be a `;` separated list. To display action glyphs (such as right mouse button, etc) use the included constants in your strings, and the appropriate icon will be inserted into the tooltip by the game:
108+
Note that when localising item tooltips, the key must be the item's name suffixed with `_ToolTips` (`ShopLocalisation.TooltipsSuffix`), and the value must be a `;` separated list. To display action glyphs (for example "[Left Click] Toggle", etc) use the glyph strings defined on the `ShopLocalisation` class in your strings, and the appropriate icon will be inserted into the tooltip by the game:
85109

86110
| Const | Glyph |
87111
| -------- | ------- |
@@ -91,9 +115,9 @@ Note that when localising item tooltips the key must be the item's name, suffixe
91115
| ZoomGlyph | Scroll wheel |
92116

93117
> [!IMPORTANT]
94-
> If you don't want to add localisation ( :( ), use the `SetDefaultTooltips` extension method on your `Item` to set default tooltips.
118+
> If you don't want to add full localisation ( :( ), use the `SetDefaultTooltips` extension method on your `Item` to set default tooltips.
95119
> If you set tooltips in the editor, they won't work: this is a bug on Unity's end, not this mod. (those tooltips are serialised to null when you save them, even if they look right in the inspector)
96-
> Setting a default is recommended in any case, but especially if you don't or only partially provide localisation.
120+
> Setting a default is recommended in any case, but especially if you don't- or only partially provide localisation.
97121
98122
## Compatibility
99123

ShopAPI.csproj

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,41 +46,29 @@
4646
<PrivateAssets>all</PrivateAssets>
4747
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
4848
</PackageReference>
49+
<PackageReference Include="Nerdbank.GitVersioning" Version="3.7.115">
50+
<PrivateAssets>all</PrivateAssets>
51+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
52+
</PackageReference>
4953
</ItemGroup>
5054

5155
<ItemGroup>
52-
<SteamFiles Include="publish\steam\*.*"/>
53-
<ThunderstoreFiles Include="publish\thunderstore\*.*"/>
56+
<SteamFiles Include="publish\steam\*.*" />
57+
<ThunderstoreFiles Include="publish\thunderstore\*.*" />
5458
</ItemGroup>
5559

5660
<Target Condition="'$(Configuration)'!='Modman (Release)'" Name="CopyVanillaPlugin" AfterTargets="Build">
5761
<!-- The 1 in the destination folder name ensures its the first plugin to load. -->
58-
<Copy
59-
SourceFiles="$(OutputPath)\$(AssemblyName).dll;@(SteamFiles)"
60-
DestinationFolder="$(CWDir)\Plugins\1$(MSBuildProjectName)"
61-
/>
62+
<Copy SourceFiles="$(OutputPath)\$(AssemblyName).dll;@(SteamFiles)" DestinationFolder="$(CWDir)\Plugins\1$(MSBuildProjectName)" />
6263
</Target>
6364

6465
<Target Condition="'$(Configuration)'=='Modman (Release)'" Name="CopyBepInExPlugin" AfterTargets="Build">
65-
<Copy
66-
SourceFiles="$(OutputPath)\$(AssemblyName).dll;@(ThunderstoreFiles)"
67-
DestinationFolder="$(AppData)\r2modmanPlus-local\ContentWarning\profiles\Default\BepInEx\plugins\$(MSBuildProjectName)"
68-
/>
66+
<Copy SourceFiles="$(OutputPath)\$(AssemblyName).dll;@(ThunderstoreFiles)" DestinationFolder="$(AppData)\r2modmanPlus-local\ContentWarning\profiles\Default\BepInEx\plugins\$(MSBuildProjectName)" />
6967
</Target>
7068

7169
<Target Condition="'$(Configuration)'=='Modman (Release)'" Name="CreateThunderstorePackage" AfterTargets="CopyBepInExPlugin">
72-
<Copy
73-
SourceFiles="$(OutputPath)\$(AssemblyName).dll;@(ThunderstoreFiles)"
74-
DestinationFolder="$(OutputPath)\Package"
75-
/>
76-
<Copy
77-
SourceFiles="$(OutputPath)\$(AssemblyName).dll"
78-
DestinationFiles="$(OutputPath)\$(AssemblyName).bepinex.dll"
79-
/>
80-
<ZipDirectory
81-
SourceDirectory="$(OutputPath)\Package"
82-
DestinationFile="$(OutputPath)\$(AssemblyName)Package-$(AssemblyVersion).zip"
83-
Overwrite="True"
84-
/>
70+
<Copy SourceFiles="$(OutputPath)\$(AssemblyName).dll;@(ThunderstoreFiles)" DestinationFolder="$(OutputPath)\Package" />
71+
<Copy SourceFiles="$(OutputPath)\$(AssemblyName).dll" DestinationFiles="$(OutputPath)\$(AssemblyName).bepinex.dll" />
72+
<ZipDirectory SourceDirectory="$(OutputPath)\Package" DestinationFile="$(OutputPath)\$(AssemblyName)Package-$(AssemblyVersion).zip" Overwrite="True" />
8573
</Target>
8674
</Project>

ShopApiPlugin.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class ShopApiPlugin
1717
{
1818
public const string MOD_GUID = "xerren.cwshopapi";
1919
public const string MOD_NAME = "ShopAPI";
20-
public const string MOD_VER = "1.0.2";
20+
public const string MOD_VER = ThisAssembly.AssemblyVersion;
2121

2222
#if STEAM
2323
static ShopApiPlugin()

ShopLocalisation.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,23 @@ public static class ShopLocalisation
2626
{
2727
private static readonly Dictionary<UnityEngine.Localization.Locale, Dictionary<string, string>> _localeStrings = new();
2828

29-
public const string TooltipsSuffix = "_ToolTips";
29+
public static readonly string TooltipsSuffix = "_ToolTips";
3030
/// <summary>
3131
/// Represents the Left Mouse Button glyph.
3232
/// </summary>
33-
public const string UseGlyph = "{key_use}";
33+
public static readonly string UseGlyph = "{key_use}";
3434
/// <summary>
3535
/// Represents the Right Mouse Button glyph.
3636
/// </summary>
37-
public const string Use2Glyph = "{key_use2}";
37+
public static readonly string Use2Glyph = "{key_use2}";
3838
/// <summary>
3939
/// Represents the R key glyph (default, can be rebound by the player).
4040
/// </summary>
41-
public const string SelfieGlyph = "{key_selfie}";
41+
public static readonly string SelfieGlyph = "{key_selfie}";
4242
/// <summary>
4343
/// Represents the Mouse Wheel glyph.
4444
/// </summary>
45-
public const string ZoomGlyph = "{key_zoom}";
45+
public static readonly string ZoomGlyph = "{key_zoom}";
4646

4747
static ShopLocalisation()
4848
{

SteamLobbyMetadataHandler.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ internal static class SteamLobbyMetadataHandler
1010
private static Callback<LobbyDataUpdate_t> cb_onLobbyDataUpdate;
1111
//
1212
internal static event Action? OnLobbyJoined;
13+
internal static event Action? OnLobbyCreated;
1314
internal static event Action? OnLobbyDataUpdate;
1415

1516
internal static CSteamID CurrentLobby = CSteamID.Nil;
@@ -29,6 +30,7 @@ private static void Steam_LobbyCreated(LobbyCreated_t e)
2930
if (e.m_eResult == EResult.k_EResultOK)
3031
{
3132
CurrentLobby = new CSteamID(e.m_ulSteamIDLobby);
33+
OnLobbyCreated?.Invoke();
3234
OnLobbyJoined?.Invoke();
3335
}
3436
}

0 commit comments

Comments
 (0)