public void InitializeArrays() { // If initialising on fresh creation, both arrays will be null (otherwise fruitPoints was already initialised in FromTreeAttributes) if (fruitPoints == null) { // This code path is called on block placement (i.e. when previous stage crop grows to final stage) // This initialises each fruit point with a different germination time // (if called after FromTreeAttributes, fruitPoints will already have been populated, and GetGerminationDate() will be called in the next CheckForGrowth() call instead) fruitPoints = new FruitData[positionsCount]; int randomSelector = Math.Abs(this.Blockentity.Pos.GetHashCode()) % fruitCodeBases.Length; for (int i = 0; i < positionsCount; i++) { int fruitVariant = i; if (i >= fruitCodeBases.Length) fruitVariant = randomSelector++ % fruitCodeBases.Length; fruitPoints[i] = new FruitData(fruitVariant, GetGerminationDate(), this, null); } } positions = new Vec3d[positionsCount]; Vec3f temp = new Vec3f(); float[] matrix = null; if (Blockentity.Block.RandomizeRotations) { // For performance, only call the hash function once per blockEntity loaded int randomSelector = GameMath.MurmurHash3(-Blockentity.Pos.X, Blockentity.Block.RandomizeAxes == EnumRandomizeAxes.XYZ ? Blockentity.Pos.Y : 0, Blockentity.Pos.Z); matrix = randomRotMatrices[GameMath.Mod(randomSelector, randomRotations.Length)]; } for (int i = 0; i < positionsCount; i++) { if (Api.Side == EnumAppSide.Client) { positions[i] = new Vec3d(points[i * 3], points[i * 3 + 1], points[i * 3 + 2]); if (matrix != null) { Mat4f.MulWithVec3_Position(matrix, (float)positions[i].X, (float)positions[i].Y, (float)positions[i].Z, temp); positions[i].X = temp.X; positions[i].Y = temp.Y; positions[i].Z = temp.Z; } } else { positions[i] = new Vec3d((i + 1) / positionsCount, (i + 1) / positionsCount, (i + 1) / positionsCount); //dummy vector for serverside - exact positions don't matter because they won't be rendered } positions[i].Add(Blockentity.Pos); } }