HyCodeYourTale

Blocks & Items

Blocks & Items

Dokumentace k práci s bloky a itemy v Hytale.

Obsah

| Soubor | Popis |
|--------|-------|
| BLOCK_TYPES.md | BlockType, BlockState, BlockModule, DrawType, BlockMaterial |
| ITEM_STACKS.md | ItemStack, Item assets, Durability, Metadata, Inventory events |

---

Přehled

Blocks & Items System

├── BlockType (Asset)
│ ├── DrawType, Material
│ └── BlockEntity, State

├── ItemStack (Runtime)
│ ├── Quantity, Durability
│ └── Metadata

└── Events
├── BreakBlockEvent
├── PlaceBlockEvent
└── Inventory events

---

Bloky

BlockType

// Získání typu bloku
BlockType blockType = event.getBlockType();

// ID bloku
String blockId = blockType.getId();

// Kontrola prázdného bloku (vzduch)
if (blockType == BlockType.EMPTY) {
return; // Přeskoč vzduch
}

BreakBlockEvent

public class BlockBreakSystem extends EntityEventSystem {

@Override
public void handle(int i, ArchetypeChunk chunk,
Store store, CommandBuffer buffer,
BreakBlockEvent event) {

// DŮLEŽITÉ: Vždy kontroluj EMPTY
if (event.getBlockType() == BlockType.EMPTY) return;

// Informace o bloku
BlockType blockType = event.getBlockType();
String blockId = blockType.getId();

// Pozice bloku
// BlockPos targetBlock = event.getTargetBlock();

// Nástroj v ruce
// ItemStack itemInHand = event.getItemInHand();

Ref ref = chunk.getReferenceTo(i);
Player player = store.getComponent(ref, Player.getComponentType());

if (player != null) {
player.sendMessage(Message.raw("Rozbit blok: " + blockId));
}
}

@Override
public Query getQuery() {
return PlayerRef.getComponentType();
}
}

PlaceBlockEvent

public class BlockPlaceSystem extends EntityEventSystem {

@Override
public void handle(int i, ArchetypeChunk chunk,
Store store, CommandBuffer buffer,
PlaceBlockEvent event) {

Ref ref = chunk.getReferenceTo(i);
Player player = store.getComponent(ref, Player.getComponentType());

if (player != null) {
player.sendMessage(Message.raw("Položen blok"));

// Zrušení položení
// event.cancel();
}
}

@Override
public Query getQuery() {
return PlayerRef.getComponentType();
}
}

UseBlockEvent

public class BlockUseSystem extends EntityEventSystem {

@Override
public void handle(int i, ArchetypeChunk chunk,
Store store, CommandBuffer buffer,
UseBlockEvent event) {

// Interakce s blokem (truhla, dveře, tlačítko...)
Ref ref = chunk.getReferenceTo(i);
Player player = store.getComponent(ref, Player.getComponentType());

if (player != null) {
// Zpracování interakce
}
}

@Override
public Query getQuery() {
return PlayerRef.getComponentType();
}
}

---

Block Definice (Assets)

Bloky jsou definovány v Assets/Common/Blocks/:

{
"Id": "stone",
"Name": "Stone",
"Hardness": 1.5,
"BlastResistance": 6.0,
"Drops": [
{
"Item": "cobblestone",
"Count": 1
}
],
"Properties": {
"Solid": true,
"Transparent": false
}
}

Dědičnost

{
"Parent": "base_stone",
"Override": {
"Name": "Granite",
"Texture": "granite.png"
}
}

---

Itemy

ItemStack

// Z eventu
ItemStack itemInHand = event.getItemInHand();

// Vlastnosti
String itemId = itemInHand.getItemId();
int count = itemInHand.getCount();

Inventory Eventy

// Změna inventáře
getEventRegistry().register(LivingEntityInventoryChangeEvent.class, event -> {
// Inventář se změnil
});

// Crafting
getEventRegistry().register(CraftRecipeEvent.class, event -> {
// Hráč craftí
// event.cancel(); // Zruší crafting
});

// Pickup
getEventRegistry().register(InteractivelyPickupItemEvent.class, event -> {
// Hráč sebral item
});

// Drop
getEventRegistry().register(DropItemEvent.class, event -> {
// Hráč zahodil item
});

---

Item Definice (Assets)

Itemy jsou definovány v Assets/Common/Items/ a Assets/Server/Item/:

{
"Id": "diamond_sword",
"Name": "Diamond Sword",
"Type": "Weapon",
"MaxStackSize": 1,
"Durability": 1561,
"Damage": 7,
"AttackSpeed": 1.6,
"Rarity": "Rare"
}

Typy Itemů

| Typ | Popis |
|-----|-------|
| Weapon | Zbraně |
| Tool | Nástroje |
| Armor | Brnění |
| Consumable | Spotřební (jídlo, lektvary) |
| Block | Položitelné bloky |
| Material | Materiály pro crafting |
| Misc | Ostatní |

---

Container (Inventáře)

Container Komponenta

Z dekompilovaného kódu - kontejnery jsou ECS entity:

// Kontejnery (truhly, inventáře) jsou entity s Container komponentou
Container container = store.getComponent(containerRef, Container.getComponentType());

> "Each item container is associated to an 'entity' in our ECS and they have entity ids... You can register a new component on those container entities" - Slikey

Přidání Vlastní Komponenty ke Kontejneru

// Koncept - přidání vlastní komponenty k truhle
public void onChestCreated(Ref chestRef, Store store) {
// Přidej vlastní data k truhle
store.addComponent(chestRef, MyChestData.getComponentType(), new MyChestData());
}

---

Drops (Loot)

Drop tabulky v Assets/Server/Drops/:

{
"Id": "zombie_drops",
"Entries": [
{
"Item": "rotten_flesh",
"Weight": 100,
"MinCount": 0,
"MaxCount": 2
},
{
"Item": "iron_ingot",
"Weight": 5,
"MinCount": 1,
"MaxCount": 1,
"Conditions": [
{ "Type": "KilledByPlayer" }
]
}
]
}

---

Příklady

Sledování Rozbitých Bloků

public class BlockStatsSystem extends EntityEventSystem {

private final Map> blockStats = new ConcurrentHashMap<>();

@Override
public void handle(int i, ArchetypeChunk chunk,
Store store, CommandBuffer buffer,
BreakBlockEvent event) {

if (event.getBlockType() == BlockType.EMPTY) return;

Ref ref = chunk.getReferenceTo(i);
PlayerRef playerRef = store.getComponent(ref, PlayerRef.getComponentType());

if (playerRef != null) {
UUID uuid = playerRef.getUuid();
String blockId = event.getBlockType().getId();

blockStats.computeIfAbsent(uuid, k -> new ConcurrentHashMap<>())
.merge(blockId, 1, Integer::sum);
}
}

public int getBlocksBroken(UUID uuid, String blockId) {
return blockStats.getOrDefault(uuid, Map.of())
.getOrDefault(blockId, 0);
}

@Override
public Query getQuery() {
return PlayerRef.getComponentType();
}
}

Ochrana Bloků

public class BlockProtectionSystem extends EntityEventSystem {

private final Set protectedBlocks = ConcurrentHashMap.newKeySet();

@Override
public void handle(int i, ArchetypeChunk chunk,
Store store, CommandBuffer buffer,
BreakBlockEvent event) {

if (event.getBlockType() == BlockType.EMPTY) return;

// Získej pozici bloku
// Vector3i blockPos = event.getTargetBlock().toVector3i();

// if (protectedBlocks.contains(blockPos)) {
// Ref ref = chunk.getReferenceTo(i);
// Player player = store.getComponent(ref, Player.getComponentType());
//
// if (player != null) {
// player.sendMessage(Message.raw("Tento blok je chráněný!"));
// }
//
// event.cancel();
// }
}

public void protectBlock(Vector3i position) {
protectedBlocks.add(position);
}

public void unprotectBlock(Vector3i position) {
protectedBlocks.remove(position);
}

@Override
public Query getQuery() {
return PlayerRef.getComponentType();
}
}

---

Shrnutí

| Event | Popis | Cancellable |
|-------|-------|-------------|
| BreakBlockEvent | Rozbití bloku | Ano |
| PlaceBlockEvent | Položení bloku | Ano |
| UseBlockEvent | Použití bloku | Ano |
| DamageBlockEvent | Poškození bloku | Ano |

| Inventory Event | Popis |
|-----------------|-------|
| LivingEntityInventoryChangeEvent | Změna inventáře |
| CraftRecipeEvent | Crafting |
| InteractivelyPickupItemEvent | Sebrání itemu |
| DropItemEvent | Zahození itemu |

| Kontrola | Kód |
|----------|-----|
| Prázdný blok | event.getBlockType() == BlockType.EMPTY |
| ID bloku | event.getBlockType().getId() |

Last updated: 20. ledna 2026