diff --git a/.timetracker b/.timetracker index 9a4b034..b100bc3 100644 --- a/.timetracker +++ b/.timetracker @@ -1,5 +1,5 @@ { - "total": 665981, + "total": 673269, "sessions": [ { "begin": "2026-01-09T17:26:02+01:00", @@ -1530,6 +1530,11 @@ "begin": "2026-05-25T04:46:47+02:00", "end": "2026-05-25T05:48:38+02:00", "duration": 3710 + }, + { + "begin": "2026-05-25T05:48:38+02:00", + "end": "2026-05-25T07:50:07+02:00", + "duration": 7288 } ] } \ No newline at end of file diff --git a/OrekiWoofsBees.Common/CompatibilityUtil.cs b/OrekiWoofsBees.Common/CompatibilityUtil.cs new file mode 100644 index 0000000..a05aaf5 --- /dev/null +++ b/OrekiWoofsBees.Common/CompatibilityUtil.cs @@ -0,0 +1,54 @@ +using System; +using System.Linq.Expressions; +using System.Reflection; +using Vintagestory.API.Common; + +namespace OrekiWoofsBees.Common; + +public static class CompatibilityUtil +{ + private const string fruiting_bush_behavior_name = "BEBehaviorFruitingBush"; + private const string b_state_field_name = "BState"; + private const string growthstate_property_name = "Growthstate"; + private const int flowering_growth_state_value = 2; + + private static System.Func? is_fruiting_bush_flowering_check; + + public static bool IsFruitingBushFlowering(this BlockEntityBehavior behavior) + { + var behaviorType = behavior.GetType(); + if (!IsFruitingBushBehaviorType(behaviorType)) + return false; + + var check = is_fruiting_bush_flowering_check ??= BuildIsFruitingBushFloweringCheck(behaviorType); + return check(behavior); + } + + private static bool IsFruitingBushBehaviorType(Type behaviorType) + { + for (var type = behaviorType; type is not null; type = type.BaseType) + { + if (type.Name == fruiting_bush_behavior_name) + return true; + } + + return false; + } + + private static System.Func BuildIsFruitingBushFloweringCheck(Type behaviorType) + { + var bStateField = behaviorType.GetField(b_state_field_name, BindingFlags.Instance | BindingFlags.Public)!; + var growthStateProperty = bStateField.FieldType.GetProperty(growthstate_property_name, BindingFlags.Instance | BindingFlags.Public)!; + + var behaviorParameter = Expression.Parameter(typeof(BlockEntityBehavior), "behavior"); + var typedBehavior = Expression.Convert(behaviorParameter, behaviorType); + var bState = Expression.Field(typedBehavior, bStateField); + var growthState = Expression.Property(bState, growthStateProperty); + + var comparison = Expression.Equal( + Expression.Convert(growthState, typeof(int)), + Expression.Constant(flowering_growth_state_value)); + + return Expression.Lambda>(comparison, behaviorParameter).Compile(); + } +} \ No newline at end of file diff --git a/OrekiWoofsBees.Common/PlantRecognitionUtilities.cs b/OrekiWoofsBees.Common/PlantRecognitionUtilities.cs index 90ca3c9..ecbabb7 100644 --- a/OrekiWoofsBees.Common/PlantRecognitionUtilities.cs +++ b/OrekiWoofsBees.Common/PlantRecognitionUtilities.cs @@ -15,9 +15,23 @@ public static class PlantRecognitionUtilities public static bool IsFlower(Block block, IBlockAccessor accessor, BlockPos pos) { - if (block.FirstCodePart() == "flower") + var code = block.FirstCodePart(); + if (code == "flower") return true; + if (code == "fruitingbush") + { + var blockEntity = accessor.GetBlockEntity(pos); + if (blockEntity is null) + return false; + + foreach (var behavior in blockEntity.Behaviors) + { + if (behavior.IsFruitingBushFlowering()) + return true; + } + } + if (block is BlockPlantContainer) { var plantContainer = block.GetBlockEntity(pos);