> 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/syntax.md).

# Начало работы с CSL

CSL — это собственный язык сценариев All Out. Он статически типизирован и больше всего похож на Go/Odin — за исключением **состояние игрового процесса автоматически синхронизируется с сервера на клиенты**.

{% hint style="info" %}
Вам не нужно писать RPC, SyncVars или собственную репликацию. Мы сделаем это за вас!
{% endhint %}

## Ваш первый скрипт (`main.csl`)

Когда вы создаёте новый проект, All Out генерирует `main.csl` в папке `scripts/` папку вашего проекта.

```go
import "core:ao"

// ============================================================================
// Глобальный жизненный цикл
// ============================================================================

ao_before_scene_load :: proc() {
    // Зарегистрировать определения предметов, валют и т. д.
    // Выполняется до создания сцены.
}

ao_start :: proc() {
    // Вызывается один раз при запуске сцены.
}

ao_update :: proc(dt: float) {
    // Вызывается каждый кадр.
}

ao_late_update :: proc(dt: float) {
    // Вызывается каждый кадр после ao_update.
}

// ============================================================================
// Жизненный цикл игрока
// ============================================================================

Player :: class : Player_Base {
    ao_start :: method() {
    }

    ao_update :: method(dt: float) {
    }

    ao_late_update :: method(dt: float) {
    }

    ao_end :: method() {
    }
}
```

Например, выводите сообщение в лог, когда подключается каждый игрок:

```go
Player :: class : Player_Base {
    ao_start :: method() {
        log_info("hello %", {this.get_username()});
    }
}
```

Если вы хотите подробнее понять, когда выполняются эти функции, см. [Жизненный цикл игры/кадра](/all-out-docs/ru/skripting/game-frame-lifecycle.md).

## Импорты

Ваш `main.csl` должен импортировать `core:ao` и любые созданные вами папки (например, `ui/`, `abilities/`, и т. д.).

```go
import "core:ao"
import "ui"
```

Импорты указывают на папки, а не на отдельные файлы. Импорт папки включает `.csl` файлы в этой папке. Импорты внутри этой папки разрешаются относительно неё:

```go
// main.csl
import "core:ao"
import "abilities"

// abilities/projectiles.csl
import "helpers"
```

{% hint style="warning" %}
В большинстве проектов **импортируйте в `main.csl` только**. Не раскидывайте импорты по множеству файлов — в итоге вы столкнётесь с запутанными проблемами порядка/видимости.
{% endhint %}

## Объявления (переменные и константы)

Объявления связывают имя со значением.

### Переменные

```go
// Общая форма
<name>: <type> = <expression>;
```

Можно опустить либо `<type>` или `<expression>` :

```go
// Явный тип
my_value: int = 42;

// Выведение типа
my_value := 42; // выведено как int

// Инициализация нулём (то же самое, что my_value := 0;)
my_value: int;
```

### Константы

Константы используют `::` и должны быть константами времени компиляции. Они могут быть скалярами, строками, типами, значениями процедур, массивами или составными литералами:

```go
MAX_PLAYERS :: 12;

Spawn_Desc :: struct {
    name: string;
    pos: v2;
}

DEFAULT_SPAWNS: []Spawn_Desc : {
    {"Blue", {-4, 0}},
    {"Red", {4, 0}},
};
```

Это недопустимо (потому что `a` не является константой времени компиляции):

```go
a := 123;
b :: a; // ошибка компиляции
```

Инициализаторы глобальных переменных тоже должны быть константами времени компиляции. Используйте `ao_before_scene_load` или `ao_start` для инициализации во время выполнения.

### Глобальные переменные

Глобальные переменные используют тот же синтаксис объявления, что и локальные. Их можно оставить с нулевой инициализацией или инициализировать константами времени компиляции, включая структуры, массивы, значения процедур и `typeid` значения:

```go
score_total: int;
spawn_names: []string = {"Blue", "Red"};
default_type: typeid = int;

start_round :: proc() {
}

on_match_start: proc() = start_round;
```

Глобальные переменные изменяемы и сохраняются на протяжении жизни экземпляра скрипта. Не используйте их для игрового состояния отдельного игрока.

## Типы

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

* Знаковые целые числа: `s8`, `s16`, `s32`, `s64`
* Беззнаковые целые числа: `u8`, `u16`, `u32`, `u64`
* Логические значения: `bool`
* Числа с плавающей точкой: `f32`, `f64`
* Псевдонимы:
  * `int` == `s64`
  * `uint` == `u64`
  * `float` == `f32`
* Векторы: `v2`, `v3`, `v4`
* `string`
* `typeid`
* `любой`

### Типы векторов

`v2` имеет `.x`, `.y`; `v3` добавляет `.z`; `v4` добавляет `.w` — все поля типа float:

```go
pos: v2 = {10, 20};        // x=10, y=20
color: v4 = {1, 0, 0, 1};  // красный с alpha=1
offset := v3{1, 4, 9};     // выведение типа
```

## Структуры и классы

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

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

```go
Food_Definition :: struct {
    name: string;
    food_value: int;
}

food: Food_Definition;
food.name = "Apple";
food.food_value = 10;
```

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

```go
Foo :: class {
    value: int = 10;
    position: v2 = {12, 34};
}

foo := new(Foo);
```

Поля класса могут иметь значения по умолчанию. Производный класс может переопределять унаследованные значения по умолчанию без повторного объявления поля:

```go
Enemy :: class {
    health: int = 100;
    speed: float = 3.0;
}

Boss :: class : Enemy {
    health = 500;
    speed = 1.5;
}
```

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

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

```go
Animal :: class {
    name: string;
    age: int;
}

Dog :: class : Animal {
    breed: string;
}

dog := new(Dog);
dog.name = "Buddy";
dog.age = 5;
dog.breed = "Labrador";
```

## Процедуры и методы

### Процедуры (`proc`)

```go
add :: proc(a: int, b: int) -> int {
    return a + b;
}

result := add(2, 4); // 6
```

Процедуры — это обычные значения, их можно присваивать/хранить так же, как и любые другие значения:

```go
op := proc(a: int, b: int) -> int { return a + b; };
op = proc(a: int, b: int) -> int { return a * b; };
```

### Методы (`method`)

Используйте `method()` внутри структуры/класса. У методов есть неявный `this` параметр-ссылка.

```go
Dog :: class {
    name: string;

    bark :: method() {
        log_info("% says bark!", {name});
    }
}

dog := new(Dog);
dog.name = "Buddy";
dog.bark();
```

### Доступ к полям vs вызов методов

Используйте `.` для полей и методов:

```go
hp := player.health;        // доступ к полю
player.respawn();          // вызов метода
entity.set_local_scale({2, 2});
```

{% hint style="info" %}
Любую процедуру можно вызвать как «метод», если её первый параметр совпадает с типом получателя. Настоящие методы и поля типа со значением процедуры имеют приоритет, прежде чем CSL перейдёт к совпадающей свободной процедуре.
{% endhint %}

## Массивы

В CSL есть несколько типов, похожих на «массивы», которые вы будете использовать постоянно:

* **Фиксированные массивы**: `[4]int`
* **Срезы / управляемые массивы**: `[]T` (часто используется как «только для чтения» представление массива)
* **Динамические массивы**: `[..]T` (изменяемый по размеру список)
* **Неуправляемые массивы**: `[^]T` (используется в сигнатурах встроенного API, таких как `format_string`, `log_info`, и т. д. — передавайте значения как `{a, b, c}`)

Динамические массивы предоставляют `.data`, `.count`, и `.capacity`, а для операций используют синтаксис вызова метода:

```go
numbers: [..]int;
numbers.append(10);
numbers.append(20);

log_info("count: %", {numbers.count});
log_info("first: %", {numbers[0]});
```

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

## Управление потоком

### Если / иначе

```go
if hp <= 0 {
    die();
} else if hp < 25 {
    Notifier.notify(player, "Низкое здоровье!");
} else {
    // всё хорошо
}
```

### Switch

Используйте `default:` для ветки по умолчанию. Ветви поддерживают **несколько значений** (через запятую) и **диапазоны**. Без проваливания в стиле C.

```go
Item_Tier :: enum {
    COMMON;
    UNCOMMON;
    RARE;
    EPIC;
    LEGENDARY;
}

get_tier_color :: proc(tier: Item_Tier) -> v4 {
    switch tier {
        case .COMMON:              return {0.7, 0.7, 0.7, 1.0};
        case .UNCOMMON:            return {0.3, 0.8, 0.3, 1.0};
        case .RARE, .EPIC:         return {0.3, 0.5, 1.0, 1.0};
        case .LEGENDARY:           return {1.0, 0.8, 0.2, 1.0};
        default:                   return {1, 1, 1, 1};
    }
}

// Ветки диапазонов
get_difficulty :: proc(level: int) -> string {
    switch level {
        case 1..5:          return "Легко";
        case 6..<11:        return "Средне";
        case 11..20, 25:    return "Тяжело";
        default:            return "Неизвестно";
    }
}
```

`..` включает обе границы. `..<` исключает верхнюю границу.

### While / for

```go
while condition {
    // ...
}

// Включительный диапазон: 0..9 включает 9
for i: 0..9 {
    log_info("i=%", {i});
}

// Полуоткрытый диапазон: 0..<count исключает count
for i: 0..<items.count {
    log_info("item %", {items[i]});
}

// Обратная итерация
for i: 0..<items.count #reverse {
    log_info("reverse item %", {items[i]});
}

// Итерация по элементам массива/среза
for item: my_items {
    // ...
}

// С переменной индекса
for item, i: my_items {
    log_info("item % at index %", {item, i});
}

// Итерация по собственным итераторам (часто для сущностей/компонентов)
for enemy: component_iterator(Enemy) {
    enemy.update_ai();
}
```

Пользовательские циклы на основе итератора `for` требуют `next :: method() -> bool` и `current` поля.

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

Используйте `expr.(T)` или `cast(T)expr` для приведения типа:

```go
a := 123.4;
b := a.(int);   // 123
c := cast(float)b; // 123.0
```

Когда целевой тип уже известен, CSL может вывести его автоматически:

```go
i: int = a.();
j: int = cast a;
```

## Передача по ссылке: `ref` (предпочтительно)

Когда вам нужно изменить параметр, **предпочитайте `ref`** обычным указателям.

```go
update_position :: proc(pos: ref v2, velocity: v2, dt: float) {
    pos.x += velocity.x * dt;
    pos.y += velocity.y * dt;
}

my_pos := v2{0, 0};
update_position(ref my_pos, {10, 5}, 0.16);
```

## Колбэки: указатели на функции + userdata (без замыканий)

В CSL нет замыканий. Встроенные `proc(...) { ... }` не могут захватывать окружающие переменные.

Чтобы передать контекст, связывайте колбэки с полем `userdata: Object` :

```go
Player :: class : Player_Base {
    on_death_userdata: Object;
    on_death: proc(player: Player, userdata: Object);

    die :: method() {
        if on_death != null {
            on_death(this, on_death_userdata);
        }
    }
}

Death_Tracker :: class : Component {
    count: int;

    ao_start :: method() {
        player := entity.get_component(Player);
        player.on_death_userdata = this;
        player.on_death = proc(player: Player, userdata: Object) {
            tracker := userdata.(Death_Tracker);
            tracker.count += 1;
        };
    }
}
```

## Информация о типах (типы как значения)

`typeid` значения можно передавать в полиморфные процедуры:

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

a := default_of(int);      // 0
b := default_of(string);   // ""
c := default_of([4]int);   // {0, 0, 0, 0}
```

## Лучшие практики (CSL в All Out)

* **Избегайте глобального игрового состояния.** Подключается несколько игроков — храните состояние каждого игрока на `Player` вместо этого.
* **Разделяйте косметическую и игровую логику.** Используйте `is_local()` для только локального UI/частиц, а `is_local_or_server()` для игровых вводов, которые должны выполняться на сервере + локальном клиенте.
* **Мобильный-first по умолчанию.** Не полагайтесь на ввод с клавиатуры/мыши, если только ваша игра явно не ориентирована на ПК.
* **Если вы не уверены в синтаксисе или API**, проверьте `api_reference/` папку, сгенерированную в вашем проекте (она содержит последнюю `core.csl` поверхность).


---

# 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, and the optional `goal` query parameter:

```
GET https://docs.allout.game/all-out-docs/ru/skripting/syntax.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
