Skip to content
2 changes: 2 additions & 0 deletions simulation_parameters/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,8 @@ public static class Constants

public const float DEFAULT_MICROBE_VENT_THRESHOLD = 2.0f;

public const float CELL_ADJACENCY_SPECIALIZATION_BONUS = 0.04f;

/// <summary>
/// A cell needs to have this many organelles for specialization to apply to it
/// </summary>
Expand Down
55 changes: 55 additions & 0 deletions src/multicellular_stage/CellBodyPlanInternalCalculations.cs
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall I think this is pretty good for the backend part of this feature, though the changes in this file are kind of looking very similar, so I think some of the methods here could be simplified so that they just look up some data and then call an overload. Would that be possible?

Also one slight naming thing is that you should clarify if the body plan is the gameplay or editor body plan (as your code only works for the editor body plan variant and will fail for the gameplay body plan).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so I think some of the methods here could be simplified so that they just look up some data and then call an overload. Would that be possible?

I'm not exactly sure what you mean by this, and I don't really see any way to simply these methods. CMIIW though, of course.

(as your code only works for the editor body plan variant and will fail for the gameplay body plan)

This seems a bit too important to just hide in parentheses.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean it looks like the index method could just get the cell type from the index and then call the variant that takes in a cell template directly? I did not try to do that rewrite so I might be missing some small detail but to me that seems like a plausible code refactor.

This seems a bit too important to just hide in parentheses.

I assumed you were aware of that... You'll want to check the differences between ModifiableGameplayCells and ModifiableEditorCells as I think that yeah your algorithm works for one but does not work for the other, so it should be clarified with variable naming and maybe even putting an XML comment with a warning about that that the algorithm only works for one cell layout variant.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Components;
using Godot;

Expand Down Expand Up @@ -141,4 +142,58 @@ public static float CalculateRotationSpeed(IReadOnlyList<HexWithData<CellTemplat

return colonyRotation / cells.Count;
}

public static float GetAdjacencySpecializationBonusFromIndexAndPlan(CellTemplate? cellInBodyPlan,
IReadOnlyList<HexWithData<CellTemplate>> bodyPlan)
{
var bonus = 0.0f;

foreach (var cell in bodyPlan)
{
if (cellInBodyPlan!.CellType == cell.Data!.CellType
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you make the parameter nullable if you just use null suppression on it? This is the incorrect way to use null suppression; it should only be overridden when you are sure it is safe to do. We have null suppression enabled so that the compiler can help us notice potential bugs in code and need to write the proper handling code (or modify the parameter definitions so that our caller has to get valid data for us).

&& cell.Position.DistanceTo(cellInBodyPlan.Position) == 1)
{
bonus += Constants.CELL_ADJACENCY_SPECIALIZATION_BONUS;
}
}

return 1 + bonus;
}

public static float GetAdjacencySpecializationBonusFromIndexAndPlan(int cellIndexInBodyPlan,
IReadOnlyIndividualLayout<IReadOnlyCellTemplate> bodyPlan)
{
var bonus = 0.0f;
var plan = bodyPlan.ToList();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Temporary memory should be avoided. So the looping needs to be done in a different way here.

var cellInBodyPlan = plan[cellIndexInBodyPlan];

foreach (var cell in bodyPlan)
{
if (cellInBodyPlan.Data!.CellType == cell.Data!.CellType
&& cell.Position.DistanceTo(cellInBodyPlan.Position) == 1)
{
bonus += Constants.CELL_ADJACENCY_SPECIALIZATION_BONUS;
}
}

return 1 + bonus;
}

public static float GetAdjacencySpecializationBonusFromIndexAndPlan(int cellIndexInBodyPlan,
IndividualHexLayout<CellTemplate> bodyPlan)
{
var bonus = 0.0f;
var cellInBodyPlan = bodyPlan[cellIndexInBodyPlan];

foreach (var cell in bodyPlan)
{
if (cellInBodyPlan.Data!.CellType == cell.Data!.CellType
&& cell.Position.DistanceTo(cellInBodyPlan.Position) == 1)
{
bonus += Constants.CELL_ADJACENCY_SPECIALIZATION_BONUS;
}
}
Comment on lines +186 to +195
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still looks very similar to me...

Like I think the code could be like:

float GetAdjacencyWithAFancyName(CellTemplate thing, others...){
  loop logic here
}

float GetAdjacencyWithAFancyName(int index, others...){
  var resolved = others[index];
  return GetAdjacencyWithAFancyName(resolved, others...);
}

So that way there's less code repetition.


return 1 + bonus;
}
}
5 changes: 2 additions & 3 deletions src/multicellular_stage/MulticellularSpecies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -347,9 +347,8 @@ public float CalculateAverageSpecialization()
/// <returns>The calculated bonus (or 1, if it can't be calculated)</returns>
public float GetAdjacencySpecializationBonus(int cellIndexInBodyPlan)
{
// TODO: implement this https://github.com/Revolutionary-Games/Thrive/issues/6764
_ = cellIndexInBodyPlan;
return 1;
return CellBodyPlanInternalCalculations
.GetAdjacencySpecializationBonusFromIndexAndPlan(cellIndexInBodyPlan, EditorCells);
}

public void SetupWorldEntities(IWorldSimulation worldSimulation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,12 +250,10 @@ private void UpdateSpecializationDisplay()

var specialization =
MicrobeInternalCalculations.CalculateSpecializationBonus(type.ModifiableOrganelles, tempMemory3);
var adjacencySpecialization =
CellBodyPlanInternalCalculations.GetAdjacencySpecializationBonusFromIndexAndPlan(i, cells);

// TODO: calculate adjacency specialization values
// https://github.com/Revolutionary-Games/Thrive/issues/6764
// totalSpecialization += specialization * adjacencySpecialization;

totalSpecialization += specialization;
totalSpecialization += specialization * adjacencySpecialization;

if (specialization > maxSpecialization)
{
Expand Down
12 changes: 8 additions & 4 deletions src/multicellular_stage/editor/CellBodyPlanEditorComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1438,11 +1438,13 @@ private void CalculateEnergyAndCompoundBalance(IReadOnlyList<HexWithData<CellTem
{
var specialization =
MicrobeInternalCalculations.CalculateSpecializationBonus(hex.Data!.ModifiableOrganelles, tempMemory3);
var adjacencySpecialization =
CellBodyPlanInternalCalculations.GetAdjacencySpecializationBonusFromIndexAndPlan(hex.Data, cells);

// TODO: adjacency bonuses from body plan (GetAdjacencySpecializationBonus)
var totalSpecialization = specialization * adjacencySpecialization;

ProcessSystem.ComputeEnergyBalanceFull(hex.Data.ModifiableOrganelles, conditionsData,
environmentalTolerances, specialization, hex.Data.MembraneType,
environmentalTolerances, totalSpecialization, hex.Data.MembraneType,
maximumMovementDirection, moving, true, Editor.CurrentGame.GameWorld.WorldSettings,
organismStatisticsPanel.CompoundAmountType, null, energyBalanceInfo);
}
Expand Down Expand Up @@ -1485,11 +1487,13 @@ private Dictionary<Compound, CompoundBalance> CalculateCompoundBalanceWithMethod
var organelles = GetEditedCellDataIfEdited(cell.Data!.ModifiableCellType).ModifiableOrganelles;
var specialization =
MicrobeInternalCalculations.CalculateSpecializationBonus(organelles, tempMemory3);
var adjacencySpecialization =
CellBodyPlanInternalCalculations.GetAdjacencySpecializationBonusFromIndexAndPlan(cell.Data, cells);

// TODO: efficiency from cell layout positions (GetAdjacencySpecializationBonus)
var totalSpecialization = specialization * adjacencySpecialization;

AddCellTypeCompoundBalance(compoundBalanceData, organelles, calculationType,
amountType, biome, energyBalance, tolerances, specialization);
amountType, biome, energyBalance, tolerances, totalSpecialization);
}

specificStorages ??= CellBodyPlanInternalCalculations.GetTotalSpecificCapacity(cells.Select(o => o.Data!),
Expand Down