Script и LocalScript в Roblox: в чём разница и где их использовать

В Roblox есть несколько типов скриптов, но чаще всего новичок упирается в два: Script и LocalScript. Они похожи по синтаксису Luau, но запускаются в разных местах: один — на сервере, другой — на устройстве игрока.

Правильный выбор зависит от вопроса: кто должен «решать» действие (сервер или клиент), кто должен это видеть (все или один игрок) и какие данные можно считать надёжными.

В этом гайде — логика выбора Script/LocalScript, правильные папки в Explorer, базовые правила связи через RemoteEvent и список типовых ошибок, когда «скрипт не работает».

Если вы используете новые настройки RunContext, поведение Script может отличаться от старых уроков. В статье отдельно показано, как это влияет на запуск кода.

Короткий ответ: чем Script отличается от LocalScript

Script выполняется на сервере Roblox и может менять мир так, чтобы изменения увидели все игроки. LocalScript выполняется на клиенте (у конкретного игрока) и обычно отвечает за интерфейс, ввод, камеру и локальные эффекты.

Быстрое правило выбора

  • Если действие влияет на других игроков, награды, предметы, сохранения — выбирайте сервер (Script).
  • Если действие нужно только одному игроку (UI, подсказки, управление камерой) — выбирайте клиент (LocalScript).

Таблица сравнения

ВопросScriptLocalScript
Где запускаетсяСерверКлиент игрока
Кто видит результатВсе (через серверную репликацию)Обычно только один игрок
Можно ли доверять входным даннымДа, если данные получены/проверены на сервереНет, клиент можно подменить
Типичные задачиСпавн предметов, урон, покупки, сохраненияUI, кнопки, эффекты, локальные анимации

А где тут ModuleScript

ModuleScript — это способ хранить общий код и подключать его через require. Он не «серверный» и не «клиентский» сам по себе: контекст зависит от того, кто его вызвал и где он лежит.

Где запускаются скрипты: сервер, клиент и RunContext

У Roblox есть граница «клиент ↔ сервер». Сервер считается авторитетным: он решает, что действительно произошло. Клиент отвечает за удобство и мгновенную реакцию, но его данные нельзя считать честными без проверки.

RunContext: почему «обычный Script» иногда ведёт себя как LocalScript

У базового класса скриптов есть свойство RunContext, которое определяет, в каком контексте выполняется код. В старой модели (legacy) поведение сильно зависело от типа скрипта и места в дереве. В новой модели можно явно задать контекст для Script.

  • Если RunContext настроен на сервер, код работает как обычный серверный Script.
  • Если RunContext настроен на клиент, Script выполняется на клиенте и по смыслу становится похож на LocalScript, но может использоваться в других местах модели.

Не используйте клиентский RunContext как способ «спрятать логику». Любой код, попавший на клиент, можно прочитать и изменить, поэтому важные решения всё равно должны быть на сервере.

Почему важно знать контекст прямо сейчас

Когда вы переносите код между папками или меняете RunContext, могут меняться доступные объекты и порядок запуска. Если у вас внезапно перестали работать события или появились nil, первым делом проверьте: где лежит скрипт и какой у него контекст.

Где размещать скрипты в Explorer

Даже правильный по смыслу скрипт не запустится, если лежит «не там». У Roblox есть контейнеры, которые автоматически копируются игрокам или доступны только серверу.

Рекомендуемые папки

Куда положитьЧто там обычно лежитЗачем
ServerScriptServiceScript, ModuleScriptСерверная логика, недоступная клиенту
ServerStorageШаблоны моделей, ресурсыХранение того, что не нужно клиенту
ReplicatedStorageRemoteEvent, RemoteFunction, общие ModuleScriptДоступно и серверу, и клиенту
StarterPlayerScriptsLocalScriptКод, который запускается у каждого игрока при входе
StarterCharacterScriptsLocalScriptКод, который копируется в персонажа при каждом спавне
StarterGuiUI и LocalScript внутри UIUI копируется в PlayerGui, там и запускается LocalScript

Что нельзя делать (частые ловушки)

  • Класть LocalScript в Workspace и ждать, что он запустится. Обычно он не выполняется, если не находится внутри персонажа игрока.
  • Пытаться выполнять серверный Script в папках, которые копируются игроку (например, в StarterGui). Эти контейнеры не предназначены для серверного кода.

Мини-чеклист перед отладкой

  1. Скрипт лежит в правильном контейнере?
  2. Включён ли он (Enabled) и не остановлен ли ошибкой?
  3. Не зависит ли он от объекта, который создаётся позже?

Как общаться клиенту и серверу: RemoteEvent и RemoteFunction

Клиент и сервер не делят одну память. Если игрок нажал кнопку в интерфейсе, сервер узнает об этом только если вы отправите сообщение через специальные объекты сети.

Что использовать: RemoteEvent или RemoteFunction

ИнструментКак работаетКогда подходит
RemoteEventОднонаправленно, без ожидания ответаСигналы: «кнопка нажата», «удар нанесён», «хочу купить»
RemoteFunctionДвусторонне, с ожиданием ответаРедкие запросы, где нужен немедленный ответ и вы контролируете нагрузку

Где хранить remotes

RemoteEvent/RemoteFunction должны лежать там, где их видят обе стороны. Чаще всего для этого используют ReplicatedStorage.

Серверная проверка: минимальный стандарт

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

Что происходитВероятная причинаЧто сделать
Игрок «покупает» предмет без денегСервер доверяет числу из клиентаХраните баланс на сервере и пересчитывайте итог на сервере
RemoteEvent спамят сотни разНет лимитов частотыДобавьте rate limit и банально игнорируйте лишнее
Игрок активирует объект на другом конце картыНет проверки позиции/дистанцииПроверьте расстояние на сервере, а не на клиенте

Следующая важная тема: RemoteEvent и RemoteFunction.

Безопасность: почему клиенту нельзя доверять

Короткая формулировка, которая экономит недели: клиент нельзя считать честным. Всё, что запускается у игрока, можно подменить: значения, вызовы remotes, порядок действий.

Что именно считается «недоверенным»

  • Любые числа, которые клиент прислал на сервер (урон, скорость, цену, награду).
  • Любые «факты», которые клиент утверждает (я рядом с магазином, я попал по цели).
  • Любой код, который оказался в доступных клиенту контейнерах (его можно прочитать).

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

  1. Сервер хранит истину: инвентарь, валюту, прогресс, выдачу наград.
  2. Клиент просит, сервер решает: клиент отправляет запрос, сервер проверяет и выполняет.
  3. Сервер вычисляет критичные вещи сам: например, итоговую цену или награду.
  4. Проверяйте контекст: дистанция, кулдаун, состояние персонажа, допустимые предметы.

Если вы делаете античит, не пытайтесь «спрятать» его в LocalScript. Смысл античита — серверные проверки, а не секретный код на клиенте.

Где клиент действительно нужен

Клиент полезен там, где важна мгновенная реакция: анимации интерфейса, эффекты, подсказки, предварительный прицел. Но итог (попадание, урон, покупка) лучше подтверждать сервером.

Шаблоны: Типичные задачи и где писать код

Ниже — типовые задачи и где их удобнее реализовывать. Это не единственно верный путь, но хороший старт для структуры проекта.

Таблица: задача → где код → почему

ЗадачаГде писатьПочему так
Кнопка UI «Купить»LocalScript (UI) + Script (сервер) через RemoteEventUI живёт у игрока, а списание валюты и выдача предмета должны быть на сервере
Подсказка на экране, уведомленияLocalScriptЭто локальный эффект, другим игрокам не нужен
Спавн предмета в миреScriptИзменение мира должно быть серверным, иначе его не увидят все
Локальная камера/вводLocalScriptДоступ к камере и вводу — клиентская зона
Сохранение прогрессаScriptСохранения должны выполняться на сервере

Мини-шаблон структуры (без кода)

  1. UI-кнопка вызывает RemoteEvent с минимальными данными (например, id товара).
  2. Серверный обработчик проверяет: существует ли товар, хватает ли валюты, нет ли спама.
  3. Сервер изменяет состояние (валюта/инвентарь) и при необходимости сообщает клиенту результатом.

Если вы хотите вынести бизнес-логику в общий модуль, используйте ModuleScript и держите его либо в ServerScriptService (только сервер), либо в ReplicatedStorage (если нужен доступ клиенту и серверу).

Если модуль лежит в ReplicatedStorage, исходники модуля также окажутся на клиенте. Не храните там секреты и критичные правила без серверной проверки.

Ошибки и диагностика

Если «ничего не происходит», почти всегда проблема в одном из четырёх пунктов: контекст, место в дереве, порядок запуска, или сеть (remotes).

Таблица: Что происходит → причина → что сделать

Что происходитВероятная причинаЧто сделать
LocalScript не печатает даже printСкрипт лежит в месте, где клиент не запускает LocalScriptПереместите в StarterPlayerScripts / StarterCharacterScripts / PlayerGui / Backpack
LocalScript в StarterGui «не работает»Он запускается уже в PlayerGui после копированияПроверяйте путь и ищите его в PlayerGui во время игры
OnClientEvent/OnServerEvent не срабатываетRemoteEvent лежит в месте, недоступном одной сторонеПоложите remote в ReplicatedStorage и убедитесь, что имя совпадает
nil у LocalPlayer.Character или его частейПерсонаж ещё не создан или идёт респавнЖдите появления Character/ChildAdded и учитывайте респавн
Серверный Script «как будто не видит» изменения клиентаКлиентские изменения не реплицируются на серверПередавайте намерение через remotes и применяйте изменения на сервере

Что проверить сначала

  1. Откройте Output и посмотрите первые ошибки (красные строки).
  2. Проверьте, что скрипт запущен в нужном контексте (сервер/клиент) и в правильной папке.
  3. Если есть remote: проверьте его место (обычно ReplicatedStorage) и имена обработчиков.
  4. Если ошибка связана с персонажем: добавьте ожидание появления Character и нужных частей.

Типовая структура отладки

  • Добавьте по одному простому print в ключевых местах и убедитесь, что путь выполнения вообще проходит там.
  • Если код на клиенте, смотрите клиентский Output; если на сервере — серверный.
  • Если проблема сетевой: временно логируйте аргументы, которые приходят в обработчик на сервере.
🧑‍💻
Administrator
Автор на RobloxInfo