Skip to content

Commit

Permalink
one-way public pins sharing to vanilla
Browse files Browse the repository at this point in the history
  • Loading branch information
nbusseneau committed Feb 25, 2024
1 parent 3d78b6a commit 70d1925
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 38 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add limited one-way compatibility for public pins sharing from modded clients to vanilla non-modded clients.

### Fixed

- Fix shared pins disappearing if a cartography table is in use while a save occurs.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,13 @@ How it works:
- **Private pins** can be interacted with.
- **Public** or **guild pins** previously retrieved from a **cartography table** can be displayed / hidden, but cannot be interacted with.

**Table pins** are stored in a custom ZDO key under the **cartography table**'s ZNetView's ZDO, thus there is no risk if a client without the mod installed interacts with a modded table. However vanilla clients will not be able to use a modded table: they cannot retrieve **table pins**, cannot store **table pins**, and cannot even use the table to store vanilla shared pins (because these get overwritten by design when a modded client interacts with a modded table).
**Table pins** are stored in a custom ZDO key under the **cartography table**'s ZNetView's ZDO, thus there is no conflict between non-modded vanilla clients and modded clients. Limited one-way compatibility is even provided, as modded clients will also write public pins to the vanilla shared data, allowing non-modded vanilla clients to receive public pins seamlessly. However non-modded vanilla clients will not be able to contribute anything: modded clients can only receive pins from other modded clients.

## Install

This is a client-side mod, it does not need to be installed on the server.

It is not required for all clients on the server to install the mod, however vanilla clients without the mod will not have access to any shared pins. This is kinda pointless so of course it's better if all clients install it 😅
It is not strictly required for all clients on the server to install the mod, however non-modded vanilla clients will not be able to share any of their pins with modded clients, so of course it's better if all clients install it 😅

### Thunderstore (recommended)

Expand Down
14 changes: 7 additions & 7 deletions src/Extensions/MapTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,12 @@ private static void RPC_StoreOwnerInZDO(this MapTable mapTable, string owner)

#endregion

#region Explored map storage (vanilla ZDO key)
#region Explored map and vanilla pins storage (vanilla ZDO key)

public static void SyncExploredMap(this MapTable mapTable)
public static void SyncVanillaSharedData(this MapTable mapTable)
{
mapTable.RetrieveExploredMapFromZDO();
mapTable.StoreExploredMapInZDO();
mapTable.StoreExploredMapAndPublicPinsInZDO();
}

private static void RetrieveExploredMapFromZDO(this MapTable mapTable)
Expand All @@ -132,17 +132,17 @@ private static void RetrieveExploredMapFromZDO(this MapTable mapTable)
{
array = Utils.Decompress(array);
// AddSharedMapData(...) has been truncated via a Harmony patch so that it only retrieves
// explored map data from vanilla shared data, and not pins.
// explored map data from vanilla shared data, ignoring pins coming from non-modded clients.
Minimap.instance.AddSharedMapData(array);
}
}

private static void StoreExploredMapInZDO(this MapTable mapTable)
private static void StoreExploredMapAndPublicPinsInZDO(this MapTable mapTable)
{
var array = mapTable.m_nview.GetZDO().GetByteArray(ZDOVars.s_data);
if (array is not null) array = Utils.Decompress(array);
// Underlying call to GetSharedMapData(...) has been truncated via a Harmony patch so that it
// only stores explored map data in vanilla shared data, and not pins.
// Underlying call to GetSharedMapData(...) has been modified via a Harmony patch so that it
// stores public pins in vanilla shared data, for limited compatibility with non-modded clients.
var zPackage = mapTable.GetMapData(array);
mapTable.m_nview.InvokeRPC("MapData", zPackage);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Managers/InteractionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ public static void OnMapTableUse(MapTable mapTable, Humanoid user)
else
{
CurrentMapTable = mapTable;
CurrentMapTable.SyncExploredMap();
MinimapManager.ReplaceMinimapPinsWithTablePins(CurrentMapTable);
CurrentMapTable.SyncVanillaSharedData();
CurrentMapTable.StartListeningForPinEvents();
MinimapManager.OpenMap(mapTable);
}
Expand Down Expand Up @@ -93,7 +93,7 @@ public static string GetHoverText(MapTable mapTable)
public static void OnMapClose()
{
if (!IsInteracting) return;
CurrentMapTable.SyncExploredMap();
CurrentMapTable.SyncVanillaSharedData();
CurrentMapTable.ReplaceTablePinsWithMinimapPins();
CurrentMapTable.StopListeningForPinEvents();
MinimapManager.OnMapClose();
Expand Down
51 changes: 24 additions & 27 deletions src/Patches/Minimap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,51 +125,48 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
}
}


/// <summary>
/// Truncate <c>Minimap.AddSharedMapData()</c> so that it only retrieves explored map data from vanilla shared data, and not pins.
/// Inject public pins as <c>Minimap.instance.m_pins</c> replacement in <c>Minimap.GetSharedMapData()</c> so that
/// non-modded clients can retrieve public pins stored in vanilla shared data.
/// </summary>
[HarmonyPatch(typeof(Minimap), nameof(Minimap.AddSharedMapData))]
private class TruncateAddSharedMapData
[HarmonyPatch(typeof(Minimap), nameof(Minimap.GetSharedMapData))]
private class InjectPublicPinsInGetSharedMapData
{
private static List<PinData> publicPins;
private static void Prefix() => publicPins = MinimapManager.PublicPins.ToList<PinData>();

private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
return new CodeMatcher(instructions)
.MatchForward(false,
new CodeMatch(OpCodes.Ldc_I4_0),
new CodeMatch(OpCodes.Stloc_S),
new CodeMatch(OpCodes.Ldloc_1),
new CodeMatch(OpCodes.Ldc_I4_2),
new CodeMatch(OpCodes.Blt))
.ThrowIfInvalid("Could not truncate Minimap.AddSharedMapData()")
.InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_3))
.InsertAndAdvance(new CodeInstruction(OpCodes.Ret))
.MatchForward(false, new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(Minimap), nameof(Minimap.m_pins))))
.ThrowIfInvalid("Could not inject pins replacement in Minimap.GetSharedMapData()")
.SetAndAdvance(OpCodes.Ldsfld, AccessTools.Field(typeof(InjectPublicPinsInGetSharedMapData), nameof(publicPins)))
.MatchForward(false, new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(Minimap), nameof(Minimap.m_pins))))
.ThrowIfInvalid("Could not inject pins replacement in Minimap.GetSharedMapData()")
.SetAndAdvance(OpCodes.Ldsfld, AccessTools.Field(typeof(InjectPublicPinsInGetSharedMapData), nameof(publicPins)))
.InstructionEnumeration();
}
}

/// <summary>
/// Truncate <c>Minimap.GetSharedMapData()</c> so that it only stores explored map data in vanilla shared data, and not pins.
/// Truncate <c>Minimap.AddSharedMapData()</c> after retrieving explored map data from vanilla shared data, ignoring
/// pins coming from non-modded clients.
/// </summary>
[HarmonyPatch(typeof(Minimap), nameof(Minimap.GetSharedMapData))]
private class TruncateGetSharedMapData
[HarmonyPatch(typeof(Minimap), nameof(Minimap.AddSharedMapData))]
private class TruncateAddSharedMapData
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
return new CodeMatcher(instructions)
.MatchForward(false,
new CodeMatch(OpCodes.Ldc_I4_0),
new CodeMatch(OpCodes.Stloc_2),
new CodeMatch(OpCodes.Ldarg_0),
new CodeMatch(OpCodes.Ldfld),
new CodeMatch(OpCodes.Callvirt))
.ThrowIfInvalid("Could not truncate Minimap.GetSharedMapData()")
.InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_1))
.InsertAndAdvance(new CodeInstruction(OpCodes.Ldc_I4_0))
.InsertAndAdvance(new CodeInstruction(OpCodes.Callvirt, AccessTools.Method(typeof(ZPackage), nameof(ZPackage.Write), [typeof(int)])))
.InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_1))
.InsertAndAdvance(new CodeInstruction(OpCodes.Callvirt, AccessTools.Method(typeof(ZPackage), nameof(ZPackage.GetArray))))
.InsertAndAdvance(new CodeInstruction(OpCodes.Ret))
new CodeMatch(OpCodes.Stloc_S),
new CodeMatch(OpCodes.Ldloc_1),
new CodeMatch(OpCodes.Ldc_I4_2),
new CodeMatch(OpCodes.Blt))
.ThrowIfInvalid("Could not truncate Minimap.AddSharedMapData()")
.SetAndAdvance(OpCodes.Ldloc_3, null)
.SetAndAdvance(OpCodes.Ret, null)
.InstructionEnumeration();
}
}
Expand Down

0 comments on commit 70d1925

Please sign in to comment.