Перейти к содержимому

Убрать и заменить ванильные части

Меняется. Следите: #278, #279, #281, #282

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

В Paper вы берете готовый сервер и добавляете к нему плагины. В mcrs вы берете группу плагинов и убираете из нее лишнее, поэтому лобби может работать без генерации мира, а тест - без освещения. Примеры взяты из файлов репозитория, вне репозиторных тестов мы их не запускали.

MinecraftServerPlugins - это PluginGroup из Bevy, то есть набор плагинов, который добавляют в приложение одним значением. Четыре ее поля - это части, которые принимают настройки:

Поля группы
pub struct MinecraftServerPlugins {
pub core: ServerCorePlugin,
pub worlds: DimensionWorldsPlugin,
pub world_gen: WorldGenPlugin,
pub network: ServerNetworkPlugin,
}

crates/mcrs_minecraft_server/src/lib.rs:22-27

Остальной ванильный сервер добавляет build(). Члены группы в том порядке, в каком build() их добавляет: ядро сервера, реестры генерации мира, ванильный набор команд, ванильные команды, команды мира, миры измерений, чат, физика сущностей, мозги мобов, генерация мира, освещение и сеть.1

Члены группы
impl PluginGroup for MinecraftServerPlugins {
fn build(self) -> PluginGroupBuilder {
PluginGroupBuilder::start::<Self>()
.add(self.core)
.add(WorldgenRegistriesPlugin)
.add(CommandPlugin::<VanillaCommands>::new())
.add(VanillaCommandsPlugin)
.add(WorldCommandsPlugin)
.add(self.worlds)
.add(VanillaChatPlugin)
.add(VanillaEntityPhysicsPlugin)
.add(VanillaMobBrainPlugin)
.add(self.world_gen)
.add(LightingPlugin)
.add(self.network)
}
}

crates/mcrs_minecraft_server/src/lib.rs:61-77

Любого члена группы можно отключить или заменить, не трогая крейт сервера. Если члену нужен другой плагин, а его нет, группа паникует при сборке и называет недостающий плагин. Ошибку вы получаете на старте, и вам не приходится разбираться с отсутствующим ресурсом на первом тике.

Ванильный геймплей живет в плагинах над движком. Каждый из них можно убрать отдельно, а в каждый мир измерения они попадают через add_dimension_plugin.2

Бинарник выключает ИИ мобов так:

src/main.rs: выключить ИИ мобов
if !settings.mob_ai {
server = server.disable::<VanillaMobBrainPlugin>();
}

src/main.rs:92-94

disable::<T>() - метод билдера группы плагинов Bevy, а T - плагин, который вы убираете. Тест из репозитория тем же методом запускает сервер без генерации мира и освещения:

Тест: сервер без генерации мира и освещения
fn a_client_without_an_app_joins_the_embedded_server_offline() {
let mut plugins = MinecraftServerPlugins::embedded();
plugins.core.asset_path = Some(ASSETS.to_owned());
plugins.network.announce_on_lan = false;
let mut app = App::new();
app.add_plugins(
plugins
.build()
.disable::<WorldGenPlugin>()
.disable::<LightingPlugin>(),
);
let stop = StopOnDrop(Arc::new(AtomicBool::new(false)));

crates/mcrs_minecraft_server/tests/it/client_join.rs:31-42

Этот тест вызывает еще и MinecraftServerPlugins::embedded(). Он дает сервер, который работает внутри другого процесса. Такой сервер слушает только loopback, берет порт, который назначит ОС, и оставляет пулы задач приложению-хозяину.

embedded()
impl MinecraftServerPlugins {
/// A server running inside another process: loopback only, an OS-assigned
/// port, and the task pools left to the host app.
pub fn embedded() -> Self {
let defaults = Self::default();
Self {
core: ServerCorePlugin {
owns_task_pools: false,
..defaults.core
},
network: ServerNetworkPlugin::embedded(),
..defaults
}
}
}

crates/mcrs_minecraft_server/src/lib.rs:45-59

Бинарник читает настройки из окружения и превращает их в поля плагинов в src/main.rs:

src/main.rs: от настроек к полям плагинов
let settings = ServerSettings::read(
|name| std::env::var(format!("MCRS_{name}")).ok(),
|error| bevy_log::warn!("{error}"),
);
let mut server = MinecraftServerPlugins {
core: ServerCorePlugin {
compute_threads: settings.compute_threads,
..MinecraftServerPlugins::default().core
},
worlds: DimensionWorldsPlugin {
world: world_folder(),
ops,
seed: settings.world_seed,
preset: settings.world_preset.clone(),
default_game_mode: settings.default_game_mode,
..Default::default()
},
world_gen: WorldGenPlugin,
network: network(&settings),
}
.build();

src/main.rs:71-91

Так делает только бинарник. Библиотечный крейт не читает ради своих настроек ни переменные окружения, ни файлы, и каждая настройка - поле того плагина, который ее использует.3

Переменные окружения бинарника соответствуют полям ServerSettings. Имя переменной - это имя поля с префиксом MCRS_. Полный список лежит в исходном файле.

В собственной программе обойдитесь без ServerSettings и заполните поля плагинов сами. Тогда встроенный сервер в тесте стартует с явными настройками, что бы ни экспортировал шелл.

Дальше: Добавить команду.

  1. Работает#279 Делит плагин сервера на группу плагинов, которые можно убрать. ↩

  2. Работает#282 Переносит ванильный геймплей из крейта сервера в убираемые плагины. ↩

  3. Работает#278 Сервер настраивается только через свой плагин. ↩

  4. В работе#281 Планирует источник чанков как заменяемую точку расширения с пустым и плоским источниками. ↩

  5. В работе#78 Отслеживает сохранение измененных чанков в файлы регионов. ↩

Источники и проверка

Проверено: 26.4-snapshot-7, 51d45c26a, 2026-11-09

Переведено с версии 51d45c26a

Следить: #278, #279, #281, #282