diff --git a/.gitignore b/.gitignore index 84269ca..b075310 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ run # Files from Forge MDK forge*changelog.txt + +libs/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0a354fd --- /dev/null +++ b/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2024 Fork Genesis + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md deleted file mode 100644 index 540f7d4..0000000 --- a/LICENSE.md +++ /dev/null @@ -1,7 +0,0 @@ -Copyright © 2024 - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 9e20d5a..022f3e2 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,9 @@ -# Minecraft Client Bot -Мод на Forge 1.20.1 - -## Пример сервера -Имплементация многопоточного сервера на Python для работы с этим модом приведена в [этом файле](server.py) +# Fork's Minecraft Botting Framework +Мод на Minecraft для версии 1.20.1, на движке Forge версии 47.3.0 и выше ## Самостоятельная сборка мода -1. Установите Git и JDK 17. Убедитесь, что `git` и `java` выдают желаемый результат. -2. Откройте в терминале папку, где желаете создать папку проекта, и введите -```bash -git clone https://github.com/VasyaProgrammist/Minecraft-Client-Bot.git -``` -3. Перейдите в эту папку в терминале и введите `./gradlew build` (на Linux) или `gradlew.bat build` (на Windows). В папке `build/libs` лежит собранный мод. \ No newline at end of file +1. Установите [Git](https://git-scm.com/downloads) и [JDK 17](https://adoptium.net/temurin/releases/?version=17&package=jdk) +2. Откройте терминал и убедитесь, что команды `git` и `java` не выдают ошибку +2. Откройте в терминале папку, где желаете создать папку проекта, и введите `git clone https://github.com/vpgel/fmbf.git -b forge-1.20.1` +3. Перейдите в эту папку в терминале +4. Введите `./gradlew build` (на Linux) или `gradlew build` (на Windows). В папке `build/libs` лежит собранный мод - тот, чьё имя кончается на `-all`. \ No newline at end of file diff --git a/TODO.md b/TODO.md index e69de29..e0b7904 100644 --- a/TODO.md +++ b/TODO.md @@ -0,0 +1 @@ +- Поддержка API Barione \ No newline at end of file diff --git a/build.gradle b/build.gradle index 6afece0..fc5ea48 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ base { } java.toolchain.languageVersion = JavaLanguageVersion.of(17) -//jarJar.enable() +jarJar.enable() println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" minecraft { @@ -118,9 +118,9 @@ repositories { // If you have mod jar dependencies in ./libs, you can declare them as a repository like so. // See https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:flat_dir_resolver - // flatDir { - // dir 'libs' - // } + flatDir { + dir 'libs' + } } dependencies { @@ -141,12 +141,15 @@ dependencies { // This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar // The group id is ignored when searching -- in this case, it is "blank" // implementation fg.deobf("blank:coolmod-${mc_version}:${coolmod_version}") - /*jarJar(group: 'org.glassfish', name: 'javax.json', version: '[1.0,1.0.5)') { - // Includes examplelib 2.8.0 + + jarJar(group: 'org.glassfish', name: 'javax.json', version: '[1.0,1.0.5)') { jarJar.pin(it, '1.0.4') } - minecraftLibrary 'org.glassfish:javax.json:1.0.4' -*/ + minecraftLibrary fg.deobf('org.glassfish:javax.json:1.0.4') + + // TODO + //implementation fg.deobf("blank:baritone-api-1.20.1:1.10.1") + // For more info: // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html // http://www.gradle.org/docs/current/userguide/dependency_management.html @@ -162,7 +165,8 @@ tasks.named('processResources', ProcessResources).configure { forge_version: forge_version, forge_version_range: forge_version_range, loader_version_range: loader_version_range, mod_id: mod_id, mod_name: mod_name, mod_license: mod_license, mod_version: mod_version, - mod_authors: mod_authors, mod_description: mod_description, + mod_authors: mod_authors, mod_description: mod_description, mod_issue_tracker: mod_issue_tracker, + mod_url: mod_url ] inputs.properties replaceProperties diff --git a/gradle.properties b/gradle.properties index 01efa44..f6515b5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,8 +11,10 @@ mapping_version=2023.09.03-1.20.1 mod_id=fmbf mod_name=Fork's Minecraft Botting Framework -mod_license=All Rights Reserved -mod_version=0.2.1 +mod_license=MIT +mod_version=0.3 mod_group_id=io.github.vpgel.fmbf -mod_authors=ForkGenesis -mod_description=Socket-driven mod for controlling player via any language you desire. (Presumably Python) \ No newline at end of file +mod_authors=ForkGenesis, GLaDOS23 +mod_description=Socket-driven mod for controlling player via any language you desire. (Presumably Python) +mod_issue_tracker=https://github.com/vpgel/FMBF/issues +mod_url=https://github.com/vpgel/FMBF/ \ No newline at end of file diff --git a/src/main/java/io/github/vpgel/fmbf/Config.java b/src/main/java/io/github/vpgel/fmbf/Config.java index c778e80..98c3be5 100644 --- a/src/main/java/io/github/vpgel/fmbf/Config.java +++ b/src/main/java/io/github/vpgel/fmbf/Config.java @@ -6,7 +6,7 @@ import net.minecraftforge.fml.event.config.ModConfigEvent; /** - * Конфиг мода: хост (127.0.0.1 по умолчанию) и порт (2323 по умолчанию) + * Конфиг мода: хост (127.0.0.1 по умолчанию), порт (2323 по умолчанию) и режим дебага (true по умолчанию). */ @Mod.EventBusSubscriber(modid=FMBF.modid, bus=Mod.EventBusSubscriber.Bus.MOD) public class Config { @@ -20,14 +20,20 @@ public class Config { .comment("Port for the socket server") .defineInRange("port", 2323, 0, 65535); + private static final ForgeConfigSpec.BooleanValue DEBUG = configBuilder + .comment("Whether enable additional messages from the mod's internal server") + .define("debug", true); + static final ForgeConfigSpec SPEC = configBuilder.build(); public static String ip; public static int port; + public static boolean debug; @SubscribeEvent static void onLoad(final ModConfigEvent event) { ip = IP.get(); port = PORT.get(); + debug = DEBUG.get(); } } diff --git a/src/main/java/io/github/vpgel/fmbf/Session.java b/src/main/java/io/github/vpgel/fmbf/Session.java index 9cc18f4..27a489e 100644 --- a/src/main/java/io/github/vpgel/fmbf/Session.java +++ b/src/main/java/io/github/vpgel/fmbf/Session.java @@ -12,251 +12,360 @@ import javax.json.JsonArrayBuilder; import javax.json.JsonObjectBuilder; +/*import baritone.api.BaritoneAPI; +import baritone.api.pathing.goals.Goal; +import baritone.api.pathing.goals.GoalGetToBlock; +import net.minecraft.ChatFormatting;*/ import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; -import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.MoverType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.FluidState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; +import net.minecraftforge.registries.ForgeRegistries; /** * Разновидность {@link Thread}, управляющая сокет-соединением между клиентской инстанцией Minecraft и сервером. + * Работа с классом вот так выглядит: + *
 {@code
+ * Session session = new Session(); session.start();
+ * } 
*/ public class Session extends Thread { + /** Сетевой сокет - обличие соединения между Minecraft и Python. */ private Socket connection; + /** Поток получения данных из сервера Python в клиент Minecraft. */ private BufferedReader in; - private BufferedWriter out; - //public FMBF mod; + /** Поток отправки данных из клиента Minecraft в сервер Python. */ + private BufferedWriter out; private String request, response; - private boolean ready; - public LocalPlayer player() { + /** Сам клиент Minecraft. */ + private Minecraft minecraft = Minecraft.getInstance(); + + /** Эта функция возвращает объект игрока, к которому привязана текущая инстанция Minecraft. */ + private LocalPlayer player() { return FMBF.instance.player; } - public boolean isReady() { - this.ready = !this.ready; - return !this.ready; - } - public String getResponse() { - return this.response; - } - + + /** - * Стадия 1: инициализация + * Инициализирует разновидность {@link Thread}, т.е. отдельный поток, управляющий сокет-соединением между клиентской инстанцией Minecraft и сервером. Эта функция инициализирует поток, соединение и открывает порт сервера на прослушивание и на чтение. + *

+ * Чтобы запустить поток, выполните метод {@code start()} созданного объекта. */ public Session() throws UnknownHostException, IOException { connection = new Socket(Config.ip, Config.port); in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-16BE")); out = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-16BE")); FMBF.logger.info(String.format("Connected to %s:%d", Config.ip, Config.port)); - ready = false; } /** - * Стадия 2: исполнение и стадия 3: завершение + * Отправляет строку в сервер Python. + * @param data - строка на отправку + */ + private void sendResponse(String data) throws IOException { + out.write(data.length()); // Отправка длины сообщения + out.flush(); + out.write(data); // Отправка самого сообщения + out.flush(); + } + + /** + * Жизнь потока - всё, что в нём происходит. */ @Override public void run() { try { + // Хз зачем задержка перед началом работы, потом удалю, наверно. Thread.sleep(1000); - request = Json.createObjectBuilder().add("name", player().getName().getString()).build().toString(); + // Отправка первых данных - никнейма игрока. Это обязательно, так как сервер ожидает именно получить строку вида {"name":""}, где - сам никнейм. + String name = Json.createObjectBuilder().add("name", player().getName().getString()).build().toString(); + sendResponse(name); - // Отправить первые данные - out.write(request.length());// длинна сообщения - out.flush(); - out.write(request);//само сообщение - out.flush(); - System.out.println(String.format("Sending data to server: %s, with the size: %d characters", request, request.length()));// просто принт + if (Config.debug) + FMBF.logger.debug(String.format("Sending data to server: %s, with the size: %d characters", name, name.length())); // Просто принт. - int len = in.read();// читаем ответ (длинну) + /** Длина запроса. */ + int len = in.read(); + + // Это главный цикл работы программы - цикл запроса-ответа. + // Он бесконечно пытается получить с сервера Python запрос, + // потом формирует в зависимости от него ответ, + // потом отправляет его. - // Пока поток не попросят прерваться, он выполняет следующие 4 действия на повторе: + // Он прервётся, если а) игрок выйдет из мира, б) закроется соединение с сервером Python. while (!this.isInterrupted() && len != -1) { - // Получить команду - char[] responseBuffer = new char[len];// создаём массив - in.read(responseBuffer, 0, len); // читаем и записываем ответ в массив - response = String.valueOf(responseBuffer);// перевод массива в строку response (нвдо) - System.out.println(String.format("Received a response from server: %s, with the size: %d characters", response, len)); - // Выполнить действия, связанные с командой - this.ready = !this.ready;// хз лол - //нужно действие,например походить + // Получение запроса, в трёх частях: + char[] requestBuffer = new char[len]; // Создание массива для запроса. + in.read(requestBuffer, 0, len); // Чтение и запись запроса в массив. + request = String.valueOf(requestBuffer); // Конвертация массива в строку. - if (Integer.valueOf(response) == 1) { - request = get_playerLook(); - //request = getSurroundingData_Block(1);// функция получения данных от майна - } - - /* - // Отправить данные - try { - request = getSurroundingData();// функция получения данных от майна - } catch (NullPointerException e) { - Thread.sleep(3000); - request = getSurroundingData(); - } - - */ - out.write(request.length());//аналогично отправляем данные на сервак - out.flush(); - out.write(request); - out.flush(); - System.out.println(String.format("Sending data to server: %s, with the size: %d characters", request, request.length())); - - len = in.read();// повторяем цикл заново + if (Config.debug) + FMBF.logger.debug(String.format("Received a request from server: %s, with the size: %d characters", request, len)); + + // На этом этапе в переменной request находится запрос. В зависимости от него формируется ответ в переменной response. + response = switch (request) { + case "спи" -> { + yield idle(); + } + case "какие блоки рядом" -> { + yield getNearestBlocks(4); + } + case "какие сущности рядом" -> { + yield getNearestEntities(5); + } + case "на что смотришь" -> { + yield getWhatImLookingAt(50.0D, true); + } + case "где ты" -> { + yield getPlayerPos(); + } + case "куда смотришь" -> { + yield getPlayerDirection(); + } + default -> { + yield defaultData(request); + } + }; + + // Аналогично, отправляем данные на сервак. + sendResponse(response); + if (Config.debug) + FMBF.logger.debug(String.format("Sending data to server: %s, with the size: %d characters", response, response.length())); + + len = in.read(); // Повторяем цикл заново. } + // Эта часть происходит при нормальном завершении работы сервера. FMBF.logger.info("Aborting connection"); connection.close(); + + // А дальше - обработка ошибок, которые могут выйти при работе мода. } catch (IOException e) { - // Сервер Питона неожиданно обрывает соединение + // Эта ошибка возникает при обрыве соединения. Решение? Просто завершить работу этой сессии. + // Перезапустить сессию можно, просто перезайдя на мир/сервер. this.interrupt(); } catch (InterruptedException e) { + // Та ж фигня, как и с предыдущей ошибкой. this.interrupt(); } + } /** - * Получение данных с мира + * Пустая команда + * @return */ - public String getSurroundingData_Block(int xi) { + private String idle() { + JsonObjectBuilder data = Json.createObjectBuilder(); + data.add("ctx","спи"); + data.add("code", 0); + return data.build().toString(); + } - // Этот JSON-объект - данные об окружающем мире и состоянии бота, которые сконвертируются в String в конце функции. + /** + * Получение блоков вокруг игрока + * + * @param r - кубический радиус получения блоков, т.е. от точки (-r, -r, -r) до точки (r, r, r) + */ + private String getNearestBlocks(int r) { + + // Это JSON-объект - словарь вида "ключ-значение", который можно сконвертировать в строку. JsonObjectBuilder data = Json.createObjectBuilder(); + // data == {} + + // Это JSON-массив - массив значений, который можно добавить как значение в JSON-объект. JsonArrayBuilder blocksData = Json.createArrayBuilder(); + // blocksData = [] - // Здесь получить данные о рядом находящихся блоках и сущностях и записать их в data + // playerPos - координаты блока, на котором стоит игрок (или над которым летает). BlockPos playerPos = player().getOnPos(); - for (int x = -xi; x <= xi; x++) { - for (int y = -xi; y <= xi; y++) { - for (int z = -xi; z <= xi; z++) { - JsonObjectBuilder block = Json.createObjectBuilder(); + for (int x = -r; x <= r; x++) { + for (int y = -r; y <= r; y++) { + for (int z = -r; z <= r; z++) { + // Этот словарь тоже создаётся пустым: {} + JsonObjectBuilder block = Json.createObjectBuilder(); + + // Далее мы получаем позицию какого-то блока. BlockPos pos = playerPos.offset(x, y, z); + // Его название. String id = player().level().getBlockState(pos).getBlock().getDescriptionId(); - //data += (pos.toString()+":"+blockState.getBlock().getDescriptionId()+"\n"); + + // И добавляем их как данные в словарь block. block.add("id", id).add("x", pos.getX()).add("y", pos.getY()).add("z", pos.getZ()); + // block == {"id": "minecraft:stone", "x": 10, "y": 60, "z": 10} + blocksData.add(block.build()); + // Этот массив хранит все словари block, что были созданы в циклах for. + // blocksData == [block, block2, ...] } } } data.add("blocks", blocksData.build()); - + // Теперь data выглядит так: + // data == {"blocks": blocksData} + // То есть, + // data == {"blocks": [block, block2, ...]} + // То есть, + // data == {"blocks": [{"id": "minecraft:stone", "x": 10, "y": 60, "z": 10}, + // {"id": "minecraft:stone", "x": 11, "y": 60, "z": 10}, + // ...]} + + data.add("ctx","какие блоки рядом"); + data.add("code", 0); return data.build().toString(); } - // получаем координаты - public String get_playerPos() { - // Этот JSON-объект - данные об окружающем мире и состоянии бота, которые сконвертируются в String в конце функции. - JsonObjectBuilder blocksData = Json.createObjectBuilder(); - - BlockPos playerPos = player().getOnPos();// получаем позицию игрока - blocksData.add("x", playerPos.getX()).add("y", playerPos.getY()).add("z", playerPos.getZ()); - return blocksData.build().toString(); - } + /** + * Получение сущностей вокруг игрока + * + * @param r - параллелепипедный радиус получения сущностей, т.е. от точки (-r, -r, -r) до точки (r, r+2, r) + */ + private String getNearestEntities(int r) { + JsonObjectBuilder data = Json.createObjectBuilder(); + // data == {} + JsonArrayBuilder entitiesData = Json.createArrayBuilder(); + // entitiesData == [] - // получаем направление взгляда - public String get_playerDirection() { - // Этот JSON-объект - данные об окружающем мире и состоянии бота, которые сконвертируются в String в конце функции. - JsonObjectBuilder blocksData = Json.createObjectBuilder(); + for (Entity entity: player().level().getEntitiesOfClass(Entity.class, player().getBoundingBox().expandTowards(r, r, r))) { + JsonObjectBuilder entityData = Json.createObjectBuilder(); + // entityData == {} + /* Координаты сущности. */ + Vec3 pos = entity.getPosition(0); + entityData.add("id", entity.getName().getString()).add("x", pos.x).add("y", pos.y).add("z", pos.z); + // entityData == {"id": "minecraft:creeper", "x": 10, "y": 60, "z": 10} - float playerPosX = player().getViewXRot(0);// получаем направление взгляда - float playerPosY = player().getViewYRot(0); - blocksData.add("x", playerPosX).add("y", playerPosY); - return blocksData.build().toString(); + entitiesData.add(entityData.build()); + // entitiesData == [entityData, entityData2, ...] + } + data.add("entities", entitiesData.build()); + // Теперь data выглядит так: + // data == {"entitites": entitiesData} + // То есть, + // data == {"entitites": [entityData, entityData2, ...]} + // То есть, + // data == {"entitites": [{"id": "minecraft:creeper", "x": 10, "y": 60, "z": 10}, + // {"id": "minecraft:creeper", "x": 13, "y": 61, "z": 7}, + // ...]} + + data.add("ctx","какие сущности рядом"); + data.add("code", 0); + return data.build().toString(); } - // получаем блок/энтити по направлению взгляда - public String get_playerLook() { - // Этот JSON-объект - данные об окружающем мире и состоянии бота, которые сконвертируются в String в конце функции. - JsonObjectBuilder blocksData = Json.createObjectBuilder(); + /** + * Получаем блок/жидкость/энтити по направлению взгляда. + * @param distance - максимальное расстояние, на которое игрок может увидеть что-то. Чем выше, тем больше лагов. + * @param enableFluids - + */ + private String getWhatImLookingAt(double distance, boolean enableFluids) { + JsonObjectBuilder data = Json.createObjectBuilder(); - Entity lookat_entity = Minecraft.getInstance().crosshairPickEntity; - HitResult hitResult = Minecraft.getInstance().getCameraEntity().pick(20.0D, 0.0F, false); + // Сущность, на которую смотрит курсор игрока. Важно! Эта переменная равна null, если игрок не смотрит на сущность. + Entity entity = minecraft.crosshairPickEntity; + // Из глаз игрока выходит луч длиной в несколько блоков, а в переменные block и liquid записывается то, во что первым попал этот луч. Может быть жидкостью или блоком. + HitResult block = minecraft.getCameraEntity().pick(distance, 0.0F, false); + HitResult liquid = minecraft.getCameraEntity().pick(distance, 0.0F, true); - if(lookat_entity != null) { - blocksData.add("Object", "entity").add("Type", String.valueOf((Object) BuiltInRegistries.ENTITY_TYPE.getKey(lookat_entity.getType()))) - .add("distance", lookat_entity.distanceTo(player())); - } + // Ну теперь есть четыре варианта событий. + // Первый: мы попали в сущность. + if(entity != null) { + data.add("type", "entity") + .add("id", String.valueOf((Object)ForgeRegistries.ENTITY_TYPES.getKey(entity.getType()))) + .add("distance", entity.distanceTo(player())); - else if (hitResult.getType() == HitResult.Type.BLOCK) { - BlockState lookat_block = Minecraft.getInstance().level.getBlockState(((BlockHitResult) hitResult).getBlockPos()); + // Второй: мы попали в жидкость. Если опция жидкостей выключена, то мы забиваем на это. + } else if (liquid.getType() == HitResult.Type.BLOCK && enableFluids) { + BlockPos blockPos = ((BlockHitResult)liquid).getBlockPos(); - blocksData.add("Object", "block").add("Type", String.valueOf((Object)BuiltInRegistries.BLOCK.getKey(lookat_block.getBlock())) ) - .add("distance",Math.sqrt(player().distanceToSqr(((BlockHitResult)hitResult).getBlockPos().getCenter()))); + FluidState fluidstate = minecraft.level.getFluidState(blockPos); + data.add("type", "fluid") + .add("id", String.valueOf((Object)ForgeRegistries.FLUIDS.getKey(fluidstate.getType()))) + .add("distance",Math.sqrt(player().distanceToSqr(blockPos.getCenter()))); + + // Третий: мы попали в блок. + } else if (block.getType() == HitResult.Type.BLOCK) { + BlockPos blockPos = ((BlockHitResult)liquid).getBlockPos(); + BlockState blockState = minecraft.level.getBlockState(blockPos); + + data.add("type", "block") + .add("id", String.valueOf((Object)ForgeRegistries.BLOCKS.getKey(blockState.getBlock()))) + .add("distance",Math.sqrt(player().distanceToSqr(blockPos.getCenter()))); + + // Четвёртый: мы попали в воздух. + } else { + data.add("object", "air"); } - - else { - blocksData.add("Object", "air"); - } - return blocksData.build().toString(); + data.add("ctx","на что смотришь"); + data.add("code", 0); + return data.build().toString(); } - public String getSurroundingData() { + /** + * Получение координат блока под игроком. + */ + private String getPlayerPos() { + JsonObjectBuilder posData = Json.createObjectBuilder(); - // Этот JSON-объект - данные об окружающем мире и состоянии бота, которые сконвертируются в String в конце функции. - JsonObjectBuilder data = Json.createObjectBuilder(); - JsonArrayBuilder blocksData = Json.createArrayBuilder(); + BlockPos playerPos = player().getOnPos(); // Это и есть координаты блока под игроком. - // Здесь получить данные о рядом находящихся блоках и сущностях и записать их в data - BlockPos playerPos = player().getOnPos(); + posData.add("x", playerPos.getX()).add("y", playerPos.getY()).add("z", playerPos.getZ()); + // posData == {"x": 10, "y": 60, "z": 10} + posData.add("ctx","где ты"); + posData.add("code", 0); + return posData.build().toString(); + } - for (int x = -1; x <= 1; x++) { - for (int y = -1; y <= 1; y++) { - for (int z = -1; z <= 1; z++) { - JsonObjectBuilder block = Json.createObjectBuilder(); - BlockPos pos = playerPos.offset(x, y, z); - String id = player().level().getBlockState(pos).getBlock().getDescriptionId(); - //data += (pos.toString()+":"+blockState.getBlock().getDescriptionId()+"\n"); - block.add("id", id).add("x", pos.getX()).add("y", pos.getY()).add("z", pos.getZ()); - blocksData.add(block.build()); - } - } - } - data.add("blocks", blocksData.build()); + /** + * Получение направления взгляда игрока. + */ + private String getPlayerDirection() { + JsonObjectBuilder directionData = Json.createObjectBuilder(); - JsonArrayBuilder entitiesData = Json.createArrayBuilder(); + float playerPosX = player().getViewXRot(0); // Это и есть направление взгляда. + float playerPosY = player().getViewYRot(0); - for (Entity entity: player().level().getEntitiesOfClass(Entity.class, player().getBoundingBox().inflate(5))) { - Vec3 pos = entity.getPosition(0); - JsonObjectBuilder entityData = Json.createObjectBuilder(); - entityData.add("id", entity.getName().getString()).add("x", pos.x).add("y", pos.y).add("z", pos.z); - entitiesData.add(entityData.build()); - } - data.add("entities", entitiesData.build()); + directionData.add("x", playerPosX).add("y", playerPosY); + // directionData == {"x": 10.23, "y": 23.15} + directionData.add("ctx","куда смотришь"); + directionData.add("code", 0); + return directionData.build().toString(); + } + private String defaultData(String command) { + JsonObjectBuilder data = Json.createObjectBuilder(); + data.add("ctx",command); + data.add("code", 1); return data.build().toString(); } - + + // TODO + /*private String walk(int x, int y, int z) { + player().move(MoverType.PLAYER, player().getEyePosition()); + BaritoneAPI.getProvider().getBaritoneForPlayer(player()).getCustomGoalProcess().setGoal(new GoalGetToBlock(player().getOnPos().offset(x, y, z))); + + JsonObjectBuilder walkData = Json.createObjectBuilder(); + return walkData.build().toString(); + }*/ + /** - * Выполнение команды - * @param message - команда и аргументы + * Отправление сообщения в игровой чат. Эта функция реально тут просто так */ - public void controlPlayer(String message) { - String command = message.split(" ")[0]; - String[] args = new String[0]; - if (message.split(" ").length == 2) { - args = message.split(" ")[1].split(","); - } - switch (command) { - case "walk_forward" -> { - //player().setDeltaMovement(player().getEyePosition()); - player().zza = 1.0F; - } - case "turn_right" -> { - player().turn(Integer.valueOf(args[0]), 0); - } - default -> { - FMBF.logger.error("Unknown command: " + command); - } - } + private String chat(String message) { + JsonObjectBuilder data = Json.createObjectBuilder(); + data.add("ctx","напиши"); + data.add("code", 1); + return data.build().toString(); } } diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index f53e18d..1745a33 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -2,14 +2,13 @@ modLoader="javafml" loaderVersion="${loader_version_range}" license="${mod_license}" -#issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional +issueTrackerURL="${mod_issue_tracker}" [[mods]] modId="${mod_id}" version="${mod_version}" displayName="${mod_name}" -displayURL="https://github.com/VasyaProgrammist/Minecraft-Client-Bot/" -logoFile="mcclientbot.png" -#credits="" +displayURL="${mod_url}" +logoFile="fmbf.png" authors="${mod_authors}" description='''${mod_description}''' diff --git a/src/main/resources/mcclientbot.png b/src/main/resources/fmbf.png similarity index 100% rename from src/main/resources/mcclientbot.png rename to src/main/resources/fmbf.png