Compare commits
10 Commits
v2.0.0-rc.
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a1f3f16bf | |||
| 44e0ea15ff | |||
| 3f928fa4bc | |||
| 136826aa68 | |||
| c5d34ec1b5 | |||
| d7ca3f8e99 | |||
| b8e356cb23 | |||
| 6813ac84d0 | |||
| afdf3425b0 | |||
| 0f1bcece53 |
42
.timetracker
42
.timetracker
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"total": 658541,
|
||||
"total": 676860,
|
||||
"sessions": [
|
||||
{
|
||||
"begin": "2026-01-09T17:26:02+01:00",
|
||||
@@ -1510,6 +1510,46 @@
|
||||
"begin": "2026-05-24T10:45:43+02:00",
|
||||
"end": "2026-05-24T11:14:02+02:00",
|
||||
"duration": 1698
|
||||
},
|
||||
{
|
||||
"begin": "2026-05-24T12:55:01+02:00",
|
||||
"end": "2026-05-24T13:15:18+02:00",
|
||||
"duration": 1217
|
||||
},
|
||||
{
|
||||
"begin": "2026-05-24T13:16:44+02:00",
|
||||
"end": "2026-05-24T13:38:36+02:00",
|
||||
"duration": 1312
|
||||
},
|
||||
{
|
||||
"begin": "2026-05-25T02:37:48+02:00",
|
||||
"end": "2026-05-25T02:57:49+02:00",
|
||||
"duration": 1201
|
||||
},
|
||||
{
|
||||
"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
|
||||
},
|
||||
{
|
||||
"begin": "2026-05-25T07:57:23+02:00",
|
||||
"end": "2026-05-25T08:19:38+02:00",
|
||||
"duration": 1334
|
||||
},
|
||||
{
|
||||
"begin": "2026-05-25T08:27:09+02:00",
|
||||
"end": "2026-05-25T08:50:02+02:00",
|
||||
"duration": 1373
|
||||
},
|
||||
{
|
||||
"begin": "2026-05-25T09:06:05+02:00",
|
||||
"end": "2026-05-25T09:20:50+02:00",
|
||||
"duration": 884
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public class BlockBehaviorBeehiveAffected(Block block) : BlockBehavior(block)
|
||||
: " " + Lang.Get("orekiwoofsbeehives:blockinfo-as-a-plant", GetLocalizedPlantTypeText(isFlower, isCrop));
|
||||
|
||||
var inRangeText = Lang.Get("orekiwoofsbeehives:blockinfo-in-range-beehive", beehiveCount);
|
||||
return inRangeText + growthOrPlantText;
|
||||
return '\n' + inRangeText + growthOrPlantText;
|
||||
}
|
||||
|
||||
private static string GetLocalizedPlantTypeText(bool isFlower, bool isCrop)
|
||||
|
||||
@@ -104,7 +104,7 @@ public readonly record struct BeehiveStats
|
||||
currentTemperature += 5;
|
||||
|
||||
if (OrekiWoofsBeehivesModSystem.IsSteadyGreenhousesLoaded)
|
||||
return Math.Max(currentTemperature, Config.Instance.MaxTemperatureGrowth);
|
||||
return Math.Max(currentTemperature, Config.Instance.TemperatureOptimal);
|
||||
|
||||
return currentTemperature;
|
||||
}
|
||||
@@ -113,13 +113,13 @@ public readonly record struct BeehiveStats
|
||||
{
|
||||
var cfg = Config.Instance;
|
||||
|
||||
if (currentTemperature >= cfg.MaxTemperatureGrowth)
|
||||
if (currentTemperature >= cfg.TemperatureOptimal)
|
||||
return 1.0;
|
||||
if (currentTemperature <= cfg.MinTemperatureGrowth)
|
||||
if (currentTemperature <= cfg.TemperatureMinimum)
|
||||
return 0.0;
|
||||
|
||||
float temperatureRange = cfg.MaxTemperatureGrowth - cfg.MinTemperatureGrowth;
|
||||
return (currentTemperature - cfg.MinTemperatureGrowth) / temperatureRange;
|
||||
float temperatureRange = cfg.TemperatureOptimal - cfg.TemperatureMinimum;
|
||||
return (currentTemperature - cfg.TemperatureMinimum) / temperatureRange;
|
||||
}
|
||||
|
||||
private static double CalculateFramesPerDay(BlockEntityReusableBeehive beehive, double temperatureMultiplier)
|
||||
@@ -161,16 +161,16 @@ public readonly record struct BeehiveStats
|
||||
private static double GetWinterReverseRamp(float currentTemperature)
|
||||
{
|
||||
var cfg = Config.Instance;
|
||||
if (currentTemperature >= cfg.MaxTemperatureGrowth)
|
||||
if (currentTemperature >= cfg.TemperatureOptimal)
|
||||
return 0;
|
||||
if (currentTemperature <= cfg.MinTemperatureGrowth)
|
||||
if (currentTemperature <= cfg.TemperatureMinimum)
|
||||
return 1;
|
||||
|
||||
float temperatureRange = cfg.MaxTemperatureGrowth - cfg.MinTemperatureGrowth;
|
||||
float temperatureRange = cfg.TemperatureOptimal - cfg.TemperatureMinimum;
|
||||
if (temperatureRange <= 0)
|
||||
return 1;
|
||||
|
||||
return 1.0 - ((currentTemperature - cfg.MinTemperatureGrowth) / temperatureRange);
|
||||
return 1.0 - ((currentTemperature - cfg.TemperatureMinimum) / temperatureRange);
|
||||
}
|
||||
|
||||
private static double GetEffectiveFlowers(BlockEntityReusableBeehive beehive)
|
||||
|
||||
@@ -22,7 +22,7 @@ public class BlockEntityReusableBeehive : BlockEntityContainer, IModEntity
|
||||
|
||||
private readonly Stopwatch stopwatch = new();
|
||||
private readonly StringBuilder infoStringBuilder = new();
|
||||
private readonly InventoryGeneric inventory;
|
||||
private readonly InventoryGeneric inventory = new(8, null, null);
|
||||
private double lastUpdateTotalHours = 0;
|
||||
private bool wasFullyScanned;
|
||||
private float? scanningProgress;
|
||||
@@ -32,6 +32,7 @@ public class BlockEntityReusableBeehive : BlockEntityContainer, IModEntity
|
||||
private bool isInGreenhouse;
|
||||
private BlockPos? activeSwarmPos;
|
||||
private BlockPos? incomingSwarmPos;
|
||||
private int? registeredRadius;
|
||||
|
||||
public override InventoryBase Inventory => inventory;
|
||||
public override string InventoryClassName => "beehive";
|
||||
@@ -53,11 +54,6 @@ public class BlockEntityReusableBeehive : BlockEntityContainer, IModEntity
|
||||
|
||||
public Mod? Mod { get; private set; }
|
||||
|
||||
public BlockEntityReusableBeehive()
|
||||
{
|
||||
inventory = new InventoryGeneric(8, null, null);
|
||||
}
|
||||
|
||||
public bool IsOpen { get; set; }
|
||||
|
||||
public override void Initialize(ICoreAPI api)
|
||||
@@ -82,6 +78,7 @@ public class BlockEntityReusableBeehive : BlockEntityContainer, IModEntity
|
||||
}
|
||||
|
||||
plantPositionRegistry.RegisterBeehive(Pos, Config.Instance.BeehiveRadius);
|
||||
registeredRadius = Config.Instance.BeehiveRadius;
|
||||
|
||||
var beehivesModSystem = Api.GetOrekiWoofsBeehives();
|
||||
if (beehivesModSystem is null)
|
||||
@@ -152,10 +149,35 @@ public class BlockEntityReusableBeehive : BlockEntityContainer, IModEntity
|
||||
stopwatch.LogTime(this, 0.05, "after flowers and crops");
|
||||
UpdateBeePopulationAndHoney();
|
||||
stopwatch.LogTime(this, 0.05, "after population and honey");
|
||||
UpdateRadius();
|
||||
|
||||
stopwatch.StopAndLogTime(this, 0.05);
|
||||
}
|
||||
|
||||
private void UpdateRadius()
|
||||
{
|
||||
if (registeredRadius == Config.Instance.BeehiveRadius)
|
||||
return;
|
||||
|
||||
scanningProgress = 0;
|
||||
rescanningProgress = 0;
|
||||
FlowersAround = null;
|
||||
CropsAround = null;
|
||||
wasFullyScanned = false;
|
||||
|
||||
var plantPositionRegistry = Api.GetPlantPositionRegistry();
|
||||
try
|
||||
{
|
||||
plantPositionRegistry?.UpdateBeehiveRadius(Pos, Config.Instance.BeehiveRadius);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Mod?.Logger.Warning("Couldn't update radius");
|
||||
Mod?.Logger.Warning(e);
|
||||
}
|
||||
registeredRadius = Config.Instance.BeehiveRadius;
|
||||
}
|
||||
|
||||
private void ClearStaleIncomingSwarmReservation()
|
||||
{
|
||||
if (incomingSwarmPos == null)
|
||||
@@ -309,7 +331,7 @@ public class BlockEntityReusableBeehive : BlockEntityContainer, IModEntity
|
||||
var cfg = Config.Instance;
|
||||
var ratePerHour = 1.0 / Math.Max(1, cfg.PreSwarmDurationHours);
|
||||
|
||||
if (stats.Components.Temperature >= cfg.MaxTemperatureGrowth)
|
||||
if (stats.Components.Temperature >= cfg.TemperatureOptimal)
|
||||
PreSwarmProgress += ratePerHour * hoursElapsed;
|
||||
else
|
||||
PreSwarmProgress -= ratePerHour * hoursElapsed;
|
||||
|
||||
@@ -527,9 +527,9 @@ public class BlockReusableBeehive : Block
|
||||
return baseColor;
|
||||
|
||||
if (IsFilledFeedFrame(be.Inventory[slotIndex].Itemstack))
|
||||
return new Vec4f(0.8f, 0.2f, 0f, baseColor.A);
|
||||
return new Vec4f(0.8f / 3f, 0.2f / 3f, 0f, baseColor.A);
|
||||
|
||||
return new Vec4f(0.6f, 0.3f, 0f, baseColor.A);
|
||||
return new Vec4f(0.2f, 0.1f, 0f, baseColor.A);
|
||||
}
|
||||
|
||||
private static bool IsFrame(ItemStack? stack)
|
||||
|
||||
@@ -91,7 +91,7 @@ public class Config
|
||||
|
||||
[ProtoMember(57)]
|
||||
[ConfigCommand(serverSide: true)]
|
||||
public bool SwarmSettingAfterPlacing { get; set; } = false;
|
||||
public bool SwarmSettingAfterPlacing { get; set; } = true;
|
||||
|
||||
[ProtoMember(5)]
|
||||
[ConfigCommand(serverSide: true, Min = 0, Max = 1000)]
|
||||
@@ -142,11 +142,11 @@ public class Config
|
||||
// weather effects
|
||||
[ProtoMember(15)]
|
||||
[ConfigCommand(serverSide: true, Min = -20, Max = 20)]
|
||||
public float MinTemperatureGrowth { get; set; } = 0f;
|
||||
public float TemperatureMinimum { get; set; } = 0f;
|
||||
|
||||
[ProtoMember(16)]
|
||||
[ConfigCommand(serverSide: true, Min = 0, Max = 40)]
|
||||
public float MaxTemperatureGrowth { get; set; } = 10f;
|
||||
public float TemperatureOptimal { get; set; } = 10f;
|
||||
|
||||
[ProtoMember(35)]
|
||||
[ConfigCommand(serverSide: true)]
|
||||
@@ -164,7 +164,7 @@ public class Config
|
||||
// client-side
|
||||
[ProtoMember(29)]
|
||||
[ConfigCommand(serverSide: false, Min = 0, Max = 4)]
|
||||
public int InformationVerbosity { get; set; } = 1;
|
||||
public int InformationVerbosity { get; set; } = 2;
|
||||
|
||||
[ProtoMember(44)]
|
||||
[ConfigCommand(serverSide: false)]
|
||||
|
||||
@@ -96,7 +96,7 @@ public static class BeehiveInfoStringBuilder
|
||||
}
|
||||
|
||||
var cfg = Config.Instance;
|
||||
var isIncreasing = stats.Components.Temperature >= cfg.MaxTemperatureGrowth;
|
||||
var isIncreasing = stats.Components.Temperature >= cfg.TemperatureOptimal;
|
||||
|
||||
string detail;
|
||||
if (isIncreasing)
|
||||
@@ -337,9 +337,9 @@ public static class BeehiveInfoStringBuilder
|
||||
|
||||
if (verbosity is >= 1 and < 3)
|
||||
{
|
||||
if (temperature <= cfg.MinTemperatureGrowth)
|
||||
if (temperature <= cfg.TemperatureMinimum)
|
||||
builder.AppendLine(Lang.Get("orekiwoofsbeehives:beehive-info-temperature-overwintering"));
|
||||
else if (temperature < cfg.MaxTemperatureGrowth)
|
||||
else if (temperature < cfg.TemperatureOptimal)
|
||||
builder.AppendLine(Lang.Get("orekiwoofsbeehives:beehive-info-temperature-cold"));
|
||||
}
|
||||
else
|
||||
@@ -356,7 +356,7 @@ public static class BeehiveInfoStringBuilder
|
||||
|
||||
if (cfg.WinterHardMode
|
||||
&& stats.Components.FilledFramesCount <= 0
|
||||
&& temperature <= cfg.MinTemperatureGrowth)
|
||||
&& temperature <= cfg.TemperatureMinimum)
|
||||
builder.AppendLine($"<font color=\"#ff0000\">{Lang.Get("orekiwoofsbeehives:beehive-info-winter-starving")}</font>");
|
||||
}
|
||||
|
||||
|
||||
@@ -64,10 +64,11 @@ public partial class OrekiWoofsBeehivesModSystem : ModSystem
|
||||
Config.Instance ??= new Config();
|
||||
|
||||
ConvertOldCropBonus(oldCropBonus, Config.Instance);
|
||||
var temperatureMigrated = ConvertBackCompatibilityTemperature(api, Config.Instance);
|
||||
|
||||
api.StoreModConfig(Config.Instance, config_filename);
|
||||
|
||||
if (oldCropBonus is not null && api.ModLoader.IsModEnabled("configlib"))
|
||||
if ((oldCropBonus is not null || temperatureMigrated) && api.ModLoader.IsModEnabled("configlib"))
|
||||
ReloadConfigForConfigLib(api);
|
||||
|
||||
api.Event.PlayerJoin += OnPlayerJoin;
|
||||
@@ -176,4 +177,33 @@ public partial class OrekiWoofsBeehivesModSystem : ModSystem
|
||||
|
||||
Mod.Logger.Event($"Converted CropBonus:{cropBonus} to YieldBoost:{config.YieldBoost}, SpeedBoost:{config.SpeedBoost}");
|
||||
}
|
||||
|
||||
private bool ConvertBackCompatibilityTemperature(ICoreAPI api, Config config)
|
||||
{
|
||||
const string old_min_temperature_growth_key = "MinTemperatureGrowth";
|
||||
const string old_max_temperature_growth_key = "MaxTemperatureGrowth";
|
||||
|
||||
var cfgJson = api.LoadModConfig(config_filename);
|
||||
if (cfgJson is null)
|
||||
return false;
|
||||
|
||||
var migrated = false;
|
||||
|
||||
if (!cfgJson.KeyExists(nameof(Config.TemperatureMinimum)) && cfgJson.KeyExists(old_min_temperature_growth_key))
|
||||
{
|
||||
config.TemperatureMinimum = cfgJson[old_min_temperature_growth_key].AsFloat(config.TemperatureMinimum);
|
||||
migrated = true;
|
||||
}
|
||||
|
||||
if (!cfgJson.KeyExists(nameof(Config.TemperatureOptimal)) && cfgJson.KeyExists(old_max_temperature_growth_key))
|
||||
{
|
||||
config.TemperatureOptimal = cfgJson[old_max_temperature_growth_key].AsFloat(config.TemperatureOptimal);
|
||||
migrated = true;
|
||||
}
|
||||
|
||||
if (migrated)
|
||||
Mod.Logger.Event($"Converted legacy temperature config values to TemperatureMinimum:{config.TemperatureMinimum}, TemperatureOptimal:{config.TemperatureOptimal}");
|
||||
|
||||
return migrated;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"code": "InformationVerbosity",
|
||||
"comment": "config-desc-InformationVerbosity",
|
||||
"type": "int",
|
||||
"default": 1,
|
||||
"default": 2,
|
||||
"range": {
|
||||
"min": 0,
|
||||
"max": 4
|
||||
@@ -256,7 +256,7 @@
|
||||
"code": "SwarmSettingAfterPlacing",
|
||||
"comment": "config-desc-SwarmSettingAfterPlacing",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"code": "PreSwarmDurationHours",
|
||||
@@ -387,8 +387,8 @@
|
||||
"title": "Weather Effects"
|
||||
},
|
||||
{
|
||||
"code": "MinTemperatureGrowth",
|
||||
"comment": "config-desc-MinTemperatureGrowth",
|
||||
"code": "TemperatureMinimum",
|
||||
"comment": "config-desc-TemperatureMinimum",
|
||||
"type": "float",
|
||||
"default": 0.0,
|
||||
"range": {
|
||||
@@ -397,8 +397,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "MaxTemperatureGrowth",
|
||||
"comment": "config-desc-MaxTemperatureGrowth",
|
||||
"code": "TemperatureOptimal",
|
||||
"comment": "config-desc-TemperatureOptimal",
|
||||
"type": "float",
|
||||
"default": 10.0,
|
||||
"range": {
|
||||
|
||||
@@ -112,8 +112,8 @@
|
||||
"config-desc-WinterHardMode": "Enables winter hard mode for additional winter mechanics.",
|
||||
"config-desc-WinterDailyBeeDeathsWithoutFood": "Extra daily bee deaths in winter when there are no filled/feed frames. Works only with WinterHardMode enabled.",
|
||||
"config-desc-WinterFoodConsumptionMultiplier": "Winter food consumption multiplier (0-1). From 10C to 0C this effect ramps up in reverse relative to honey production; below 0C it stays at max. Works only with WinterHardMode enabled.",
|
||||
"config-desc-MinTemperatureGrowth": "Temperature at which bee growth and honey production stops.",
|
||||
"config-desc-MaxTemperatureGrowth": "Temperature at which bee growth and honey production reaches maximum.",
|
||||
"config-desc-TemperatureMinimum": "Temperature at which bee growth and honey production stops.",
|
||||
"config-desc-TemperatureOptimal": "Temperature at which bee growth and honey production reaches maximum.",
|
||||
"config-desc-GreenhouseAffectsBeehive": "Whether greenhouses give 5C temperature boost to the beehive.",
|
||||
"config-desc-BeesPerParticle": "Number of bees represented by each particle group. If this is 1000, there are 5000 bees in a beehive, then the beehive will spawn at most 5 particles.",
|
||||
"config-desc-BeehiveAlwaysSpawnNumberOfBees": "Will spawn this amount of bees per beehive block, regardless of their population.",
|
||||
@@ -128,7 +128,7 @@
|
||||
"blockhelp-beehive-enable-swarm": "Enable swarming",
|
||||
"blockhelp-beehive-disable-swarm": "Disable swarming",
|
||||
"config-desc-EnableSwarms": "Whether beehives can produce swarms.",
|
||||
"config-desc-PreSwarmDurationHours": "Duration in hours for bees to build up their swarm urge (0 to 100%). Progress only increases at MaxTemperatureGrowth or higher; otherwise it decreases.",
|
||||
"config-desc-PreSwarmDurationHours": "Duration in hours for bees to build up their swarm urge (0 to 100%). Progress only increases at TemperatureOptimal or higher; otherwise it decreases.",
|
||||
"config-desc-SwarmSettingAfterPlacing": "Whether a newly placed beehive has swarming enabled or disabled. Can be changed with a wrench.",
|
||||
"setpopulation-desc": "Set bee population of the beehive block you are currently looking at.",
|
||||
"debugunload-desc": "Enable or disable unload catch-up debug messages in server chat.",
|
||||
|
||||
@@ -111,8 +111,8 @@
|
||||
"config-desc-WinterHardMode": "Включает усложнённый зимний режим с дополнительными зимними механиками.",
|
||||
"config-desc-WinterDailyBeeDeathsWithoutFood": "Дополнительная ежедневная гибель пчёл зимой, когда нет заполненных/кормовых рамок. Работает только с включенным WinterHardMode.",
|
||||
"config-desc-WinterFoodConsumptionMultiplier": "Коэффициент потребления зимних продуктов питания (0-1). При температуре от 10° C до 0° C этот эффект увеличивается в обратном направлении относительно производства мёда; при температуре ниже 0° C он остается максимальным. Работает только при включенном режиме WinterHardMode.",
|
||||
"config-desc-MinTemperatureGrowth": "Температура, при которой прекращается рост пчёл и производство мёда.",
|
||||
"config-desc-MaxTemperatureGrowth": "Температура, при которой рост пчёл и производство мёда достигают максимума.",
|
||||
"config-desc-TemperatureMinimum": "Температура, при которой прекращается рост пчёл и производство мёда.",
|
||||
"config-desc-TemperatureOptimal": "Температура, при которой рост пчёл и производство мёда достигают максимума.",
|
||||
"config-desc-GreenhouseAffectsBeehive": "Дают ли теплицы повышение температуры в улье на 5°C.",
|
||||
"config-desc-BeesPerParticle": "Количество пчёл, представленных каждой группой частиц. Если это 1000, а в улье 5000 пчёл, тогда улей породит не более 5 частиц.",
|
||||
"config-desc-BeehiveAlwaysSpawnNumberOfBees": "Всегда создаёт указанное количество пчёл на блок улья независимо от их численности.",
|
||||
@@ -127,7 +127,7 @@
|
||||
"blockhelp-beehive-enable-swarm": "Включить роение",
|
||||
"blockhelp-beehive-disable-swarm": "Отключить роение",
|
||||
"config-desc-EnableSwarms": "Определяет, могут ли ульи выпускать рои.",
|
||||
"config-desc-PreSwarmDurationHours": "Время в часах, за которое у пчёл накапливается готовность к роению (0–100%). Прогресс растёт только при MaxTemperatureGrowth или выше, иначе уменьшается.",
|
||||
"config-desc-PreSwarmDurationHours": "Время в часах, за которое у пчёл накапливается готовность к роению (0–100%). Прогресс растёт только при TemperatureOptimal или выше, иначе уменьшается.",
|
||||
"config-desc-SwarmSettingAfterPlacing": "Будет ли в только что установленном улье включено или отключено роение. Можно изменить гаечным ключом.",
|
||||
"setpopulation-desc": "Установить численность пчёл в улье, на который вы сейчас смотрите.",
|
||||
"debugunload-desc": "Включить или отключить отладочные сообщения догоняющей обработки после выгрузки в чате сервера.",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"OrekiWoof"
|
||||
],
|
||||
"description": "Beehive with 8 slots for honey frames. Boosts your plants.",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.0.0",
|
||||
"dependencies": {
|
||||
"game": "1.21.0"
|
||||
}
|
||||
|
||||
54
OrekiWoofsBees.Common/CompatibilityUtil.cs
Normal file
54
OrekiWoofsBees.Common/CompatibilityUtil.cs
Normal file
@@ -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<BlockEntityBehavior, bool>? 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<BlockEntityBehavior, bool> 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<System.Func<BlockEntityBehavior, bool>>(comparison, behaviorParameter).Compile();
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,8 @@ public interface IPlantPositionRegistry
|
||||
|
||||
void RegisterBeehive(BlockPos pos, int radius);
|
||||
|
||||
void UpdateBeehiveRadius(BlockPos pos, int radius);
|
||||
|
||||
void RemovePlantPosition(BlockPos pos, Block block);
|
||||
|
||||
void UnregisterBeehive(BlockPos pos);
|
||||
|
||||
@@ -22,6 +22,8 @@ public class PlantPositionRegistryModSystem2 : ModSystem, IPlantPositionRegistry
|
||||
|
||||
private static readonly Dictionary<int, ScanOffsetTable> offsetTables = [];
|
||||
|
||||
private readonly Stopwatch getCountsStopwatch = new();
|
||||
private readonly Stopwatch getPlantsStopwatch = new();
|
||||
private long? tickListenerId;
|
||||
private readonly Dictionary<StructVec3i, BeehiveScanCursor> beehives = [];
|
||||
private readonly HashSet<StructVec3i> flowerPositions = [];
|
||||
@@ -77,6 +79,15 @@ public class PlantPositionRegistryModSystem2 : ModSystem, IPlantPositionRegistry
|
||||
beehives[key] = new BeehiveScanCursor(pos, radius);
|
||||
}
|
||||
|
||||
public void UpdateBeehiveRadius(BlockPos pos, int radius)
|
||||
{
|
||||
if (!offsetTables.ContainsKey(radius))
|
||||
offsetTables[radius] = new ScanOffsetTable(radius);
|
||||
|
||||
var key = StructVec3i.FromBlockPos(pos);
|
||||
beehives[key] = new BeehiveScanCursor(pos, radius);
|
||||
}
|
||||
|
||||
public void UnregisterBeehive(BlockPos pos)
|
||||
{
|
||||
var key = StructVec3i.FromBlockPos(pos);
|
||||
@@ -88,6 +99,7 @@ public class PlantPositionRegistryModSystem2 : ModSystem, IPlantPositionRegistry
|
||||
float RescanProgress
|
||||
) GetPlantsNearPosition(BlockPos hivePos, int radius, List<StructVec3i> flowerPositionsBuffer, List<StructVec3i> cropPositionsBuffer)
|
||||
{
|
||||
getPlantsStopwatch.Restart();
|
||||
flowerPositionsBuffer.Clear();
|
||||
cropPositionsBuffer.Clear();
|
||||
|
||||
@@ -119,11 +131,13 @@ public class PlantPositionRegistryModSystem2 : ModSystem, IPlantPositionRegistry
|
||||
rescanProgress = cursor.GetRescanProgress(offsetTables);
|
||||
}
|
||||
|
||||
getPlantsStopwatch.StopAndLogTime(this, 0.1, $"radius: {radius}, in: {initialProgress}, re: {rescanProgress}, totals: {flowerPositions.Count}+{cropPositions.Count}");
|
||||
return (initialProgress, rescanProgress);
|
||||
}
|
||||
|
||||
public (int FlowerCount, int CropCount, float InitialScanProgress, float RescanProgress) GetPlantCountsNearPosition(BlockPos hivePos, int radius)
|
||||
{
|
||||
getCountsStopwatch.Restart();
|
||||
int flowers = 0;
|
||||
foreach (var flowerPos in flowerPositions)
|
||||
{
|
||||
@@ -151,6 +165,7 @@ public class PlantPositionRegistryModSystem2 : ModSystem, IPlantPositionRegistry
|
||||
rescanProgress = cursor.GetRescanProgress(offsetTables);
|
||||
}
|
||||
|
||||
getCountsStopwatch.StopAndLogTime(this, 0.1, $"radius: {radius}, fl: {flowers}, cr: {crops}, in: {initialProgress}, re: {rescanProgress}, totals: {flowerPositions.Count}+{cropPositions.Count}");
|
||||
return (flowers, crops, initialProgress, rescanProgress);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<BlockEntityPlantContainer?>(pos);
|
||||
|
||||
@@ -39,6 +39,7 @@ public class BlockEntityBehaviorRoamingBees(BlockEntity blockEntity) : BlockEnti
|
||||
|
||||
private ClimateCondition? climate;
|
||||
private Vec3d? windVec;
|
||||
private int? registeredRadius;
|
||||
private int onParticleTickStopwatchTriggerCount;
|
||||
private int spawnStopwatchTriggerCount;
|
||||
private readonly Stopwatch plantInfoStopwatch = new();
|
||||
@@ -87,6 +88,7 @@ public class BlockEntityBehaviorRoamingBees(BlockEntity blockEntity) : BlockEnti
|
||||
plantPositionRegistry = api.GetPlantPositionRegistry();
|
||||
var radius = GetRadiusFromBlockEntity();
|
||||
plantPositionRegistry?.RegisterBeehive(Blockentity.Pos, radius);
|
||||
registeredRadius = radius;
|
||||
|
||||
var updateFrequency = 20;
|
||||
Blockentity.RegisterGameTickListener(OnParticleTick, updateFrequency);
|
||||
@@ -116,13 +118,13 @@ public class BlockEntityBehaviorRoamingBees(BlockEntity blockEntity) : BlockEnti
|
||||
climate = Api.World.BlockAccessor.GetClimateAt(Blockentity.Pos, EnumGetClimateMode.NowValues);
|
||||
}
|
||||
|
||||
private readonly TreeAttribute _tempTreeAttribute = new();
|
||||
private int GetRadiusFromBlockEntity()
|
||||
{
|
||||
var radius = properties[RADIUS_ATTRIBUTE].AsInt(10);
|
||||
|
||||
var tree = new TreeAttribute();
|
||||
Blockentity.ToTreeAttributes(tree);
|
||||
radius = tree.GetAsInt(RADIUS_ATTRIBUTE, radius);
|
||||
_tempTreeAttribute.Clear();
|
||||
Blockentity.ToTreeAttributes(_tempTreeAttribute);
|
||||
radius = _tempTreeAttribute.GetAsInt(RADIUS_ATTRIBUTE, radius);
|
||||
return radius;
|
||||
}
|
||||
|
||||
@@ -230,10 +232,31 @@ public class BlockEntityBehaviorRoamingBees(BlockEntity blockEntity) : BlockEnti
|
||||
|
||||
plantInfoStopwatch.Restart();
|
||||
UpdatePlantInfo();
|
||||
UpdateRadius();
|
||||
|
||||
var note = $"global bees: {modSystem?.GlobalActiveBees}, registered hives: {modSystem?.BeeSpawnPacketDistributor?.SpawnHandlersCount}, radius: {Config.Instance.BeeRoamingRadius}";
|
||||
plantInfoStopwatch.StopAndLogTime(this, 0.1, note);
|
||||
}
|
||||
|
||||
private void UpdateRadius()
|
||||
{
|
||||
var radius = GetRadiusFromBlockEntity();
|
||||
if (registeredRadius == radius)
|
||||
return;
|
||||
|
||||
var plantPositionRegistry = Api.GetPlantPositionRegistry();
|
||||
try
|
||||
{
|
||||
plantPositionRegistry?.UpdateBeehiveRadius(Pos, radius);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Mod?.Logger.Warning("Couldn't update radius");
|
||||
Mod?.Logger.Warning(e);
|
||||
}
|
||||
registeredRadius = radius;
|
||||
}
|
||||
|
||||
private bool ShouldTick()
|
||||
{
|
||||
if (Block is BlockSkep && !Config.Instance.EnableOnVanillaSkeps)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"OrekiWoof"
|
||||
],
|
||||
"description": "Cute immersive roaming bees. Now on vanilla skeps and other mods' hives.",
|
||||
"version": "2.0.0-rc.1",
|
||||
"version": "2.0.0",
|
||||
"dependencies": {
|
||||
"game": "1.21.0"
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
## 1) ClientSide mode
|
||||
- Server: `InformationVerbosityServerSideType=ClientSide`, `InformationVerbosityServer=4`
|
||||
- Client: `InformationVerbosity=1`
|
||||
- Expected: client uses `1`
|
||||
- Client: `InformationVerbosity=2`
|
||||
- Expected: client uses `2`
|
||||
|
||||
## 2) ServerRecommended mode (override OFF)
|
||||
- Server: `InformationVerbosityServerSideType=ServerRecommended`, `InformationVerbosityServer=4`
|
||||
@@ -12,11 +12,11 @@
|
||||
|
||||
## 3) ServerRecommended mode (override ON)
|
||||
- Same as above, but `DisableServerRecommended=true`
|
||||
- Expected: client uses `1`
|
||||
- Expected: client uses `2`
|
||||
|
||||
## 4) ServerForced mode
|
||||
- Server: `InformationVerbosityServerSideType=ServerForced`, `InformationVerbosityServer=4`
|
||||
- Client: `InformationVerbosity=1`, `DisableServerRecommended=true`
|
||||
- Client: `InformationVerbosity=2`, `DisableServerRecommended=true`
|
||||
- Expected: client uses `4`
|
||||
|
||||
## 5) Client-side settings stay client-side
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
/beehives BeehiveConsideredEmptyBelowPopulation 500
|
||||
/beehives PopulationPercentRequirementForSwarm 80
|
||||
/beehives SwarmPopulationPercentage 0.2
|
||||
/beehives MaxTemperatureGrowth 10
|
||||
/beehives TemperatureOptimal 10
|
||||
```
|
||||
|
||||
## 1) Open-for-incoming is always below-threshold
|
||||
@@ -44,13 +44,13 @@
|
||||
|
||||
## 2b) Pre-swarm progress builds at optimal temperature
|
||||
- Source hive above required percent, cooldown expired.
|
||||
- Ensure temperature is at or above `MaxTemperatureGrowth`.
|
||||
- Ensure temperature is at or above `TemperatureOptimal`.
|
||||
- Expected: block info shows "Bees are preparing to swarm" (v1) or progress % (v2+).
|
||||
- Expected: progress increases from 0 to 100% over `PreSwarmDurationHours` hours.
|
||||
|
||||
## 2c) Pre-swarm progress decreases in cold
|
||||
- Start with some pre-swarm progress built up.
|
||||
- Drop temperature below `MaxTemperatureGrowth`.
|
||||
- Drop temperature below `TemperatureOptimal`.
|
||||
- Expected: pre-swarm progress decreases back toward 0.
|
||||
- Expected: swarm does not trigger until progress reaches 100% again.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user