Diamond-Square Algorithm problems

Hello community,

I’ve try to generate a terrain with DS algorithm, but the resul is… is really bad, it work fine with small sizes, mx 20x20 points, any higher value brake it into square with cones.
Please help to solve I’ve already spen a full day for it with no result ( I finish it yesterday at 11 am and fixing this untill know ).

Here is the code which I use:

TerrainGen.h



// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/Actor.h"
#include "ProceduralMeshComponent.h"
#include "TerrainGen.generated.h"

UCLASS()
class HILL_LAND_GEN_V1_API ATerrainGen : public AActor
{
	GENERATED_BODY()

public:	
	// Sets default values for this actor's properties
	ATerrainGen();

	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
	// Called every frame
	virtual void Tick( float DeltaSeconds ) override;

	virtual void OnConstruction(const FTransform& Transform) override;

	UPROPERTY(EditAnywhere)
		uint16 Size = 2;

	UPROPERTY(EditAnywhere)
		float roughness = 0.0f;

	UPROPERTY(EditAnywhere)
		TArray<float> map;

	UPROPERTY(EditAnywhere)
		uint16 max_offset; // offset max

	UPROPERTY(EditAnywhere)
		UMaterialInterface* Material;

private:

	UProceduralMeshComponent* mesh;

	void divide(uint16 _size_);

	float get(uint16 x, uint16 y);

	void set(uint16 x, uint16 y, float val);

	float average( TArray<float> value );

	void square(uint16 x, uint16 y, uint16 half, float rand_offset);

	void diamond(uint16 x, uint16 y, uint16 half, float rand_offset);

};


TerrainGen.cpp



// Fill out your copyright notice in the Description page of Project Settings.

#include "hill_land_gen_v1.h"
#include "TerrainGen.h"


// Sets default values
ATerrainGen::ATerrainGen()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	USphereComponent* SphereComponent = CreateDefaultSubobject<USphereComponent>(TEXT("RootComponent"));
	RootComponent = SphereComponent;

	mesh = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("TerrainMesh"));
}

// Called when the game starts or when spawned
void ATerrainGen::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void ATerrainGen::Tick( float DeltaTime )
{
	Super::Tick( DeltaTime );

}

void ATerrainGen::OnConstruction(const FTransform& Transform)
{
	if (Size > 1) {
		max_offset = Size - 1;
		map.SetNumZeroed(Size*Size);

		set(0, 0, max_offset);
		set(max_offset, 0, max_offset / 2);
		set(max_offset, max_offset, max_offset / 2);
		set(0, max_offset, 0);

		divide(max_offset);

		TArray<FVector> vertices;

		uint16 offset = 50;
		for (uint16 x = 0; x < Size; x++) {
			for (uint16 y = 0; y < Size; y++) {
				vertices.Add(FVector(x, y, get(x, y)) * offset);
			}
		}

		TArray<int32> Triangles;
		uint16 step = 1;

		for (uint16 i = 0; i + Size * step < map.Num(); i += step) {

			if (i / Size == (i + step) / Size && (i / Size) % step == 0) {

				Triangles.Add(i);
				Triangles.Add(i + step);
				Triangles.Add(i + Size * step);

				Triangles.Add(i + step);
				Triangles.Add(i + Size * step + step);
				Triangles.Add(i + Size * step);
			}
		}

		//mesh->CreateMeshSection(1, vertices, Triangles, normals, UV0, vertexColors, tangents, false);

		// With default options
		mesh->CreateMeshSection(1, vertices, Triangles, TArray<FVector>(), TArray<FVector2D>(), TArray<FColor>(), TArray<FProcMeshTangent>(), true);

		mesh->SetMaterial(1, Material);

		mesh->AttachTo(RootComponent);
	}
}

void ATerrainGen::divide(uint16 _size_)
{
	uint16 x, y, half = _size_ / 2;
	float scale = roughness * _size_;

	if (half < 1.0f) return;

	for (y = half; y < max_offset; y += _size_) {
		for (x = half; x < max_offset; x += _size_) {
			square(y,x, half, FMath::RandRange(0.0f, 1.0f) * scale * 2 - scale);
		}
	}

	for (y = 0; y <= max_offset; y += half) {
		for (x = (y + half) % _size_; x <= max_offset; x += _size_) {
			diamond(x, y, half, FMath::RandRange(0.0f, 1.0f) * scale * 2 - scale);
		}
	}

	divide(half);
}

float ATerrainGen::get(uint16 x, uint16 y)
{
	if (x < 0 || x > max_offset || y < 0 || y > max_offset) return -1.0f;
	return map[x + Size * y];
}

void ATerrainGen::set(uint16 x, uint16 y, float val)
{
	checkf(x > -1 && x < Size && y > -1 && y < Size, TEXT("ATerrainGen::set(): x|y out of bounds."));
	map[x + Size * y] = val;
}

float ATerrainGen::average(TArray<float> value)
{
	float total = 0;

	//value = value.FilterByPredicate(](const float& val) {
	//	return val != -1.0f;
	//});

	TArray<float> valid;

	for (float& val : value) {
		if (val != -1.0f)
			valid.Add(val);
	}

	for (float& val : valid) {
		total += val;
	}

	return total / valid.Num();
}

void ATerrainGen::square(uint16 x, uint16 y, uint16 half, float rand_offset)
{
	float ave = average(TArray<float>({
		get(x - half, y - half),   // upper left
		get(x + half, y - half),   // upper right
		get(x + half, y + half),   // lower right
		get(x - half, y + half)    // lower left
	}));
	set(x, y, ave + rand_offset);
}

void ATerrainGen::diamond(uint16 x, uint16 y, uint16 half, float rand_offset)
{
	float ave = average(TArray<float>({
		get(x, y - half),      // top
		get(x + half, y),      // right
		get(x, y + half),      // bottom
		get(x - half, y)       // left
	}));
	set(x, y, ave + rand_offset);
}


Hope on your help. Thanks.

P.S. - I am not attaching the result because it really bad, so I am not see reason for it.