text: // Copyright (c) Improbable Worlds Ltd, All Rights Reserved
  
  #pragma once
  
  #include "CoreMinimal.h"
  #include "Components/ActorComponent.h"
  #include "Templates/SubclassOf.h"
  
  #include "SpatialInterestConstraints.generated.h"
  
  namespace SpatialGDK
  {
  struct QueryConstraint;
  }
  class USpatialClassInfoManager;
  
  /**
   * Query data used to configure Query-based Interest.
   */
  USTRUCT(BlueprintType)
  struct SPATIALGDK_API FQueryData
  {
  	GENERATED_BODY()
  public:
  	FQueryData() = default;
  	~FQueryData() = default;
  
  	/**
  	 * The root constraint associated with the query generated by this component.
  	 */
  	UPROPERTY(BlueprintReadonly, EditDefaultsOnly, Instanced, Category = "Query Data")
  	class UAbstractQueryConstraint* Constraint;
  
  	/**
  	 * Used for frequency-based rate limiting. Represents the maximum frequency
  	 * of updates for this particular query. An empty option represents no
  	 * rate-limiting (ie. updates are received as soon as possible). Frequency
  	 * is measured in Hz.
  	 *
  	 * If set, the time between consecutive updates will be at least
  	 * 1/frequency. This is determined at the time that updates are sent from
  	 * the Runtime and may not necessarily correspond to the time updates are
  	 * received by the worker.
  	 *
  	 * If after an update has been sent, multiple updates are applied to a
  	 * component, they will be merged and sent as a single update after
  	 * 1/frequency of the last sent update. When components with events are
  	 * merged, the resultant component will contain a concatenation of all the
  	 * events.
  	 *
  	 * If multiple queries match the same Entity-Component then the highest of
  	 * all frequencies is used.
  	 */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Meta = (ClampMin = 0.0), Category = "SpatialGDK")
  	float Frequency;
  };
  
  UCLASS(Abstract, BlueprintInternalUseOnly)
  class SPATIALGDK_API UAbstractQueryConstraint : public UObject
  {
  	GENERATED_BODY()
  public:
  	UAbstractQueryConstraint() = default;
  	virtual ~UAbstractQueryConstraint() = default;
  
  	virtual void CreateConstraint(const USpatialClassInfoManager& ClassInfoManager, SpatialGDK::QueryConstraint& OutConstraint) const PURE_VIRTUAL(UAbstractQueryConstraint::CreateConstraint, );
  };
  
  /**
   * Creates a constraint that is satisfied if any of its inner constraints are satisfied.
   */
  UCLASS(BlueprintType, EditInlineNew, DefaultToInstanced)
  class SPATIALGDK_API UOrConstraint final : public UAbstractQueryConstraint
  {
  	GENERATED_BODY()
  public:
  	UOrConstraint() = default;
  	~UOrConstraint() = default;
  
  	virtual void CreateConstraint(const USpatialClassInfoManager& ClassInfoManager, SpatialGDK::QueryConstraint& OutConstraint) const override;
  
  	/** Entities captured by any subconstraints will be included in interest results. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Instanced, Category = "Or Constraint")
  	TArray<UAbstractQueryConstraint *> Constraints;
  };
  
  /**
   * Creates a constraint that is satisfied if all of its inner constraints are satisfied.
   */
  UCLASS(BlueprintType, EditInlineNew, DefaultToInstanced)
  class SPATIALGDK_API UAndConstraint final : public UAbstractQueryConstraint
  {
  	GENERATED_BODY()
  public:
  	UAndConstraint() = default;
  	~UAndConstraint() = default;
  
  	virtual void CreateConstraint(const USpatialClassInfoManager& ClassInfoManager, SpatialGDK::QueryConstraint& OutConstraint) const override;
  
  	/** Entities captured by all subconstraints will be included in interest results. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Instanced, Category = "And Constraint")
  	TArray<UAbstractQueryConstraint *> Constraints;
  };
  
  /**
   * Creates a constraint that includes all entities within a sphere centered on the specified point.
   */
  UCLASS(BlueprintType, EditInlineNew, DefaultToInstanced)
  class SPATIALGDK_API USphereConstraint final : public UAbstractQueryConstraint
  {
  	GENERATED_BODY()
  public:
  	USphereConstraint() = default;
  	~USphereConstraint() = default;
  
  	virtual void CreateConstraint(const USpatialClassInfoManager& ClassInfoManager, SpatialGDK::QueryConstraint& OutConstraint) const override;
  
  	/** The location in the world that this constraint is relative to. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "Sphere Constraint")
  	FVector Center = FVector::ZeroVector;
  
  	/** The size of the sphere represented by this constraint in centimeters. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Meta = (ClampMin = 0.0), Category = "Sphere Constraint")
  	float Radius = 0.0f;
  };
  
  /**
   * Creates a constraint that includes all entities within a cylinder centered on the specified point.
   */
  UCLASS(BlueprintType, EditInlineNew, DefaultToInstanced)
  class SPATIALGDK_API UCylinderConstraint final : public UAbstractQueryConstraint
  {
  	GENERATED_BODY()
  public:
  	UCylinderConstraint() = default;
  	~UCylinderConstraint() = default;
  
  	virtual void CreateConstraint(const USpatialClassInfoManager& ClassInfoManager, SpatialGDK::QueryConstraint& OutConstraint) const override;
  
  	/** The location in the world that this constraint is relative to. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "Cylinder Constraint")
  	FVector Center = FVector::ZeroVector;
  
  	/** The size of the cylinder represented by this constraint in centimeters. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Meta = (ClampMin = 0.0), Category = "Cylinder Constraint")
  	float Radius = 0.0f;
  };
  
  /**
   * Creates a constraint that includes all entities within a bounding box centered on the specified point.
   */
  UCLASS(BlueprintType, EditInlineNew, DefaultToInstanced)
  class SPATIALGDK_API UBoxConstraint final : public UAbstractQueryConstraint
  {
  	GENERATED_BODY()
  public:
  	UBoxConstraint() = default;
  	~UBoxConstraint() = default;
  
  	virtual void CreateConstraint(const USpatialClassInfoManager& ClassInfoManager, SpatialGDK::QueryConstraint& OutConstraint) const override;
  
  	/** The location in the world that this constraint is relative to. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "Box Constraint")
  	FVector Center = FVector::ZeroVector;
  
  	/** The size of the box represented by this constraint. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Meta = (ClampMin = 0.0), Category = "Box Constraint")
  	FVector EdgeLengths = FVector::ZeroVector;
  };
  
  /**
   * Creates a constraint that includes all entities within a sphere centered on the actor.
   */
  UCLASS(BlueprintType, EditInlineNew, DefaultToInstanced)
  class SPATIALGDK_API URelativeSphereConstraint final : public UAbstractQueryConstraint
  {
  	GENERATED_BODY()
  public:
  	URelativeSphereConstraint() = default;
  	~URelativeSphereConstraint() = default;
  
  	virtual void CreateConstraint(const USpatialClassInfoManager& ClassInfoManager, SpatialGDK::QueryConstraint& OutConstraint) const override;
  
  	/** The size of the sphere represented by this constraint in centimeters. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Meta = (ClampMin = 0.0), Category = "Relative Sphere Constraint")
  	float Radius = 0.0f;
  };
  
  /**
   * Creates a constraint that includes all entities within a cylinder centered on the actor.
   */
  UCLASS(BlueprintType, EditInlineNew, DefaultToInstanced)
  class SPATIALGDK_API URelativeCylinderConstraint final : public UAbstractQueryConstraint
  {
  	GENERATED_BODY()
  public:
  	URelativeCylinderConstraint() = default;
  	~URelativeCylinderConstraint() = default;
  
  	virtual void CreateConstraint(const USpatialClassInfoManager& ClassInfoManager, SpatialGDK::QueryConstraint& OutConstraint) const override;
  
  	/** The size of the cylinder represented by this constraint in centimeters. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Meta = (ClampMin = 0.0), Category = "Relative Cylinder Constraint")
  	float Radius = 0.0f;
  };
  
  /**
   * Creates a constraint that includes all entities within a bounding box centered on the actor.
   */
  UCLASS(BlueprintType, EditInlineNew, DefaultToInstanced)
  class SPATIALGDK_API URelativeBoxConstraint final : public UAbstractQueryConstraint
  {
  	GENERATED_BODY()
  public:
  	URelativeBoxConstraint() = default;
  	~URelativeBoxConstraint() = default;
  
  	virtual void CreateConstraint(const USpatialClassInfoManager& ClassInfoManager, SpatialGDK::QueryConstraint& OutConstraint) const override;
  
  	/** The size of the box represented by this constraint. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Meta = (ClampMin = 0.0), Category = "Relative Box Constraint")
  	FVector EdgeLengths = FVector::ZeroVector;
  };
  
  /**
   * Creates a constraint that includes an actor type (including subtypes) and a cylindrical range around the actor with the interest.
   */
  UCLASS(BlueprintType, EditInlineNew, DefaultToInstanced)
  class SPATIALGDK_API UCheckoutRadiusConstraint final : public UAbstractQueryConstraint
  {
  	GENERATED_BODY()
  public:
  	UCheckoutRadiusConstraint() = default;
  	~UCheckoutRadiusConstraint() = default;
  
  	virtual void CreateConstraint(const USpatialClassInfoManager& ClassInfoManager, SpatialGDK::QueryConstraint& OutConstraint) const override;
  
  	/** The base type of actor that this constraint will capture. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "Checkout Radius Constraint")
  	TSubclassOf<AActor> ActorClass;
  
  	/** The size of the cylinder represented by this constraint in centimeters. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Meta = (ClampMin = 0.0), Category = "Checkout Radius Constraint")
  	float Radius = 0.0f;
  };
  
  /**
   * Creates a constraint that includes all actors of a type (optionally including subtypes).
   */
  UCLASS(BlueprintType, EditInlineNew, DefaultToInstanced)
  class SPATIALGDK_API UActorClassConstraint final : public UAbstractQueryConstraint
  {
  	GENERATED_BODY()
  public:
  	UActorClassConstraint() = default;
  	~UActorClassConstraint() = default;
  
  	virtual void CreateConstraint(const USpatialClassInfoManager& ClassInfoManager, SpatialGDK::QueryConstraint& OutConstraint) const override;
  
  	/** The base type of actor that this constraint will capture. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "Actor Class Constraint")
  	TSubclassOf<AActor> ActorClass;
  
  	/** Whether this constraint should capture derived types. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "Actor Class Constraint")
  	bool bIncludeDerivedClasses = true;
  };
  
  /**
   * Creates a constraint that includes all components of a type (optionally including subtypes).
   */
  UCLASS(BlueprintType, EditInlineNew, DefaultToInstanced)
  class SPATIALGDK_API UComponentClassConstraint final : public UAbstractQueryConstraint
  {
  	GENERATED_BODY()
  public:
  	UComponentClassConstraint() = default;
  	~UComponentClassConstraint() = default;
  
  	virtual void CreateConstraint(const USpatialClassInfoManager& ClassInfoManager, SpatialGDK::QueryConstraint& OutConstraint) const override;
  
  	/** The base type of component that this constraint will capture. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "Component Class Constraint")
  	TSubclassOf<UActorComponent> ComponentClass;
  
  	/** Whether this constraint should capture derived types. */
  	UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "Component Class Constraint")
  	bool bIncludeDerivedClasses = true;
  };
  