# Custom DataStream

ObjectNet provides the facility to send and receive simple and complex structured over-network ( see [datastream](https://onlineobject.gitbook.io/objectnet/general/fundamentals/datastream "mention")).

In multiplayer games, you often need to send custom data over the network—like a player’s stats, a damage hit, or a full status effect. Instead of sending each field manually every time, Custom DataStream (**serialization)** lets you group that data into a class and send it with a single line.

ObjectNet makes this easy with **custom DataStreams**.

***

## <mark style="color:blue;">Why Use Custom DataStream?</mark>

Let’s say you have a `Damage` class with two values:

```csharp
public class Damage {
    public int amount;
    public Vector3 direction;
    
    //constroctor
    public Damage(int amount, Vector3 direction) {
        this.amount = amount;
        this.direction = direction;
    }
}
```

Without serialization, you’d need to write each value manually every time:

```csharp
writer.Write<int>(damage.amount);
writer.Write<Vector3>(damage.direction);
```

That’s repetitive and error-prone. Instead: Serialize Once, Reuse Everywhere

With a custom DataStream, you can send the full object like this:

```csharp
writer.Write<Damage>(damage);
```

And read it just as easily:

```csharp
Damage damage = reader.Read<Damage>();
```

***

## <mark style="color:blue;">How to Create a Custom DataStream</mark>

### 1. Create the Data Handler

To teach ObjectNet how to read/write your class, create a new class that inherits from `DataHandler<T>`:

```csharp
public class DamageStream : DataHandler<Damage> {
    
    public override int Write(Damage data, ref byte[] buffer, ref int offset) {        
        int result  = base.Write(data.amount, ref buffer, ref offset, typeof(int));
            result += base.Write(data.direction, ref buffer, ref offset, typeof(Vector3));
        return result;
    }

    public override Damage Read(byte[] buffer, ref int offset) {
        int  amount = Read<int>(buffer, ref offset);
        Vector3 dir = Read<Vector3>(buffer, ref offset);
        return new Damage(amount, dir);
    }
}
```

{% hint style="info" %}
The order of reading must exactly match the order of writing.
{% endhint %}

***

### 2. Register Your Stream

Register your handler once (e.g. at startup):

```csharp
DataStream.RegisterGlobalStream<Damage, DamageStream>();
```

This tells ObjectNet:

> “Whenever I send or receive a `Damage` object, use the `DamageStream` class to handle it.”
