diff --git a/README.md b/README.md index ddf61945..e190c451 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ GTNHLib ======= +🌐 **Languages:** [English](README.md) | [Українська](README_uk.md) + ## About Shared code library for GTNH mods. diff --git a/README_uk.md b/README_uk.md new file mode 100644 index 00000000..d16f9167 --- /dev/null +++ b/README_uk.md @@ -0,0 +1,76 @@ +GTNHLib +======= + +🌐 **Мови:** [English](README.md) | [Українська](README_uk.md) + +## Про бібліотеку + +Спільна бібліотека коду для модів GTNH. + +## Можливості + +### Налаштування + +- Визначення налаштувань за допомогою анотації `@Config` для класу. Кожне поле стає параметром конфігурації. +- Встановлення значень за замовчуванням, діапазонів, коментарів та ключів локалізації за допомогою анотацій полів, таких як `@DefaultInt`, `@RangeInt` та `@Comment`. +- Бібліотека зчитує, записує та перевіряє файл `.cfg` за вас. Жодних ручних викликів `Configuration`. +- Позначення полів анотацією `@Sync` для надсилання значень із сервера клієнтам під час підключення. +- Створення графічного інтерфейсу налаштувань Forge прямо з анотацій. + +### Події + +- Викликає `InventoryChangedEvent`, коли змінюється загальна кількість предметів в інвентарі гравця. Підписуйтесь на `ItemAdded` або `ItemRemoved`, які містять змінений `ItemStack`, дельту зі знаком, а також `inventoryCount` — загальну кількість цього предмета у гравця після зміни. +- Предмети зіставляються за типом і метаданими, ігноруючи NBT, тому сортування інвентарю не викликає жодних подій. Сканування виконується кожні кілька тактів (можна налаштувати). +- Викликає `PickBlockEvent`, коли гравець клацає середньою кнопкою миші по блоку. +- Позначте клас анотацією `@EventBusSubscriber` для автоматичної реєстрації його методів `@SubscribeEvent`. Виберіть сторону та етап завантаження в анотації. Ручна реєстрація не потрібна. + +### Предмети + +- `ImmutableItemStack` обгортає стек як доступний лише для читання, щоб запобігти випадковим змінам. +- `ItemTransfer` переміщує предмети між `ItemSource` та `ItemSink` за допомогою фільтрів-предикатів та обмежень кількості. +- Перебирайте будь-який `IInventory` за допомогою `InventoryIterator`, включно зі слотами, прив’язаними до сторін блока. +- Інтерфейси джерела та приймача абстрагують вилучення та вставлення предметів, тому логіка переміщення працює з будь-яким типом інвентарю. + +### Рендеринг + +- Рендеринг предметів з кількома накладеними текстурними шарами шляхом реалізації `ItemWithTextures`. Реєструйте за допомогою `TexturedItemRenderer`. +- `CapturingTesselator` захоплює квади рендерингу поза основним потоком для пакетної або асинхронної візуалізації. +- Допоміжні класи для анімованих підказок та HUD-повідомлень над панеллю швидкого доступу. + +### Стан блоку + +- Реєстрація власних властивостей блоку: boolean, int, enum, direction, axis та orientation. +- Пакування та зчитування значень властивостей із метаданих блоку, щоб на версії 1.7 блоки поводилися як сучасні стани блоків. +- Включає команду `blockstate` для перевірки стану блоку за координатами. + +### Команди + +- Brigadier command API для сучасного парсингу, автодоповнення та виконання команд на версії 1.7. +- Реєстрація власних ігрових правил за допомогою `GameRuleRegistry`. Бібліотека вбудовується у ванільну систему ігрових правил, щоб сповіщати ваші правила про зміни. + +### Команди гравців + +- Система керування командами гравців з ролями, складом учасників та адміністративними командами. +- Реєстрація власних даних команди за допомогою `TeamDataRegistry`. Бібліотека зберігає їх на диск і синхронізує з клієнтами. + +### Мережа + +- Надсилання екранних повідомлень, повідомлень над панеллю швидкого доступу та дальності промальовування клієнтам. +- Синхронізація власних даних гравців. + +### Утиліти + +- Бекпорт `MemoryUtil` та `MemoryStack` у стилі LWJGL3 в пакеті `bytebuf`. +- 32- та 64-бітне хешування FNV-1a. +- Допоміжні класи для роботи з математикою, NBT, JSON, файлами, напрямками та відстанями. +- Типи кольорів для RGB та HSV. +- Ітератори та трансформації 3D-геометрії. +- Допоміжні класи для провайдерів можливостей. +- Синхронізовані прив’язки клавіш. +- Допоміжні класи для роботи з ASM та байт-кодом. +- Перевірка сумісності з модами (Baubles, FalseTweaks, NEI). +- Тіньове підключення FastUtil через https://github.com/GTNewHorizons/GTNHExtLib + +## Подяки + +Налаштування: Оригінальний код від FalsePattern, що розповсюджується за ліцензією LGPL-3.0 у [FalsePatternLib](https://github.com/FalsePattern/FalsePatternLib/tree/master/src/main/java/com/falsepattern/lib/config) diff --git a/models.md b/models.md index 41665b34..28c946b2 100644 --- a/models.md +++ b/models.md @@ -1,5 +1,7 @@ # Model API +🌐 **Languages:** [English](models.md) | [Українська](models_uk.md) + In general, it is designed to mimic the latest version. ### Intentional deviations diff --git a/models_uk.md b/models_uk.md new file mode 100644 index 00000000..70150213 --- /dev/null +++ b/models_uk.md @@ -0,0 +1,174 @@ +# Model API + +🌐 **Мови:** [English](models.md) | [Українська](models_uk.md) + +Загалом цей API розроблений так, щоб імітувати поведінку новіших версій Minecraft. + +### Свідомі відхилення +Наразі відсутні. + +### Колишні відхилення +Посилання на текстури більше не вважаються прив’язаними до розташувань 1.7.10. +Замість цього вони обробляються з assets/namespace/textures, як у сучасних версіях. +Це також означає, що тепер ви можете використовувати будь-яку текстуру у своєму ISBRH, +і GTNHLib впровадить її в атлас блоків. Будь ласка, використовуйте цю можливість відповідально. + +Ресурспаки тепер можуть замінювати більшість блоків, аналогічно до сучасних версій. +*Зверніть увагу:* це працює насамперед для блоків із ISBRH — якщо для блоку +в коді зареєстровано TESR, це призведе до рендерингу *як* моделі, +*так і* TESR. + +## Приклади +### BlockColor +Використовуйте для застосування кольору до `TintIndex`. +
+Приклад: Використання реєстрації BlockColor + +
+BlockColor.registerBlockColors(new IBlockColor() {
+
+ @Override
+ public int colorMultiplier(IBlockAccess world, int x, int y, int z, int tintIndex) {
+ // Повертає червоний колір для основного шару, зелений — для додаткового
+ return tintIndex == 0 ? 0xFF0000 : 0x00FF00;
+ }
+
+ @Override
+ public int colorMultiplier(ItemStack stack, int tintIndex) {
+ // Повертає синій колір для основного шару, жовтий — для додаткового
+ return tintIndex == 0 ? 0x0000FF : 0xFFFF00;
+ }
+}, ModBlocks.MY_CUSTOM_BLOCK);
+
+
+Приклад: Реалізація `IBlockColor` безпосередньо у класі блоку
+
+public class BlockTestTint extends Block implements IBlockColor {
+
+ public BlockTestTint() {
+ super(Material.wood);
+ }
+
+ @Override
+ public int colorMultiplier(IBlockAccess world, int x, int y, int z, int tintIndex) {
+ return switch(tintIndex) {
+ case 0 -> 0xFF0000; // червоний
+ case 1 -> 0x00FF00; // зелений
+ case 2 -> 0x0000FF; // синій
+ case 3 -> 0xFFFF00; // жовтий
+ case 4 -> 0xFF00FF; // пурпуровий
+ case 5 -> 0x00FFFF; // блакитний
+ default -> 0xFFFFFF; // білий
+ };
+ }
+
+ @Override
+ public int colorMultiplier(ItemStack stack, int tintIndex) {
+ return colorMultiplier(null, 0, 0, 0, tintIndex);
+ }
+}
+
+
+### BlockState API
+
+Замість використання 4-бітових метаданих, вибір моделі можна визначити на основі повних даних про стан блоку за допомогою зареєстрованого `BlockProperty`.
+
+Це дозволяє:
+- Необмежену кількість логічних станів (без обмеження в 16 значень метаданих);
+- Варіанти моделей на основі даних `TileEntity`;
+- Визначення стану з урахуванням `ItemStack`;
+- Динамічну поведінку рендерингу.
+
+Визначення BlockState працює у три кроки:
+1. `BlockProperty` реєструється для блоку (і опціонально для його предмета).
+2. Властивість надає значення з:
+ - Світу + `TileEntity`
+ - `ItemStack`
+3. Завантажувач `JsonModel` визначає варіанти моделей, використовуючи ці значення властивостей.
+
+#### 1. Створення BlockProperty
+
+Приклад: Властивість напрямку, яка базується на `TileEntity`.
+
+
+DirectionBlockProperty property = new DirectionBlockProperty() {
+
+ @Override
+ public String getName() {
+ return "facing";
+ }
+
+ @Override
+ public boolean hasTrait(BlockPropertyTrait trait) {
+ return switch (trait) {
+ case SupportsWorld, WorldMutable, StackMutable, SupportsStacks -> true;
+ default -> false;
+ };
+ }
+
+ @Override
+ public ForgeDirection getValue(IBlockAccess world, int x, int y, int z) {
+ TileEntity te = world.getTileEntity(x, y, z);
+ if (te instanceof TileTestTintMul tile) {
+ return tile.getFacing();
+ }
+ return ForgeDirection.NORTH;
+ }
+
+ @Override
+ public void setValue(World world, int x, int y, int z, ForgeDirection value) {
+ TileEntity te = world.getTileEntity(x, y, z);
+ if (te instanceof TileTestTintMul tile) {
+ tile.setFacing(value);
+ }
+ }
+
+ @Override
+ public ForgeDirection getValue(ItemStack stack) {
+ return ForgeDirection.NORTH;
+ }
+};
+
+
+#### 2. Реєстрація властивості
+
++BlockPropertyRegistry.registerProperty(block, property); +BlockPropertyRegistry.registerProperty(Item.getItemFromBlock(block), property); ++Ви повинні зареєструвати властивість: + - Для блоку (стан у світі); + - Для предмета (відображення в інвентарі). + +#### 3. Визначення JSON-файлу blockstate + +Приклад: +
+{
+ "variants": {
+ "facing=north": { "model": "modid:block/machine_north" },
+ "facing=south": { "model": "modid:block/machine_south" },
+ "facing=west": { "model": "modid:block/machine_west" },
+ "facing=east": { "model": "modid:block/machine_east" }
+ }
+}
+
+
+Завантажувач виконає такі дії:
+- Надішле запит до `property.getValue(...)`;
+- Сформує рядок стану, наприклад: `facing=north`;
+- Визначить відповідний варіант моделі.
+
+#### Підтримувані атрибути
+`BlockPropertyTrait` керує тим, де саме працює властивість:
+- `SupportsWorld` → використовується під час рендерингу у світі;
+- `SupportsStacks` → використовується під час рендерингу предмета в інвентарі;
+- `WorldMutable` → значення можна змінювати у світі;
+- `StackMutable` → значення можна змінювати в ItemStack.
+
+Реалізовуйте лише ті атрибути, які вам необхідні.
+
+### Заплановано
+- Додавання м’якого затінення до ModelISBRH.
+- Додавання відсікання граней для моделей.
+- Реалізація фіксації UV-координат.
diff --git a/src/main/resources/assets/gtnhlib/lang/uk_UA.lang b/src/main/resources/assets/gtnhlib/lang/uk_UA.lang
new file mode 100644
index 00000000..a35ea052
--- /dev/null
+++ b/src/main/resources/assets/gtnhlib/lang/uk_UA.lang
@@ -0,0 +1,295 @@
+# Тестові блоки
+tile.model_test.name=Тестовий блок
+tile.model_test_tint.name=Тестовий блок (Відтінок)
+tile.model_test_tint_mul.name=Тестовий блок (Множник відтінку)
+tile.model_test_lectern.name=Тестовий блок аналоя
+tile.rng_test.name=Тестовий блок RNG
+tile.weighted_rng_test.name=Тестовий блок зваженого RNG
+
+# Налаштування
+fml.configgui.tooltip.default=[типово: %s]
+fml.configgui.tooltip.defaultNumeric=[діапазон: %2$s ~ %3$s, типово: %1$s]
+
+# Перенесено з WAWLA (What Are We Looking At)
+# Професії селян
+description.villager.profession.farmer=Фермер
+description.villager.profession.librarian=Бібліотекар
+description.villager.profession.priest=Церковник
+description.villager.profession.blacksmith=Коваль
+description.villager.profession.butcher=М’ясник
+description.villager.profession.zombie=Зомбі
+description.villager.profession.witch=Відьма
+description.villager.profession.misingno=Звичайний
+description.villager.profession.openblocks.king-ish=Королеподібний
+description.villager.profession.tinker.villagertools=Майстер
+description.villager.profession.extvil.Miller=Мельник
+description.villager.profession.extvil.Fisher=Рибалка
+description.villager.profession.extvil.Baker=Пекар
+description.villager.profession.extvil.Miner=Шахтар
+description.villager.profession.extvil.Scientist=Вчений
+description.villager.profession.extvillom.Tanner=Чинбар
+description.villager.profession.forestry.beekeeper=Бджоляр
+description.villager.profession.forestry.lumberjack=Лісоруб
+description.villager.profession.mystcraft.archivist=Архівіст
+description.villager.profession.bcaddons.Engineer=Інженер
+description.villager.profession.thaumcraft.wizard=Чаклун
+description.villager.profession.thaumcraft.moneychanger=Торговець
+description.villager.profession.compactmachines.villager=Компактний механік
+description.villager.profession.railcraft.trackman=Залізничник
+description.villager.profession.pneumaticcraft.VillagerMechanic=Механік
+description.villager.profession.witchery.apothecary=Аптекар
+description.villager.profession.minefactoryreloaded.zoologist=Зоолог
+description.villager.profession.is_mtc.card_master=Майстер карт
+description.villager.profession.gravestone.undertaker=Гробар
+description.villager.profession.gcewing_sg.tokra=Ток’ра
+description.villager.profession.steamcraft.villager=Паровий майстер
+description.villager.profession.fantastic.fantastic_fisherman=Дивовижний рибалка
+description.villager.profession.defeatedcrow.villager_cafe=Офіціант
+description.villager.profession.defeatedcrow.villager_yome=Йоме
+description.villager.profession.grccellar.brewer=Пивовар
+description.villager.profession.peripheralsplusplus.CCVillager=Комп’ютерний технік
+description.villager.profession.evilcraft.werewolfVillager=Перевертень
+description.villager.profession.redgear_brewcraft.villagerwitch=Відьма
+description.villager.profession.redgear_brewcraft.villagerwarlock=Чорнокнижник
+description.villager.profession.fossil.Archaeologist=Археолог
+description.villager.profession.pennyarcade.CoinMerchant=Торговець монетами
+description.villager.profession.psychedelicraft.villagerDealer=Наркоторговець
+description.villager.profession.jukeboxreloaded.villager=Торговець платівками
+description.villager.profession.minecraft.etymologist=Етимолог
+description.villager.profession.tofucraft.tofucook=Шеф-кухар тофу
+description.villager.profession.jewelrycraft.jeweler=Ювелір
+description.villager.profession.taverns.barwench=Шинкарка
+description.villager.profession.taverns.village_shepherdess=Пастушка
+description.villager.profession.taverns.village_hostler=Конюх
+description.villager.profession.taverns.village_baker=Пекар
+description.villager.profession.tynkyn.jx_villager_chef=Шеф-кухар
+description.villager.profession.tynkyn.jx_villager_recycle=Спеціаліст із вторсировини
+description.villager.profession.tynkyn.jx_villager_botanist=Ботанік
+description.villager.profession.lozmod.villager_beedle=Бідл
+description.villager.profession.lozmod.villager_beedle_special=Бідл
+description.villager.profession.minecraft.farmer=Фермер
+description.villager.profession.savemoney.insurer=Страховик
+description.villager.profession.gvcguns.gvcVillager=Торговець зброєю
+description.villager.profession.actuallyadditions.jamVillager=Торговець джемом
+description.villager.profession.jewelrycraft2.jeweler=Ювелір
+description.villager.profession.pokecube_adventures.cubesalesman=Продавець покекубів
+description.villager.profession.terraarts.YE3TE2y=YE3TE2y
+description.villager.profession.xw.smithy3=Коваль
+description.villager.profession.xw.hunter_v1=Мисливець
+description.villager.profession.diversity.warrior=Воїн
+description.villager.profession.diversity.priest=Священник
+description.villager.profession.diversity.butcher=М’ясник
+description.villager.profession.diversity.chief=Вождь
+description.villager.profession.diversity.breeder=Селекціонер
+description.villager.profession.diversity.guru=Гуру
+description.villager.profession.diversity.farmer=Фермер
+description.villager.profession.jbrobot.jbvillagerblock=Блоки
+description.villager.profession.jbrobot.jbvillageritem=Предмети
+description.villager.profession.jbrobot.jbvillagermodel=Моделі
+description.villager.profession.jbrobot.jbvillagermotion=Рух
+description.villager.profession.jbrobot.jbvillagercarving=Різьблення
+description.villager.profession.wa.villager=Селянин
+description.villager.profession.wa.swordsmith=Майстер мечів
+description.villager.profession.wa.teaMaster=Чайний майстер
+description.villager.profession.wa.priest=Священник
+description.villager.profession.rftools.rftoolsvillager=Інженер RFTools
+description.villager.profession.forbidden.heretic=Єретик
+description.villager.profession.agricraft.villager=Фермер AgriCraft
+
+# Конфігурація форматування чисел
+gtnhlib.config.number_formatting.numberFormatLocale=Локаль форматування чисел
+gtnhlib.config.number_formatting.numberFormatLocale.tooltip=Оберіть локаль для форматування чисел. «Системна за замовчуванням» використовує формат мови системи.
+# Оновлювач пакетів ресурсів
+# Сповіщення про оновлення пакетів ресурсів
+gtnhlib.chat.rpupdater.update_available=§3Доступне нове оновлення для §f%s: v%s §7(у вас v%s)§3.
+gtnhlib.chat.rpupdater.click_here=§6Натисніть сюди
+gtnhlib.chat.rpupdater.open_release= §3, щоб відкрити сторінку релізу.
+gtnhlib.chat.rpupdater.line_mismatch=§f%s §3призначений для GTNH §f%s§3, але ви граєте на §fGTNH %s§3.
+gtnhlib.chat.rpupdater.checking=§3Перевірка оновлень пакетів ресурсів...
+gtnhlib.chat.rpupdater.no_updates=§3Оновлень для активних пакетів ресурсів не знайдено.
+gtnhlib.chat.rpupdater.already_running=§4Перевірка оновлень вже триває.
+gtnhlib.chat.rpupdater.cooldown=§4Перевірку оновлень призупинено через нещодавній збій. Спробуйте пізніше або скористайтеся §f%s§4.
+gtnhlib.chat.rpupdater.disabled=§4Перевірку оновлень пакетів ресурсів вимкнено у конфігурації. Увімкніть її в §fконфігурації GTNH Lib§4 або запустіть з аргументом §f%s§4.
+gtnhlib.chat.rpupdater.manual_cooldown=§4Будь ласка, зачекайте трохи перед повторним виконанням цієї команди.
+gtnhlib.chat.rpupdater.commands=§2Команди оновлювача пакетів ресурсів:
+gtnhlib.chat.rpupdater.list.header=§2Активні пакети ресурсів (§f%s§2):
+gtnhlib.chat.rpupdater.list.item.updater=§3%s §2(оновлювач: §7%s v%s, %s§2)
+gtnhlib.chat.rpupdater.list.item.none=%s §4(без оновлювача)
+gtnhlib.chat.rpupdater.status.header=§2Статус оновлювача пакетів ресурсів:
+gtnhlib.chat.rpupdater.status.running=Виконується: §7%s
+gtnhlib.chat.rpupdater.status.last_check=Остання перевірка: §7%s
+gtnhlib.chat.rpupdater.status.never=§7ніколи
+gtnhlib.chat.rpupdater.status.cooldown_failure=Призупинення через збій: §7%s
+gtnhlib.chat.rpupdater.status.cooldown_manual=Ручне призупинення: §7%s
+gtnhlib.chat.rpupdater.info.usage=Використання: §7%s
+gtnhlib.chat.rpupdater.info.not_found=Жоден активний пакет ресурсів не відповідає §7%s.
+gtnhlib.chat.rpupdater.info.ambiguous=Кілька пакетів ресурсів відповідають §7%s§f (§7%s§f). Уточніть запит.
+gtnhlib.chat.rpupdater.info.header=§2Інформація про пакет ресурсів §3%s§2:
+gtnhlib.chat.rpupdater.info.no_updater=Для цього пакета ресурсів не знайдено метаданих оновлювача.
+gtnhlib.chat.rpupdater.info.updater_name=Назва оновлювача: §7%s
+gtnhlib.chat.rpupdater.info.version=Версія: §7%s (GTNH %s)
+gtnhlib.chat.rpupdater.info.source=Джерело: §7%s/%s
+
+# Команди GTNHTeams
+gtnhlib.chat.teams.error.name_in_use=Ця назва команди вже зайнята або недійсна.
+gtnhlib.chat.teams.error.not_in_team=Ви не перебуваєте в команді.
+gtnhlib.chat.teams.error.not_online=Гравець "%s" не в мережі.
+gtnhlib.chat.teams.error.no_invite=У вас немає очікуваних запрошень до команди.
+gtnhlib.chat.teams.error.team_not_found=Команди "%s" не існує.
+gtnhlib.chat.teams.error.no_invite_specific=Вас не запрошували до команди "%s".
+gtnhlib.chat.teams.error.disambiguate_invite=Вас запросили до кількох команд. Використайте %s accept <Назва команди> або %1$s deny <Назва команди>.
+gtnhlib.chat.teams.error.other_not_in_team=%s не перебуває у вашій команді.
+gtnhlib.chat.teams.error.invite_teammate=%s вже у вашій команді.
+gtnhlib.chat.teams.error.invite_self=Ви не можете запросити самого себе.
+gtnhlib.chat.teams.error.not_owner_rename=Лише власники команди можуть змінювати її назву.
+gtnhlib.chat.teams.error.not_owner_promote=Лише власники команди можуть підвищувати учасників.
+gtnhlib.chat.teams.error.not_owner_demote=Лише власники команди можуть понижувати учасників.
+gtnhlib.chat.teams.error.kick_not_allowed=Ви можете виганяти гравців лише як власник або якщо вони нижчі за вас за рангом.
+gtnhlib.chat.teams.error.cannot_kick_self=Ви не можете вигнати самого себе (у грі).
+gtnhlib.chat.teams.error.not_owner_merge_request=Лише власники команди можуть надсилати або скасовувати запити на об’єднання.
+gtnhlib.chat.teams.error.not_owner_merge_response=Лише власники команди можуть приймати або відхиляти запити на об’єднання.
+gtnhlib.chat.teams.error.not_owner_disband=Лише власники команди можуть розформувати свою команду.
+gtnhlib.chat.teams.error.not_officer_invite=Лише власники або офіцери команди можуть запрошувати гравців.
+gtnhlib.chat.teams.error.merge_self=Ваша команда не може об’єднатися сама з собою.
+gtnhlib.chat.teams.error.merge_already_requested=Ваша команда вже має очікуваний запит на об’єднання з %s.
+gtnhlib.chat.teams.error.no_such_merge_request=Запит на об’єднання від вашої команди до %s не знайдено.
+gtnhlib.chat.teams.error.no_merge_request=У вашої команди немає очікуваних запитів на об’єднання.
+gtnhlib.chat.teams.error.disambiguate_merge=У вашої команди є кілька очікуваних запитів на об’єднання. Використайте %s merge accept <Назва команди> або %1$s merge deny <Назва команди>.
+gtnhlib.chat.teams.error.no_merge_request_specific=Ваша команда не отримувала запиту на об’єднання від "%s".
+gtnhlib.chat.teams.error.last_member_leave=Ви не можете покинути команду, якщо ви її єдиний учасник.
+gtnhlib.chat.teams.error.last_owner_leave=Ви не можете покинути команду як останній власник, поки в ній є інші учасники. Спочатку підвищте іншого учасника.
+gtnhlib.chat.teams.error.last_owner_demote=Ви не можете понизити себе, якщо ви єдиний власник своєї команди.
+gtnhlib.chat.teams.error.last_owner_disband=Ви не можете розформувати команду, якщо ви її єдиний учасник.
+gtnhlib.chat.teams.error.demote_member=%s вже має найнижчий ранг (учасник).
+gtnhlib.chat.teams.error.promote_owner=%s вже є власником.
+gtnhlib.chat.teams.error.not_player=Цю команду може використовувати лише гравець.
+gtnhlib.chat.teams.message.usage=Команди %s: help, gui, info, rename, invite, accept, deny, leave, promote, demote, kick, disband, merge