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)]