> For the complete documentation index, see [llms.txt](https://thisistails.gitbook.io/tailslib/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://thisistails.gitbook.io/tailslib/tailslib-rus/custom-blocks/block-methods.md).

# Block Methods

## Designations

* **`Object?`** - Object can be null.

## data() (required)

Main info about this block.

### CustomBlockData

* ID: ID of this block
* CustomItem: Item that represents this block. Item should be block to automaticly place this block without code.

### Example

{% hint style="warning" %}
Before binding custom item to your block make sure that custom item was registered before your block.
{% endhint %}

```java
@Override
public CustomBlockData data() {
    return new CustomBlockData(
        "test_block", 
        CustomItemManager.getManager().customItem("block_item").orElse(null)
    );
}
```

## validate(CustomBlockRuntime) (required)

Validation for your block. Called by `/cbmanager validate` command or by validating service.

### Example

In this example our test block is placing diamond block so when validation comes this block will check if block on position IS diamond block or else this block should be deleted.

{% hint style="danger" %}
Do not just blindly put `return true` to this method. This can cause bugs and dupes since your block will still be functional even if it will be replaced by something and still gonna recieve events.
{% endhint %}

```java
@Override
public boolean validate(CustomBlockRuntime blockRuntime) {
    return blockRuntime.block().getType() == Material.DIAMOND_BLOCK;
}
```

## createBlock(Location, CustomItemRuntime?) (required)

Method for creating your block.

### Nullable

CustomItemRuntime would not be null if:

* Block was placed because it was binded to this custom item. (See [#data](#data "mention"))
* `CustomItemRuntime` is specified in `PlaceBlockOptions`.

### Example

```java
@Override
public void createBlock(Location location, @Nullable CustomItemRuntime fromItem) {
    location.getBlock().setType(Material.DIAMOND_BLOCK);
    if (fromItem != null) {
        Bukkit.getLogger().info("TestBlock created at " + location + " from item " + fromItem.itemInstance().id());
    } else {
        Bukkit.getLogger().info("TestBlock created at " + location + " without item");
    }
}
```

## beforePlace(CustomItemRuntime?, Player?, Location)

Called before calling [#createblock-location-nullable-customitemruntime](#createblock-location-nullable-customitemruntime "mention") event. Used to determine if this block can be placed at this place.

### Nullable

CustomItemRuntime would not be null if:

* Block was placed because it was binded to this custom item. (See [#data](#data "mention"))
* `CustomItemRuntime` is specified in `PlaceBlockOptions`.

Player would not be null if:

* Player placed this block
* Player was specified in `PlaceBlockOptions`.

### Example

```java
// List of everyone who placed this block
public static List<UUID> alreadyPlacedBy = new ArrayList<>();

@Override
public boolean beforePlace(CustomItemRuntime item, Player player, Location loc) {
    // Checking if block was already placed by this player
    if (alreadyPlacedBy.contains(player.getUniqueId()))
        // If yes then abort placing this block. 
        return false;
    
    // Checking if this block is placing above grass block
    Location under = loc.clone().add(0, -1, 0);
    if (under.getBlock().getType() != Material.GRASS_BLOCK)
        // If not then abort
        return false;
    
    // If all okay then continue
    return true;
}
```

## placed(CustomItemRuntime?, OfflinePlayer?, CustomBlockRuntime)

Called after block was placed.

### Nullable

CustomItemRuntime would not be null if:

* Block was placed because it was binded to this custom item. (See [#data](#data "mention"))
* `CustomItemRuntime` is specified in `PlaceBlockOptions`.

OfflinePlayer would not be null if:

* Player placed this block
* Player was specified in `PlaceBlockOptions`.

## Destroy and destroyRequest

Both event needed to say to block that this instance of block was destroyed.

Destroy event called when natural reasons destroyed block instance like commands, player, explosion and etc.

Destroy request on the other hand called only when block was removed by manager. This means event would be called when command `/cblock` placing block with replacing or manager called to delete or replace a block at some position.

### destroyRequest(CustomBlockRuntime)

Called by manager

### destroy(CustomBlockBreakContext)

Called by explosion, players and etc.

### CustomBlockBreakContext

* `BreakReason` **breakReason** - Reason why this block was destroyed
* `Block` **block** - New block at this position (Most likely a AIR)
* `Location` **location** - Location of this block (Basicly a shortcut)
* `Event` **event** - event that called this event
* `CustomBlock` **customBlock** - this block

**Methods**

* eventAs(Class) - Try to cast event to specific class.

Example

```java
@Override
public void destroy(CustomBlockBreakContext context) {
    // Will fire if event is BlockBreakEvent
    context.eventAs(BlockBreakEvent.class).ifPresent((event) -> {
        Bukkit.getLogger().info("TestBlock destroyed at " 
        + context.location() + 
        " by " + (event.getPlayer() != null ? event.getPlayer().getName() : "unknown"));
        context.location().createExplosion(10f);
    });

    // Will fire if event is BlockDestroyEvent
    context.eventAs(BlockDestroyEvent.class).ifPresent((event) -> {
        Bukkit.getLogger().info("TestBlock destroyed at " + context.location());
    });
}
```

* isCancellable() - Check if this event can be cancelled.
* isCancelled() - Check if this event is cancelled.
* setCancelled(Boolean) - Set the cancelled state of the event if it is cancellable.

## Left and right click

I don't think it's necessary to explain how it works.

### rightClicked(CustomBlockRuntime, PlayerInteractEvent)

Right click

### leftClicked(CustomBlockRuntime, PlayerInteractEvent)

Left click

## blockDestroyProgress(CustomBlockRuntime, BlockBreakProgressUpdateEvent)

Called when player is mining this block.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://thisistails.gitbook.io/tailslib/tailslib-rus/custom-blocks/block-methods.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
