> For the complete documentation index, see [llms.txt](https://docs.allout.game/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.allout.game/all-out-docs/ru/skripting/types-and-structures.md).

# Основы языка

Эта страница посвящена стороне CSL, связанной с «моделированием данных»: примитивам, структурам/классам и шаблонам, которые вы будете использовать, чтобы аккуратно представлять состояние игры.

{% hint style="info" %}
Если вы совсем новичок, начните с [Начало работы с CSL](/all-out-docs/ru/skripting/syntax.md). Эта страница предполагает, что вы уже умеете объявлять переменные и писать `proc`/`method`.
{% endhint %}

## Примитивные типы

### Числа и булевы значения

* Знаковые целые числа: `s8`, `s16`, `s32`, `s64` (псевдоним: `int` == `s64`)
* Беззнаковые целые числа: `u8`, `u16`, `u32`, `u64` (псевдоним: `uint` == `u64`)
* Числа с плавающей точкой: `f32` (псевдоним: `float`), `f64`
* Булевы значения: `bool`

```go
health: int = 100;
speed: float = 6.5;
is_dead: bool = false;
```

CSL расширяет числовые типы, когда это безопасно: меньшие знаковые целые могут становиться более широкими знаковыми целыми, меньшие беззнаковые целые могут становиться более широкими беззнаковыми целыми, беззнаковые целые могут становиться более широкими знаковыми целыми, если целевой тип может вместить весь диапазон, и `f32` может стать `f64`.

### Строки

`string` используется постоянно для идентификаторов, имён и форматирования.

```go
item_id := "sword";
log_info("picked up %", {item_id});
```

### Векторы

`v2`, `v3`, `v4` — это встроенные математические типы/типы данных:

```go
pos: v2 = {10, 20};
color: v4 = {1, 0, 0, 1};
```

## Перечисления

Перечисления отлично подходят для читаемых полей «режим/состояние»:

```go
Game_Phase :: enum {
    LOBBY;
    RUNNING;
    POST_GAME;
}

phase := Game_Phase.LOBBY;

if phase == .RUNNING {
    // ...
}
```

{% hint style="info" %}
К значениям перечислений обычно обращаются с сокращённой записью `.VALUE` когда компилятор может вывести тип перечисления.
{% endhint %}

## Структуры (типы-значения)

Используйте структуры для «простых данных», которые вы хотите дешево копировать (конфиги, небольшие блоки состояния, дескрипторы).

```go
Damage_Desc :: struct {
    amount: int;
    knockback: v2;
}

hit := Damage_Desc{amount=10, knockback={2, 1}};
```

Структуры могут наследоваться от других структур. Составные литералы включают унаследованные поля первыми:

```go
Base_Stats :: struct {
    health: int;
}

Enemy_Stats :: struct : Base_Stats {
    speed: float;
}

stats: Enemy_Stats = {100, 4.5};
```

### Когда использовать структуру

* Объект-дескриптор/конфиг (`*_Desc`)
* Небольшое, самодостаточное состояние, которое вы хотите копировать по значению
* Данные, которые вы хотите встроить внутрь другого типа

### Когда не стоит использовать структуру

* Большое изменяемое состояние, общее для нескольких систем (используйте класс)
* Объекты «с идентичностью» (игроки, предметы, долго живущие объекты) (используйте класс)

## Классы (ссылочные типы)

Классы — это ссылочные типы. Создавайте экземпляры с помощью `new(...)`.

```go
Enemy :: class {
    health: int = 50;
    target: v2 = {0, 0};
}

e := new(Enemy);
```

### Наследование

Вы можете наследовать от других структур/классов:

```go
Weapon_Definition :: class {
    id: string;
    name: string;
}

Gun_Definition :: class : Weapon_Definition {
    fire_rate: float;
}
```

Производные классы наследуют значения полей по умолчанию. Они могут переопределять унаследованные значения по умолчанию с помощью `field = value` в теле класса:

```go
Weapon_Definition :: class {
    damage: int = 10;
}

Rocket_Definition :: class : Weapon_Definition {
    damage = 100;
    splash_radius: float = 3.0;
}
```

{% hint style="warning" %}
Используйте наследование, когда есть реальная связь «является». Для большинства игровых данных композиция (поля) проще и легче в поддержке.
{% endhint %}

## Массивы, срезы и динамические массивы

Вы встретите три распространённые формы:

* **Фиксированные массивы**: `[N]T` (размер на этапе компиляции)
* **Срезы / управляемые массивы**: `[]T` (представление массива)
* **Динамические массивы**: `[..]T` (изменяемый по размеру список)

Пример:

```go
spawn_points: [4]v2 = {{0,0}, {5,0}, {0,5}, {5,5}};

alive_enemy_ids: [..]int;
alive_enemy_ids.append(123);
alive_enemy_ids.append(456);
```

Полное руководство см. [Массивы и коллекции](/all-out-docs/ru/skripting/arrays-and-collections.md).

## Передача по ссылке (`ref`)

Если процедуре нужно изменить значение, используйте `ref`:

```go
apply_damage :: proc(health: ref int, amount: int) {
    health -= amount;
}

hp := 100;
apply_damage(ref hp, 10);
```

Это особенно полезно для API в стиле «layout», которые постепенно обрезают/уменьшают прямоугольник:

```go
draw_panel :: proc(rect: ref Rect) {
    header := rect.cut_top(50);
    draw_header(header);
    // теперь rect — это оставшаяся область для содержимого
}
```

## Приведение типов

Используйте `expr.(T)` или `cast(T)expr`:

```go
f := 12.7;
i := f.(int);       // 12
f2 := cast(float)i; // 12.0
```

Когда целевой тип уже известен, `expr.()` и `cast expr` выводят целевой тип.

## Полиморфизм типов (процедуры в стиле generics)

CSL поддерживает полиморфные процедуры, используя `$` для вывода типов в месте вызова:

```go
min :: proc(a: $T, b: T) -> T {
    if a < b return a;
    return b;
}

a := min(10, 20);       // T == int
b := min(1.25, 3.5);    // T == float
```

## Типы как значения (`typeid`)

`typeid` — это значение, представляющее тип во время выполнения и/или для полиморфных вызовов:

```go
default_of :: proc($T: typeid) -> T {
    t: T;
    return t;
}

zero := default_of(int);
empty := default_of(string);
```

`value.#type` возвращает тип значения класса во время выполнения. Используйте его перед приведением вниз из базового класса, когда важен точный производный тип.

## Практические рекомендации по моделированию

* **Состояние, привязанное к каждому игроку, хранится в `Player`.** Если это должно отличаться у разных игроков, это не должно быть глобальным.
* **Для дескрипторов предпочитайте небольшие структуры** а состояние во время выполнения храните в классах/компонентах.
* **Запускайте геймплей в общем предсказанном пути.** Не вычисляйте состояние геймплея только при `is_local()` или не ограничивайте его `Game.is_server()`.

Для шаблонов, специфичных для игрока, см. [Добавление логики игрока](/all-out-docs/ru/skripting/player-model.md). А для ECS-стороны мира см. [Сущности и компоненты](/all-out-docs/ru/skripting/entities-and-components.md).
