Чтение данных игрока
Эта страница показывает, как плагин находит игроков, читает их данные, различает их идентификаторы и меняет их состояние. В Paper Player - объект с методами. В mcrs игрок - сущность внутри мира измерения, а его состояние хранится в наборе компонентов. Поэтому там, где код для Paper держал бы объект, вы пишете запрос.
Страница короткая, потому что набор компонентов растет вместе с проектом. Примеры взяты из файлов репозитория, и вне тестов репозитория мы их не запускали.
Игроков находит запрос
Заголовок раздела «Игроков находит запрос»У каждой сущности игрока есть компонент-маркер Player. Система в мире измерения видит игроков только этого измерения, об этом рассказывает страница Измерения. Тестовое окружение находит игрока таким же запросом:
pub fn player_in(&mut self, dim: Entity, anchor: Entity) -> Option<Entity> { let session = self.session_of(anchor)?; let world = self.world_in(dim); world .query_filtered::<(Entity, &Owner), With<Player>>() .iter(world) .find(|(_, owner)| owner.0 == session) .map(|(player, _)| player)}crates/mcrs_minecraft_server/tests/it/host_app/mod.rs:374-382
В плагине запрос пишется как параметр системы, например Query<(&GameProfile, &PlayerGameMode), With<Player>>. Эта строка только иллюстрация, ее никто не компилировал. Имена типов в ней взяты из файлов следующего раздела.
Компоненты, которые можно читать
Заголовок раздела «Компоненты, которые можно читать»GameProfile - профиль, с которым клиент вошел на сервер:
#[derive(Debug, Clone, Component)]pub struct GameProfile { pub id: uuid::Uuid, pub username: String, pub properties: Vec<Property<String>>,}crates/mcrs_minecraft_engine/src/game_profile.rs:8-13
Режим игры, состояние полета и уровень оператора лежат в одном файле:
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Deref, DerefMut)]pub struct PlayerGameMode(pub GameMode);
impl Default for PlayerGameMode { fn default() -> Self { Self(GameMode::Survival) }}
/// Whether the player flies, as its client reports it and its game mode allows.#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Deref, DerefMut, Default)]pub struct PlayerFlying(pub bool);crates/mcrs_minecraft_engine/src/ability.rs:12-23
PlayerOpLevel в том же файле хранит уровень оператора, от 0 для игрока без прав оператора до 4. Тестовое окружение читает режим игры так:
pub fn game_mode(&mut self, anchor: Entity) -> GameMode { let player = self.player(anchor); self.world().get::<PlayerGameMode>(player).unwrap().0}crates/mcrs_minecraft_server/tests/it/host_app/mod.rs:389-392
У одного игрока три идентификатора
Заголовок раздела «У одного игрока три идентификатора»Подставить один из них вместо другого нельзя.
| Идентификатор | Где | Что это |
|---|---|---|
GameProfile::id |
компонент игрока | UUID профиля, как в Paper |
PlayerSession |
компонент Owner игрока в мире измерения, а также на хосте |
имя одного соединения. Хост не выдает одно значение дважды, а при смене измерения оно сохраняется |
Entity |
сущность игрока внутри одного мира измерения | идентификатор Bevy, который существует только в одном мире. У хоста для того же игрока есть еще якорная сущность, и это другая сущность |
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]pub struct PlayerSession(pub u64);crates/mcrs_minecraft_engine_world/src/session/sessions.rs:12-13
По сессии адресуйте игрока между мирами и отправляйте ему пакеты. UUID берите для всего, что должно пережить переподключение.
Игрока меняют внутри его мира
Заголовок раздела «Игрока меняют внутри его мира»Внутри мира игрока его компоненты можно вставлять и править. Не меняйте игрока из системы, которая работает в другом мире. Изменение, которое пересекает границу миров, передается сообщением или эффектом. Ванильные команды gamemode и teleport делают это через эффекты команд, см. Добавить команду.
Отправка сообщения игроку
Заголовок раздела «Отправка сообщения игроку»Метода player.sendMessage() в mcrs нет. Низкоуровневый способ - записать пакет в сессию. Плагин чата так и поступает с игроком, который скрыл чат:
if info.is_some_and(|info| info.chat_mode == ChatMode::Hidden) { let disabled: Text = Text::translate("chat.disabled.options", vec![]).color(Color::RED); if let Ok(disabled) = RawText::from_text(&disabled) { packet_writer.write(bus::to(owner.0, system_chat(disabled))); } return;}crates/mcrs_minecraft_chat_server/src/chat_plugin.rs:56-62
Более удобного слоя для этого пока нет. Issue о нем мы не знаем, поэтому ничего не обещаем.
Сохранение данных игрока тоже не готово.2 Состояние сохранения показывает страница Статус.
Дальше: Тест плагина без клиента, где тест подключает фиктивного игрока и читает эти компоненты.
Footnotes
Заголовок раздела «Footnotes»Источники и проверка
Проверено: 26.4-snapshot-7, 51d45c26a, 2026-11-09
Переведено с версии 51d45c26a
- crates/mcrs_minecraft_engine/src/ability.rs
- crates/mcrs_minecraft_engine/src/game_profile.rs
- crates/mcrs_minecraft_engine_world/src/entity/player/mod.rs
- crates/mcrs_minecraft_engine_world/src/session/sessions.rs
- crates/mcrs_minecraft_server/tests/it/host_app/mod.rs
- issue #158
Следить: #158