diff --git a/docs/articles/cameras.md b/docs/articles/cameras.md
index c6be55e..a094e26 100644
--- a/docs/articles/cameras.md
+++ b/docs/articles/cameras.md
@@ -107,6 +107,7 @@ Each `CameraFrame` (delivered via `OnCameraRaysReceived`) contains:
- `Entities` — list of `CameraEntity` objects visible in the frame (id, type, position/rotation/size, name).
- `TimeOfDay` — in-game time of day when captured (`null` if not reported).
- `CameraPosition` / `CameraRotation` — world-space position and rotation (`null` if not reported).
+- `SampleRotation` — world-space rotation the frame's rays were sampled with (`null` if not reported).
## CameraController
diff --git a/src/RustPlusApi/Data/Cameras/CameraFrame.cs b/src/RustPlusApi/Data/Cameras/CameraFrame.cs
index 54da941..ac72fe7 100644
--- a/src/RustPlusApi/Data/Cameras/CameraFrame.cs
+++ b/src/RustPlusApi/Data/Cameras/CameraFrame.cs
@@ -31,4 +31,7 @@ public record CameraFrame
/// World-space rotation of the camera, if reported.
public Vector3? CameraRotation { get; init; }
+
+ /// World-space rotation the frame's rays were sampled with, if reported.
+ public Vector3? SampleRotation { get; init; }
}
diff --git a/src/RustPlusApi/Data/VendingMachineItem.cs b/src/RustPlusApi/Data/VendingMachineItem.cs
index 3f12025..b27530b 100644
--- a/src/RustPlusApi/Data/VendingMachineItem.cs
+++ b/src/RustPlusApi/Data/VendingMachineItem.cs
@@ -32,4 +32,7 @@ public sealed record VendingMachineItem
/// Price multiplier applied to the order, if reported.
public float? PriceMultiplier { get; init; }
+
+ /// Multiplier applied to the quantity actually received per transaction, if reported.
+ public float? ReceivedQuantityMultiplier { get; init; }
}
diff --git a/src/RustPlusApi/Extensions/AppCameraToModel.cs b/src/RustPlusApi/Extensions/AppCameraToModel.cs
index 40c8e4b..db2db7e 100644
--- a/src/RustPlusApi/Extensions/AppCameraToModel.cs
+++ b/src/RustPlusApi/Extensions/AppCameraToModel.cs
@@ -39,7 +39,8 @@ public static CameraFrame ToCameraFrame(this AppCameraRays appCameraRays)
Entities = appCameraRays.Entities.ToCameraEntities(),
TimeOfDay = appCameraRays.ShouldSerializeTimeOfDay() ? appCameraRays.TimeOfDay : null,
CameraPosition = appCameraRays.CameraPosition?.ToVector3(),
- CameraRotation = appCameraRays.CameraRotation?.ToVector3()
+ CameraRotation = appCameraRays.CameraRotation?.ToVector3(),
+ SampleRotation = appCameraRays.SampleRotation?.ToVector3()
};
}
@@ -56,7 +57,8 @@ public static CameraRaysEventArg ToCameraRaysEvent(this AppCameraRays appCameraR
Entities = appCameraRays.Entities.ToCameraEntities(),
TimeOfDay = appCameraRays.ShouldSerializeTimeOfDay() ? appCameraRays.TimeOfDay : null,
CameraPosition = appCameraRays.CameraPosition?.ToVector3(),
- CameraRotation = appCameraRays.CameraRotation?.ToVector3()
+ CameraRotation = appCameraRays.CameraRotation?.ToVector3(),
+ SampleRotation = appCameraRays.SampleRotation?.ToVector3()
};
}
diff --git a/src/RustPlusApi/Extensions/AppMarkerToModel.cs b/src/RustPlusApi/Extensions/AppMarkerToModel.cs
index a54f012..7a99854 100644
--- a/src/RustPlusApi/Extensions/AppMarkerToModel.cs
+++ b/src/RustPlusApi/Extensions/AppMarkerToModel.cs
@@ -76,7 +76,10 @@ public static VendingMachineItem ToVendingMachineItem(this SellOrder sellOrder)
IsCurrencyBlueprint = sellOrder.CurrencyIsBlueprint,
ItemLife = sellOrder.ItemCondition,
ItemMaxLife = sellOrder.ItemConditionMax,
- PriceMultiplier = sellOrder.ShouldSerializePriceMultiplier() ? sellOrder.PriceMultiplier : null
+ PriceMultiplier = sellOrder.ShouldSerializePriceMultiplier() ? sellOrder.PriceMultiplier : null,
+ ReceivedQuantityMultiplier = sellOrder.ShouldSerializeReceivedQuantityMultiplier()
+ ? sellOrder.ReceivedQuantityMultiplier
+ : null
};
}
diff --git a/src/RustPlusApi/Protobuf/RustPlusContracts.proto b/src/RustPlusApi/Protobuf/RustPlusContracts.proto
index 4a0fe63..288f845 100644
--- a/src/RustPlusApi/Protobuf/RustPlusContracts.proto
+++ b/src/RustPlusApi/Protobuf/RustPlusContracts.proto
@@ -335,6 +335,7 @@ message AppMarker {
optional float item_condition = 8;
optional float item_condition_max = 9;
optional float price_multiplier = 10;
+ optional float received_quantity_multiplier = 11;
}
}
@@ -424,6 +425,7 @@ message AppCameraRays {
optional float time_of_day = 6;
optional Vector3 camera_position = 7;
optional Vector3 camera_rotation = 8;
+ optional Vector3 sample_rotation = 9;
enum EntityType {
Tree = 1;
diff --git a/tests/RustPlusApi.UnitTests/CameraModelMapperTests.cs b/tests/RustPlusApi.UnitTests/CameraModelMapperTests.cs
index 09eb462..b6cfbe3 100644
--- a/tests/RustPlusApi.UnitTests/CameraModelMapperTests.cs
+++ b/tests/RustPlusApi.UnitTests/CameraModelMapperTests.cs
@@ -32,6 +32,7 @@ public void ToCameraFrame_NullRayData_BecomesEmpty_AndNullVectorsStayNull()
Assert.Null(frame.TimeOfDay);
Assert.Null(frame.CameraPosition);
Assert.Null(frame.CameraRotation);
+ Assert.Null(frame.SampleRotation);
Assert.Empty(frame.Entities);
}
@@ -50,6 +51,10 @@ public void ToCameraFrame_WithTimeOfDayAndCameraVectors_MapsThem()
CameraRotation = new ProtoVector3
{
X = 4, Y = 5, Z = 6
+ },
+ SampleRotation = new ProtoVector3
+ {
+ X = 7, Y = 8, Z = 9
}
};
@@ -58,6 +63,7 @@ public void ToCameraFrame_WithTimeOfDayAndCameraVectors_MapsThem()
Assert.Equal(0.5f, frame.TimeOfDay);
Assert.Equal(1, frame.CameraPosition!.X);
Assert.Equal(6, frame.CameraRotation!.Z);
+ Assert.Equal(9, frame.SampleRotation!.Z);
}
[Fact]
@@ -74,6 +80,7 @@ public void ToCameraRaysEvent_NullRayData_BecomesEmpty_AndNullVectorsStayNull()
Assert.Null(frame.TimeOfDay);
Assert.Null(frame.CameraPosition);
Assert.Null(frame.CameraRotation);
+ Assert.Null(frame.SampleRotation);
}
[Fact]
@@ -91,6 +98,10 @@ public void ToCameraRaysEvent_WithTimeOfDayAndCameraVectors_MapsThem()
CameraRotation = new ProtoVector3
{
X = 1, Y = 2, Z = 3
+ },
+ SampleRotation = new ProtoVector3
+ {
+ X = 4, Y = 5, Z = 6
}
};
@@ -99,5 +110,6 @@ public void ToCameraRaysEvent_WithTimeOfDayAndCameraVectors_MapsThem()
Assert.Equal(0.75f, frame.TimeOfDay);
Assert.Equal(10, frame.CameraPosition!.X);
Assert.Equal(3, frame.CameraRotation!.Z);
+ Assert.Equal(6, frame.SampleRotation!.Z);
}
}
diff --git a/tests/RustPlusApi.UnitTests/MarkerMapperTests.cs b/tests/RustPlusApi.UnitTests/MarkerMapperTests.cs
index a950ca0..7b4bbf3 100644
--- a/tests/RustPlusApi.UnitTests/MarkerMapperTests.cs
+++ b/tests/RustPlusApi.UnitTests/MarkerMapperTests.cs
@@ -6,7 +6,7 @@
namespace RustPlusApi.UnitTests;
/// Locks every projection in , including the sell-order
-/// presence fork on PriceMultiplier.
+/// presence forks on PriceMultiplier and ReceivedQuantityMultiplier.
public class MarkerMapperTests
{
private static AppMarker Marker(AppMarkerType type) => new()
@@ -78,6 +78,36 @@ public void ToVendingMachineItem_WhenPriceMultiplierUnset_IsNull()
Assert.Null(item.PriceMultiplier);
}
+ [Fact]
+ public void ToVendingMachineItem_WhenReceivedQuantityMultiplierSet_MapsValue()
+ {
+ var order = new SellOrder
+ {
+ ItemId = 9,
+ Quantity = 1,
+ CostPerItem = 1,
+ AmountInStock = 1,
+ ReceivedQuantityMultiplier = 2.5f
+ };
+
+ var item = order.ToVendingMachineItem();
+
+ Assert.Equal(2.5f, item.ReceivedQuantityMultiplier);
+ }
+
+ [Fact]
+ public void ToVendingMachineItem_WhenReceivedQuantityMultiplierUnset_IsNull()
+ {
+ var order = new SellOrder
+ {
+ ItemId = 9, Quantity = 1, CostPerItem = 1, AmountInStock = 1
+ };
+
+ var item = order.ToVendingMachineItem();
+
+ Assert.Null(item.ReceivedQuantityMultiplier);
+ }
+
[Theory]
[InlineData(AppMarkerType.Ch47)]
[InlineData(AppMarkerType.CargoShip)]