From 60fd7f0891393e268273a78ffc9d551277032be7 Mon Sep 17 00:00:00 2001 From: skippyall <> Date: Sat, 13 Apr 2024 22:04:49 +0200 Subject: [PATCH] lots of code --- .gitignore | 118 ++++ LICENSE | 21 + build.gradle | 91 +++ gradle.properties | 20 + gradle/wrapper/gradle-wrapper.properties | 1 + .../skippyall/minions/MinionInventory.java | 46 ++ .../github/skippyall/minions/MinionItem.java | 56 ++ .../io/github/skippyall/minions/Minions.java | 27 + .../minions/client/MinionsClient.java | 16 + .../fakeplayer/ClientConnectionInterface.java | 7 + .../fakeplayer/EntityPlayerActionPack.java | 626 ++++++++++++++++++ .../fakeplayer/FakeClientConnection.java | 37 ++ .../minions/fakeplayer/MinionFakePlayer.java | 201 ++++++ .../fakeplayer/NetHandlerPlayServerFake.java | 46 ++ .../fakeplayer/ServerPlayerInterface.java | 8 + .../skippyall/minions/fakeplayer/Tracer.java | 90 +++ .../minions/mixins/ConnectionMixin.java | 14 + .../minions/mixins/PlayerListMixin.java | 56 ++ .../minions/mixins/ServerPlayerMixin.java | 37 ++ .../networking/ClientToServerNetworking.java | 41 ++ .../minions/networking/VersionChecker.java | 22 + .../minions/program/block/CodeBlock.java | 12 + .../minions/program/block/CodeBlocks.java | 5 + .../minions/program/block/ForwardBlock.java | 19 + .../minions/program/module/Modul.java | 15 + .../minions/program/module/Modules.java | 5 + .../minions/program/module/MoveModul.java | 30 + .../program/variables/IntegerType.java | 4 + .../minions/program/variables/Type.java | 4 + .../minions/program/variables/Types.java | 5 + .../minions/server/MinionsServer.java | 22 + settings.gradle | 9 + .../io/github/skippyall/minions/Minions.java | 21 + .../minions/client/MinionsClient.java | 16 + .../fakeplayer/ClientConnectionInterface.java | 7 + .../fakeplayer/EntityPlayerActionPack.java | 625 +++++++++++++++++ .../fakeplayer/FakeClientConnection.java | 37 ++ .../minions/fakeplayer/MinionFakePlayer.java | 277 ++++++++ .../fakeplayer/NetHandlerPlayServerFake.java | 45 ++ .../fakeplayer/ServerPlayerInterface.java | 8 + .../skippyall/minions/fakeplayer/Tracer.java | 89 +++ .../minions/minion/ImplementedInventory.java | 132 ++++ .../minions/minion/MinionInventory.java | 62 ++ .../skippyall/minions/minion/MinionItem.java | 50 ++ .../minions/minion/ModuleInventory.java | 42 ++ .../minions/mixins/ConnectionMixin.java | 14 + .../minions/mixins/PlayerListMixin.java | 53 ++ .../minions/mixins/ServerPlayerMixin.java | 37 ++ .../networking/ClientToServerNetworking.java | 40 ++ .../minions/networking/VersionChecker.java | 21 + .../minions/program/MinionRuntime.java | 26 + .../minions/program/block/CodeBlock.java | 23 + .../minions/program/block/CodeBlocks.java | 5 + .../block/CodeContainingCodeBlock.java | 15 + .../minions/program/block/GoBlock.java | 25 + .../minions/program/block/UseBlock.java | 21 + .../minions/program/module/Module.java | 22 + .../minions/program/module/Modules.java | 5 + .../minions/program/module/MoveModule.java | 29 + .../minions/program/statement/Arg.java | 8 + .../minions/program/statement/Statement.java | 15 + .../program/statement/StatementList.java | 37 ++ .../minions/program/variables/FloatType.java | 4 + .../program/variables/IntegerType.java | 4 + .../minions/program/variables/Type.java | 4 + .../minions/program/variables/Types.java | 7 + .../minions/program/variables/Variable.java | 24 + .../minions/server/MinionsServer.java | 22 + src/main/resources/TODO.txt | 35 + src/main/resources/fabric.mod.json | 33 + src/main/resources/minions.mixins.json | 16 + 71 files changed, 3667 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 oldSrc/io/github/skippyall/minions/MinionInventory.java create mode 100644 oldSrc/io/github/skippyall/minions/MinionItem.java create mode 100644 oldSrc/io/github/skippyall/minions/Minions.java create mode 100644 oldSrc/io/github/skippyall/minions/client/MinionsClient.java create mode 100644 oldSrc/io/github/skippyall/minions/fakeplayer/ClientConnectionInterface.java create mode 100644 oldSrc/io/github/skippyall/minions/fakeplayer/EntityPlayerActionPack.java create mode 100644 oldSrc/io/github/skippyall/minions/fakeplayer/FakeClientConnection.java create mode 100644 oldSrc/io/github/skippyall/minions/fakeplayer/MinionFakePlayer.java create mode 100644 oldSrc/io/github/skippyall/minions/fakeplayer/NetHandlerPlayServerFake.java create mode 100644 oldSrc/io/github/skippyall/minions/fakeplayer/ServerPlayerInterface.java create mode 100644 oldSrc/io/github/skippyall/minions/fakeplayer/Tracer.java create mode 100644 oldSrc/io/github/skippyall/minions/mixins/ConnectionMixin.java create mode 100644 oldSrc/io/github/skippyall/minions/mixins/PlayerListMixin.java create mode 100644 oldSrc/io/github/skippyall/minions/mixins/ServerPlayerMixin.java create mode 100644 oldSrc/io/github/skippyall/minions/networking/ClientToServerNetworking.java create mode 100644 oldSrc/io/github/skippyall/minions/networking/VersionChecker.java create mode 100644 oldSrc/io/github/skippyall/minions/program/block/CodeBlock.java create mode 100644 oldSrc/io/github/skippyall/minions/program/block/CodeBlocks.java create mode 100644 oldSrc/io/github/skippyall/minions/program/block/ForwardBlock.java create mode 100644 oldSrc/io/github/skippyall/minions/program/module/Modul.java create mode 100644 oldSrc/io/github/skippyall/minions/program/module/Modules.java create mode 100644 oldSrc/io/github/skippyall/minions/program/module/MoveModul.java create mode 100644 oldSrc/io/github/skippyall/minions/program/variables/IntegerType.java create mode 100644 oldSrc/io/github/skippyall/minions/program/variables/Type.java create mode 100644 oldSrc/io/github/skippyall/minions/program/variables/Types.java create mode 100644 oldSrc/io/github/skippyall/minions/server/MinionsServer.java create mode 100644 settings.gradle create mode 100644 src/main/java/io/github/skippyall/minions/Minions.java create mode 100644 src/main/java/io/github/skippyall/minions/client/MinionsClient.java create mode 100644 src/main/java/io/github/skippyall/minions/fakeplayer/ClientConnectionInterface.java create mode 100644 src/main/java/io/github/skippyall/minions/fakeplayer/EntityPlayerActionPack.java create mode 100644 src/main/java/io/github/skippyall/minions/fakeplayer/FakeClientConnection.java create mode 100644 src/main/java/io/github/skippyall/minions/fakeplayer/MinionFakePlayer.java create mode 100644 src/main/java/io/github/skippyall/minions/fakeplayer/NetHandlerPlayServerFake.java create mode 100644 src/main/java/io/github/skippyall/minions/fakeplayer/ServerPlayerInterface.java create mode 100644 src/main/java/io/github/skippyall/minions/fakeplayer/Tracer.java create mode 100644 src/main/java/io/github/skippyall/minions/minion/ImplementedInventory.java create mode 100644 src/main/java/io/github/skippyall/minions/minion/MinionInventory.java create mode 100644 src/main/java/io/github/skippyall/minions/minion/MinionItem.java create mode 100644 src/main/java/io/github/skippyall/minions/minion/ModuleInventory.java create mode 100644 src/main/java/io/github/skippyall/minions/mixins/ConnectionMixin.java create mode 100644 src/main/java/io/github/skippyall/minions/mixins/PlayerListMixin.java create mode 100644 src/main/java/io/github/skippyall/minions/mixins/ServerPlayerMixin.java create mode 100644 src/main/java/io/github/skippyall/minions/networking/ClientToServerNetworking.java create mode 100644 src/main/java/io/github/skippyall/minions/networking/VersionChecker.java create mode 100644 src/main/java/io/github/skippyall/minions/program/MinionRuntime.java create mode 100644 src/main/java/io/github/skippyall/minions/program/block/CodeBlock.java create mode 100644 src/main/java/io/github/skippyall/minions/program/block/CodeBlocks.java create mode 100644 src/main/java/io/github/skippyall/minions/program/block/CodeContainingCodeBlock.java create mode 100644 src/main/java/io/github/skippyall/minions/program/block/GoBlock.java create mode 100644 src/main/java/io/github/skippyall/minions/program/block/UseBlock.java create mode 100644 src/main/java/io/github/skippyall/minions/program/module/Module.java create mode 100644 src/main/java/io/github/skippyall/minions/program/module/Modules.java create mode 100644 src/main/java/io/github/skippyall/minions/program/module/MoveModule.java create mode 100644 src/main/java/io/github/skippyall/minions/program/statement/Arg.java create mode 100644 src/main/java/io/github/skippyall/minions/program/statement/Statement.java create mode 100644 src/main/java/io/github/skippyall/minions/program/statement/StatementList.java create mode 100644 src/main/java/io/github/skippyall/minions/program/variables/FloatType.java create mode 100644 src/main/java/io/github/skippyall/minions/program/variables/IntegerType.java create mode 100644 src/main/java/io/github/skippyall/minions/program/variables/Type.java create mode 100644 src/main/java/io/github/skippyall/minions/program/variables/Types.java create mode 100644 src/main/java/io/github/skippyall/minions/program/variables/Variable.java create mode 100644 src/main/java/io/github/skippyall/minions/server/MinionsServer.java create mode 100644 src/main/resources/TODO.txt create mode 100644 src/main/resources/fabric.mod.json create mode 100644 src/main/resources/minions.mixins.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c37caf --- /dev/null +++ b/.gitignore @@ -0,0 +1,118 @@ +# User-specific stuff +.idea/ + +*.iml +*.ipr +*.iws + +# IntelliJ +out/ +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Cache of project +.gradletasknamecache + +**/build/ + +# Common working directory +run/ + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c986429 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 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. diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..08b597b --- /dev/null +++ b/build.gradle @@ -0,0 +1,91 @@ +plugins { + id 'fabric-loom' version '1.5-SNAPSHOT' + id 'maven-publish' +} + +version = project.mod_version +group = project.maven_group + +base { + archivesName = project.archives_base_name +} + +repositories { + // Add repositories to retrieve artifacts from in here. + // You should only use this when depending on other mods because + // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. + // See https://docs.gradle.org/current/userguide/declaring_repositories.html + // for more information about repositories. + maven { url 'https://maven.nucleoid.xyz' } +} + +dependencies { + // To change the versions see the gradle.properties file + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + + // Fabric API. This is technically optional, but you probably want it anyway. + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + modImplementation include("eu.pb4:polymer-core:${project.polymer_version}") + modImplementation include("eu.pb4:sgui:${project.sgui_version}") +} + +processResources { + inputs.property "version", project.version + inputs.property "minecraft_version", project.minecraft_version + inputs.property "loader_version", project.loader_version + filteringCharset "UTF-8" + + filesMatching("fabric.mod.json") { + expand "version": project.version, + "minecraft_version": project.minecraft_version, + "loader_version": project.loader_version + } +} + +def targetJavaVersion = 17 +tasks.withType(JavaCompile).configureEach { + // ensure that the encoding is set to UTF-8, no matter what the system default is + // this fixes some edge cases with special characters not displaying correctly + // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html + // If Javadoc is generated, this must be specified in that task too. + it.options.encoding = "UTF-8" + if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) { + it.options.release.set(targetJavaVersion) + } +} + +java { + def javaVersion = JavaVersion.toVersion(targetJavaVersion) + if (JavaVersion.current() < javaVersion) { + toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion) + } + // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task + // if it is present. + // If you remove this line, sources will not be generated. + withSourcesJar() +} + +jar { + from("LICENSE") { + rename { "${it}_${project.archivesBaseName}"} + } +} + +// configure the maven publication +publishing { + publications { + mavenJava(MavenPublication) { + from components.java + } + } + + // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. + repositories { + // Add repositories to publish to here. + // Notice: This block does NOT have the same function as the block in the top level. + // The repositories here will be used for publishing your artifact, not for + // retrieving dependencies. + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..ef815f8 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,20 @@ +# Done to increase the memory available to gradle. +org.gradle.jvmargs=-Xmx1G + +# Fabric Properties + # check these on https://modmuss50.me/fabric.html + minecraft_version=1.20.4 + loader_version=0.15.6 + yarn_mappings=1.20.4+build.3 + +# Mod Properties + mod_version = 0.0.1 + maven_group = io.github.skippyall + archives_base_name = Minions + +# Dependencies + # check this on https://modmuss50.me/fabric.html + fabric_version=0.95.4+1.20.4 + + polymer_version=0.7.5+1.20.4 + sgui_version=1.4.1+1.20.4 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..eb1dde3 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip diff --git a/oldSrc/io/github/skippyall/minions/MinionInventory.java b/oldSrc/io/github/skippyall/minions/MinionInventory.java new file mode 100644 index 0000000..5595a3a --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/MinionInventory.java @@ -0,0 +1,46 @@ +package io.github.skippyall.minions; + +import eu.pb4.sgui.api.ClickType; +import eu.pb4.sgui.api.elements.GuiElement; +import eu.pb4.sgui.api.elements.GuiElementBuilder; +import eu.pb4.sgui.api.elements.GuiElementInterface; +import eu.pb4.sgui.api.gui.SimpleGui; +import eu.pb4.sgui.api.gui.SlotGuiInterface; +import io.github.skippyall.minions.fakeplayer.MinionFakePlayer; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +public class MinionInventory { + public static void openInventory(ServerPlayer player, MinionFakePlayer minion) { + + } + + public static void openServerSideInventory(ServerPlayer player, MinionFakePlayer minion) { + SimpleGui gui = new SimpleGui(MenuType.GENERIC_3x3, player, false); + gui.setTitle(Component.literal("Minion")); + gui.setSlot(4, new GuiElementBuilder() + .setItem(Items.REDSTONE) + .setName(Component.literal("Programming")) + .setCallback((i, clickType, clickType1) -> { + openProgrammingInventory(player, minion); + }) + ); + gui.setSlot(3, new GuiElementBuilder() + .setItem(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE) + .setName(Component.literal("Modules and Detectors")) + .setCallback((i, clickType, clickType1) -> { + + }) + ); + gui.open(); + } + + public static void openProgrammingInventory(ServerPlayer player, MinionFakePlayer minion) { + + } + + public static void open +} diff --git a/oldSrc/io/github/skippyall/minions/MinionItem.java b/oldSrc/io/github/skippyall/minions/MinionItem.java new file mode 100644 index 0000000..1952708 --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/MinionItem.java @@ -0,0 +1,56 @@ +package io.github.skippyall.minions; + +import eu.pb4.polymer.core.api.item.PolymerItem; +import eu.pb4.polymer.core.api.item.PolymerItemUtils; +import io.github.skippyall.minions.fakeplayer.MinionFakePlayer; +import net.fabricmc.fabric.api.item.v1.FabricItemSettings; +import net.minecraft.network.chat.ComponentContents; +import net.minecraft.network.chat.contents.PlainTextContents; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import org.jetbrains.annotations.Nullable; + +public class MinionItem extends Item implements PolymerItem { + public MinionItem() { + super(new FabricItemSettings()); + } + + @Override + public Item getPolymerItem(ItemStack itemStack, @Nullable ServerPlayer player) { + return Items.PLAYER_HEAD; + } + + @Override + public ItemStack getPolymerItemStack(ItemStack stack, TooltipFlag flag, ServerPlayer player) { + ItemStack out = PolymerItemUtils.createItemStack(stack, flag, player); + //CompoundTag tag = out.getOrCreateTag(); + //PlayerHeadItem.TAG_SKULL_OWNER; + return out; + } + + /*@Override + public int getPolymerCustomModelData(ItemStack itemStack, @Nullable ServerPlayer player) { + return 10; + }*/ + + public InteractionResult useOn(UseOnContext context) { + System.out.println("Minion spawned "+ context.getItemInHand().getDisplayName()); + ComponentContents contents = context.getItemInHand().getHoverName().getContents(); + String name; + if(contents instanceof PlainTextContents plainContents) { + name = plainContents.text(); + } else { + name = "Minion"; + } + if(!context.getLevel().isClientSide) { + MinionFakePlayer.createMinion(name, (ServerLevel) context.getLevel(), (ServerPlayer) context.getPlayer(), context.getClickedPos().getCenter().add(0,0.5,0), 0, 0); + } + return InteractionResult.SUCCESS; + } +} diff --git a/oldSrc/io/github/skippyall/minions/Minions.java b/oldSrc/io/github/skippyall/minions/Minions.java new file mode 100644 index 0000000..ab563f5 --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/Minions.java @@ -0,0 +1,27 @@ +package io.github.skippyall.minions; + +import eu.pb4.polymer.core.api.entity.PolymerEntityUtils; +import io.github.skippyall.minions.networking.ClientToServerNetworking; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking; +import net.fabricmc.fabric.api.networking.v1.ServerLoginConnectionEvents; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerLoginPacketListenerImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Minions implements ModInitializer { + public static final String MOD_ID = "minions"; + public static final MinionItem MINION_ITEM = Registry.register(BuiltInRegistries.ITEM, new ResourceLocation(MOD_ID, "minion"), new MinionItem()); + + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + @Override + public void onInitialize() { + PolymerEntityUtils.registerType(); + } +} diff --git a/oldSrc/io/github/skippyall/minions/client/MinionsClient.java b/oldSrc/io/github/skippyall/minions/client/MinionsClient.java new file mode 100644 index 0000000..4c8282f --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/client/MinionsClient.java @@ -0,0 +1,16 @@ +package io.github.skippyall.minions.client; + +import io.github.skippyall.minions.networking.ClientToServerNetworking; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationConnectionEvents; +import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents; + +public class MinionsClient implements ClientModInitializer { + /** + * Runs the mod initializer on the client environment. + */ + @Override + public void onInitializeClient() { + ClientConfigurationConnectionEvents.INIT.register(ClientToServerNetworking::onConfigurationInit); + } +} diff --git a/oldSrc/io/github/skippyall/minions/fakeplayer/ClientConnectionInterface.java b/oldSrc/io/github/skippyall/minions/fakeplayer/ClientConnectionInterface.java new file mode 100644 index 0000000..a199f98 --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/fakeplayer/ClientConnectionInterface.java @@ -0,0 +1,7 @@ +package io.github.skippyall.minions.fakeplayer; + +import io.netty.channel.Channel; + +public interface ClientConnectionInterface { + void setChannel(Channel channel); +} diff --git a/oldSrc/io/github/skippyall/minions/fakeplayer/EntityPlayerActionPack.java b/oldSrc/io/github/skippyall/minions/fakeplayer/EntityPlayerActionPack.java new file mode 100644 index 0000000..d4f2762 --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/fakeplayer/EntityPlayerActionPack.java @@ -0,0 +1,626 @@ +package io.github.skippyall.minions.fakeplayer; + + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.minecraft.commands.arguments.EntityAnchorArgument; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.protocol.game.ClientboundSetCarriedItemPacket; +import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.animal.horse.AbstractHorse; +import net.minecraft.world.entity.decoration.ItemFrame; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.vehicle.Boat; +import net.minecraft.world.entity.vehicle.Minecart; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec2; +import net.minecraft.world.phys.Vec3; + +public class EntityPlayerActionPack +{ + private final ServerPlayer player; + + private final Map actions = new EnumMap<>(ActionType.class); + + private BlockPos currentBlock; + private int blockHitDelay; + private boolean isHittingBlock; + private float curBlockDamageMP; + + private boolean sneaking; + private boolean sprinting; + private float forward; + private float strafing; + + private int itemUseCooldown; + + public EntityPlayerActionPack(ServerPlayer playerIn) + { + player = playerIn; + stopAll(); + } + public void copyFrom(EntityPlayerActionPack other) + { + actions.putAll(other.actions); + currentBlock = other.currentBlock; + blockHitDelay = other.blockHitDelay; + isHittingBlock = other.isHittingBlock; + curBlockDamageMP = other.curBlockDamageMP; + + sneaking = other.sneaking; + sprinting = other.sprinting; + forward = other.forward; + strafing = other.strafing; + + itemUseCooldown = other.itemUseCooldown; + } + + public EntityPlayerActionPack start(ActionType type, Action action) + { + Action previous = actions.remove(type); + if (previous != null) type.stop(player, previous); + if (action != null) + { + actions.put(type, action); + type.start(player, action); // noop + } + return this; + } + + public EntityPlayerActionPack setSneaking(boolean doSneak) + { + sneaking = doSneak; + player.setShiftKeyDown(doSneak); + if (sprinting && sneaking) + setSprinting(false); + return this; + } + public EntityPlayerActionPack setSprinting(boolean doSprint) + { + sprinting = doSprint; + player.setSprinting(doSprint); + if (sneaking && sprinting) + setSneaking(false); + return this; + } + + public EntityPlayerActionPack setForward(float value) + { + forward = value; + return this; + } + public EntityPlayerActionPack setStrafing(float value) + { + strafing = value; + return this; + } + public EntityPlayerActionPack look(Direction direction) + { + return switch (direction) + { + case NORTH -> look(180, 0); + case SOUTH -> look(0, 0); + case EAST -> look(-90, 0); + case WEST -> look(90, 0); + case UP -> look(player.getYRot(), -90); + case DOWN -> look(player.getYRot(), 90); + }; + } + public EntityPlayerActionPack look(Vec2 rotation) + { + return look(rotation.x, rotation.y); + } + + public EntityPlayerActionPack look(float yaw, float pitch) + { + player.setYRot(yaw % 360); //setYaw + player.setXRot(Mth.clamp(pitch, -90, 90)); // setPitch + // maybe player.moveTo(player.getX(), player.getY(), player.getZ(), yaw, Mth.clamp(pitch,-90.0F, 90.0F)); + return this; + } + + public EntityPlayerActionPack lookAt(Vec3 position) + { + player.lookAt(EntityAnchorArgument.Anchor.EYES, position); + return this; + } + + public EntityPlayerActionPack turn(float yaw, float pitch) + { + return look(player.getYRot() + yaw, player.getXRot() + pitch); + } + + public EntityPlayerActionPack turn(Vec2 rotation) + { + return turn(rotation.x, rotation.y); + } + + public EntityPlayerActionPack stopMovement() + { + setSneaking(false); + setSprinting(false); + forward = 0.0F; + strafing = 0.0F; + return this; + } + + + public EntityPlayerActionPack stopAll() + { + for (ActionType type : actions.keySet()) type.stop(player, actions.get(type)); + actions.clear(); + return stopMovement(); + } + + public EntityPlayerActionPack mount(boolean onlyRideables) + { + //test what happens + List entities; + if (onlyRideables) + { + entities = player.level().getEntities(player, player.getBoundingBox().inflate(3.0D, 1.0D, 3.0D), + e -> e instanceof Minecart || e instanceof Boat || e instanceof AbstractHorse); + } + else + { + entities = player.level().getEntities(player, player.getBoundingBox().inflate(3.0D, 1.0D, 3.0D)); + } + if (entities.size()==0) + return this; + Entity closest = null; + double distance = Double.POSITIVE_INFINITY; + Entity currentVehicle = player.getVehicle(); + for (Entity e: entities) + { + if (e == player || (currentVehicle == e)) + continue; + double dd = player.distanceToSqr(e); + if (dd actionAttempts = new HashMap<>(); + actions.values().removeIf(e -> e.done); + for (Map.Entry e : actions.entrySet()) + { + ActionType type = e.getKey(); + Action action = e.getValue(); + // skipping attack if use was successful + if (!(actionAttempts.getOrDefault(ActionType.USE, false) && type == ActionType.ATTACK)) + { + Boolean actionStatus = action.tick(this, type); + if (actionStatus != null) + actionAttempts.put(type, actionStatus); + } + // optionally retrying use after successful attack and unsuccessful use + if (type == ActionType.ATTACK + && actionAttempts.getOrDefault(ActionType.ATTACK, false) + && !actionAttempts.getOrDefault(ActionType.USE, true) ) + { + // according to MinecraftClient.handleInputEvents + Action using = actions.get(ActionType.USE); + if (using != null) // this is always true - we know use worked, but just in case + { + using.retry(this, ActionType.USE); + } + } + } + float vel = sneaking?0.3F:1.0F; + // The != 0.0F checks are needed given else real players can't control minecarts, however it works with fakes and else they don't stop immediately + if (forward != 0.0F || player instanceof MinionFakePlayer) { + player.zza = forward * vel; + } + if (strafing != 0.0F || player instanceof MinionFakePlayer) { + player.xxa = strafing * vel; + } + } + + static HitResult getTarget(ServerPlayer player) + { + double reach = player.gameMode.isCreative() ? 5 : 4.5f; + return Tracer.rayTrace(player, 1, reach, false); + } + + private void dropItemFromSlot(int slot, boolean dropAll) + { + Inventory inv = player.getInventory(); // getInventory; + if (!inv.getItem(slot).isEmpty()) + player.drop(inv.removeItem(slot, + dropAll ? inv.getItem(slot).getCount() : 1 + ), false, true); // scatter, keep owner + } + + public void drop(int selectedSlot, boolean dropAll) + { + Inventory inv = player.getInventory(); // getInventory; + if (selectedSlot == -2) // all + { + for (int i = inv.getContainerSize(); i >= 0; i--) + dropItemFromSlot(i, dropAll); + } + else // one slot + { + if (selectedSlot == -1) + selectedSlot = inv.selected; + dropItemFromSlot(selectedSlot, dropAll); + } + } + + public void setSlot(int slot) + { + player.getInventory().selected = slot-1; + player.connection.send(new ClientboundSetCarriedItemPacket(slot-1)); + } + + public enum ActionType + { + USE(true) + { + @Override + boolean execute(ServerPlayer player, Action action) + { + EntityPlayerActionPack ap = ((ServerPlayerInterface) player).getActionPack(); + if (ap.itemUseCooldown > 0) + { + ap.itemUseCooldown--; + return true; + } + if (player.isUsingItem()) + { + return true; + } + HitResult hit = getTarget(player); + for (InteractionHand hand : InteractionHand.values()) + { + switch (hit.getType()) + { + case BLOCK: + { + player.resetLastActionTime(); + ServerLevel world = player.serverLevel(); + BlockHitResult blockHit = (BlockHitResult) hit; + BlockPos pos = blockHit.getBlockPos(); + Direction side = blockHit.getDirection(); + if (pos.getY() < player.level().getMaxBuildHeight() - (side == Direction.UP ? 1 : 0) && world.mayInteract(player, pos)) + { + InteractionResult result = player.gameMode.useItemOn(player, world, player.getItemInHand(hand), hand, blockHit); + if (result.consumesAction()) + { + if (result.shouldSwing()) player.swing(hand); + ap.itemUseCooldown = 3; + return true; + } + } + break; + } + case ENTITY: + { + player.resetLastActionTime(); + EntityHitResult entityHit = (EntityHitResult) hit; + Entity entity = entityHit.getEntity(); + boolean handWasEmpty = player.getItemInHand(hand).isEmpty(); + boolean itemFrameEmpty = (entity instanceof ItemFrame) && ((ItemFrame) entity).getItem().isEmpty(); + Vec3 relativeHitPos = entityHit.getLocation().subtract(entity.getX(), entity.getY(), entity.getZ()); + if (entity.interactAt(player, relativeHitPos, hand).consumesAction()) + { + ap.itemUseCooldown = 3; + return true; + } + // fix for SS itemframe always returns CONSUME even if no action is performed + if (player.interactOn(entity, hand).consumesAction() && !(handWasEmpty && itemFrameEmpty)) + { + ap.itemUseCooldown = 3; + return true; + } + break; + } + } + ItemStack handItem = player.getItemInHand(hand); + if (player.gameMode.useItem(player, player.level(), handItem, hand).consumesAction()) + { + ap.itemUseCooldown = 3; + return true; + } + } + return false; + } + + @Override + void inactiveTick(ServerPlayer player, Action action) + { + EntityPlayerActionPack ap = ((ServerPlayerInterface) player).getActionPack(); + ap.itemUseCooldown = 0; + player.releaseUsingItem(); + } + }, + ATTACK(true) { + @Override + boolean execute(ServerPlayer player, Action action) { + HitResult hit = getTarget(player); + switch (hit.getType()) { + case ENTITY: { + EntityHitResult entityHit = (EntityHitResult) hit; + if (!action.isContinuous) + { + player.attack(entityHit.getEntity()); + player.swing(InteractionHand.MAIN_HAND); + } + player.resetAttackStrengthTicker(); + player.resetLastActionTime(); + return true; + } + case BLOCK: { + EntityPlayerActionPack ap = ((ServerPlayerInterface) player).getActionPack(); + if (ap.blockHitDelay > 0) + { + ap.blockHitDelay--; + return false; + } + BlockHitResult blockHit = (BlockHitResult) hit; + BlockPos pos = blockHit.getBlockPos(); + Direction side = blockHit.getDirection(); + if (player.blockActionRestricted(player.level(), pos, player.gameMode.getGameModeForPlayer())) return false; + if (ap.currentBlock != null && player.level().getBlockState(ap.currentBlock).isAir()) + { + ap.currentBlock = null; + return false; + } + BlockState state = player.level().getBlockState(pos); + boolean blockBroken = false; + if (player.gameMode.getGameModeForPlayer().isCreative()) + { + player.gameMode.handleBlockBreakAction(pos, ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, side, player.level().getMaxBuildHeight(), -1); + ap.blockHitDelay = 5; + blockBroken = true; + } + else if (ap.currentBlock == null || !ap.currentBlock.equals(pos)) + { + if (ap.currentBlock != null) + { + player.gameMode.handleBlockBreakAction(ap.currentBlock, ServerboundPlayerActionPacket.Action.ABORT_DESTROY_BLOCK, side, player.level().getMaxBuildHeight(), -1); + } + player.gameMode.handleBlockBreakAction(pos, ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, side, player.level().getMaxBuildHeight(), -1); + boolean notAir = !state.isAir(); + if (notAir && ap.curBlockDamageMP == 0) + { + state.attack(player.level(), pos, player); + } + if (notAir && state.getDestroyProgress(player, player.level(), pos) >= 1) + { + ap.currentBlock = null; + //instamine?? + blockBroken = true; + } + else + { + ap.currentBlock = pos; + ap.curBlockDamageMP = 0; + } + } + else + { + ap.curBlockDamageMP += state.getDestroyProgress(player, player.level(), pos); + if (ap.curBlockDamageMP >= 1) + { + player.gameMode.handleBlockBreakAction(pos, ServerboundPlayerActionPacket.Action.STOP_DESTROY_BLOCK, side, player.level().getMaxBuildHeight(), -1); + ap.currentBlock = null; + ap.blockHitDelay = 5; + blockBroken = true; + } + player.level().destroyBlockProgress(-1, pos, (int) (ap.curBlockDamageMP * 10)); + + } + player.resetLastActionTime(); + player.swing(InteractionHand.MAIN_HAND); + return blockBroken; + } + } + return false; + } + + @Override + void inactiveTick(ServerPlayer player, Action action) + { + EntityPlayerActionPack ap = ((ServerPlayerInterface) player).getActionPack(); + if (ap.currentBlock == null) return; + player.level().destroyBlockProgress(-1, ap.currentBlock, -1); + player.gameMode.handleBlockBreakAction(ap.currentBlock, ServerboundPlayerActionPacket.Action.ABORT_DESTROY_BLOCK, Direction.DOWN, player.level().getMaxBuildHeight(), -1); + ap.currentBlock = null; + } + }, + JUMP(true) + { + @Override + boolean execute(ServerPlayer player, Action action) + { + if (action.limit == 1) + { + if (player.onGround()) player.jumpFromGround(); // onGround + } + else + { + player.setJumping(true); + } + return false; + } + + @Override + void inactiveTick(ServerPlayer player, Action action) + { + player.setJumping(false); + } + }, + DROP_ITEM(true) + { + @Override + boolean execute(ServerPlayer player, Action action) + { + player.resetLastActionTime(); + player.drop(false); // dropSelectedItem + return false; + } + }, + DROP_STACK(true) + { + @Override + boolean execute(ServerPlayer player, Action action) + { + player.resetLastActionTime(); + player.drop(true); // dropSelectedItem + return false; + } + }, + SWAP_HANDS(true) + { + @Override + boolean execute(ServerPlayer player, Action action) + { + player.resetLastActionTime(); + ItemStack itemStack_1 = player.getItemInHand(InteractionHand.OFF_HAND); + player.setItemInHand(InteractionHand.OFF_HAND, player.getItemInHand(InteractionHand.MAIN_HAND)); + player.setItemInHand(InteractionHand.MAIN_HAND, itemStack_1); + return false; + } + }; + + public final boolean preventSpectator; + + ActionType(boolean preventSpectator) + { + this.preventSpectator = preventSpectator; + } + + void start(ServerPlayer player, Action action) {} + abstract boolean execute(ServerPlayer player, Action action); + void inactiveTick(ServerPlayer player, Action action) {} + void stop(ServerPlayer player, Action action) + { + inactiveTick(player, action); + } + } + + public static class Action + { + public boolean done = false; + public final int limit; + public final int interval; + public final int offset; + private int count; + private int next; + private final boolean isContinuous; + + private Action(int limit, int interval, int offset, boolean continuous) + { + this.limit = limit; + this.interval = interval; + this.offset = offset; + next = interval + offset; + isContinuous = continuous; + } + + public static Action once() + { + return new Action(1, 1, 0, false); + } + + public static Action continuous() + { + return new Action(-1, 1, 0, true); + } + + public static Action interval(int interval) + { + return new Action(-1, interval, 0, false); + } + + public static Action interval(int interval, int offset) + { + return new Action(-1, interval, offset, false); + } + + Boolean tick(EntityPlayerActionPack actionPack, ActionType type) + { + next--; + Boolean cancel = null; + if (next <= 0) + { + if (interval == 1 && !isContinuous) + { + // need to allow entity to tick, otherwise won't have effect (bow) + // actions are 20 tps, so need to clear status mid tick, allowing entities process it till next time + if (!type.preventSpectator || !actionPack.player.isSpectator()) + { + type.inactiveTick(actionPack.player, this); + } + } + + if (!type.preventSpectator || !actionPack.player.isSpectator()) + { + cancel = type.execute(actionPack.player, this); + } + count++; + if (count == limit) + { + type.stop(actionPack.player, null); + done = true; + return cancel; + } + next = interval; + } + else + { + if (!type.preventSpectator || !actionPack.player.isSpectator()) + { + type.inactiveTick(actionPack.player, this); + } + } + return cancel; + } + + void retry(EntityPlayerActionPack actionPack, ActionType type) + { + //assuming action run but was unsuccesful that tick, but opportunity emerged to retry it, lets retry it. + if (!type.preventSpectator || !actionPack.player.isSpectator()) + { + type.execute(actionPack.player, this); + } + count++; + if (count == limit) + { + type.stop(actionPack.player, null); + done = true; + } + } + } +} diff --git a/oldSrc/io/github/skippyall/minions/fakeplayer/FakeClientConnection.java b/oldSrc/io/github/skippyall/minions/fakeplayer/FakeClientConnection.java new file mode 100644 index 0000000..10bdb7c --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/fakeplayer/FakeClientConnection.java @@ -0,0 +1,37 @@ +package io.github.skippyall.minions.fakeplayer; + +import io.netty.channel.embedded.EmbeddedChannel; +import net.minecraft.network.Connection; +import net.minecraft.network.PacketListener; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.PacketFlow; + +public class FakeClientConnection extends Connection { + public FakeClientConnection(PacketFlow p) + { + super(p); + // compat with adventure-platform-fabric. This does NOT trigger other vanilla handlers for establishing a channel + // also makes #isOpen return true, allowing enderpearls to teleport fake players + ((ClientConnectionInterface)this).setChannel(new EmbeddedChannel()); + } + + @Override + public void setReadOnly() + { + } + + @Override + public void handleDisconnection() { + getPacketListener().onDisconnect(getDisconnectedReason()==null ? Component.literal("Disconnected"): getDisconnectedReason()); + } + + @Override + public void setListenerForServerboundHandshake(PacketListener packetListener) + { + } + + @Override + public void setListener(PacketListener packetListener) { + + } +} diff --git a/oldSrc/io/github/skippyall/minions/fakeplayer/MinionFakePlayer.java b/oldSrc/io/github/skippyall/minions/fakeplayer/MinionFakePlayer.java new file mode 100644 index 0000000..ec465e6 --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/fakeplayer/MinionFakePlayer.java @@ -0,0 +1,201 @@ +package io.github.skippyall.minions.fakeplayer; + +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.yggdrasil.ProfileResult; +import net.minecraft.core.BlockPos; +import net.minecraft.core.UUIDUtil; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.contents.TranslatableContents; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket; +import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket; +import net.minecraft.network.protocol.game.ServerboundClientCommandPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.TickTask; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.food.FoodData; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +import java.util.UUID; + +public class MinionFakePlayer extends ServerPlayer { + public Runnable fixStartingPosition = () -> {}; + public boolean isAShadow; + public static void createMinion(String username, ServerLevel level, ServerPlayer owner, Vec3 pos, double yaw, double pitch) { + MinecraftServer server = level.getServer(); + server.getProfileCache().getAsync(username).thenAcceptAsync((optional) -> { + GameProfile profile = null; + if(optional.isPresent()){ + UUID uuid = optional.get().getId(); + ProfileResult result = server.getSessionService().fetchProfile(uuid, true); + if(result != null) { + profile = result.profile(); + } + } + if(profile == null) { + profile = new GameProfile(UUIDUtil.createOfflinePlayerUUID(username), username); + } + MinionFakePlayer instance = new MinionFakePlayer(server, level, profile, ClientInformation.createDefault(), false); + instance.fixStartingPosition = () -> instance.moveTo(pos.x, pos.y, pos.z, (float) yaw, (float) pitch); + server.getPlayerList().placeNewPlayer(new FakeClientConnection(PacketFlow.SERVERBOUND), instance, new CommonListenerCookie(profile, 0, instance.clientInformation())); + instance.teleportTo(level, pos.x, pos.y, pos.z, (float) yaw, (float) pitch); + instance.setHealth(20.0F); + instance.unsetRemoved(); + instance.gameMode.changeGameModeForPlayer(GameType.SURVIVAL); + server.getPlayerList().broadcastAll(new ClientboundRotateHeadPacket(instance, (byte) (instance.yHeadRot * 256 / 360)), level.dimension());//instance.dimension); + server.getPlayerList().broadcastAll(new ClientboundTeleportEntityPacket(instance), level.dimension());//instance.dimension); + //instance.world.getChunkManager(). updatePosition(instance); + instance.entityData.set(DATA_PLAYER_MODE_CUSTOMISATION, (byte) 0x7f); // show all model layers (incl. capes) + instance.getAbilities().flying = false; + instance.setMaxUpStep(0.6F); + }); + + + } + + @SuppressWarnings("unused") //Don't know if I'll need this + public static MinionFakePlayer createShadow(MinecraftServer server, ServerPlayer player) + { + player.getServer().getPlayerList().remove(player); + player.connection.disconnect(Component.translatable("multiplayer.disconnect.duplicate_login")); + ServerLevel worldIn = player.serverLevel();//.getWorld(player.dimension); + GameProfile gameprofile = player.getGameProfile(); + MinionFakePlayer playerShadow = new MinionFakePlayer(server, worldIn, gameprofile, player.clientInformation(), true); + playerShadow.setChatSession(player.getChatSession()); + server.getPlayerList().placeNewPlayer(new FakeClientConnection(PacketFlow.SERVERBOUND), playerShadow, new CommonListenerCookie(gameprofile, 0, player.clientInformation())); + + playerShadow.setHealth(player.getHealth()); + playerShadow.connection.teleport(player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot()); + playerShadow.gameMode.changeGameModeForPlayer(player.gameMode.getGameModeForPlayer()); + ((ServerPlayerInterface) playerShadow).getActionPack().copyFrom(((ServerPlayerInterface) player).getActionPack()); + playerShadow.entityData.set(DATA_PLAYER_MODE_CUSTOMISATION, player.getEntityData().get(DATA_PLAYER_MODE_CUSTOMISATION)); + + + server.getPlayerList().broadcastAll(new ClientboundRotateHeadPacket(playerShadow, (byte) (player.yHeadRot * 256 / 360)), playerShadow.level().dimension()); + server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, playerShadow)); + //player.world.getChunkManager().updatePosition(playerShadow); + playerShadow.getAbilities().flying = player.getAbilities().flying; + return playerShadow; + } + + public static MinionFakePlayer respawnFake(MinecraftServer server, ServerLevel level, GameProfile profile, ClientInformation cli) + { + return new MinionFakePlayer(server, level, profile, cli, false); + } + + private MinionFakePlayer(MinecraftServer server, ServerLevel worldIn, GameProfile profile, ClientInformation cli, boolean shadow) + { + super(server, worldIn, profile, cli); + isAShadow = shadow; + } + + @Override + public void onEquipItem(final EquipmentSlot slot, final ItemStack previous, final ItemStack stack) + { + if (!isUsingItem()) super.onEquipItem(slot, previous, stack); + } + + @Override + public void kill() + { + kill(Component.literal("Killed")); + } + + public void kill(Component reason) + { + shakeOff(); + + if (reason.getContents() instanceof TranslatableContents text && text.getKey().equals("multiplayer.disconnect.duplicate_login")) { + this.connection.onDisconnect(reason); + } else { + this.server.tell(new TickTask(this.server.getTickCount(), () -> { + this.connection.onDisconnect(reason); + })); + } + } + + @Override + public void tick() + { + if (this.getServer().getTickCount() % 10 == 0) + { + this.connection.resetPosition(); + this.serverLevel().getChunkSource().move(this); + } + try + { + super.tick(); + this.doTick(); + } + catch (NullPointerException ignored) + { + // happens with that paper port thingy - not sure what that would fix, but hey + // the game not gonna crash violently. + } + + + } + + private void shakeOff() + { + if (getVehicle() instanceof Player) stopRiding(); + for (Entity passenger : getIndirectPassengers()) + { + if (passenger instanceof Player) passenger.stopRiding(); + } + } + + @Override + public void die(DamageSource cause) + { + shakeOff(); + super.die(cause); + setHealth(20); + this.foodData = new FoodData(); + kill(this.getCombatTracker().getDeathMessage()); + } + + @Override + public String getIpAddress() + { + return "127.0.0.1"; + } + + @Override + public boolean allowsListing() { + return false; + } + + @Override + protected void checkFallDamage(double y, boolean onGround, BlockState state, BlockPos pos) { + doCheckFallDamage(0.0, y, 0.0, onGround); + } + + @Override + public Entity changeDimension(ServerLevel serverLevel) + { + super.changeDimension(serverLevel); + if (wonGame) { + ServerboundClientCommandPacket p = new ServerboundClientCommandPacket(ServerboundClientCommandPacket.Action.PERFORM_RESPAWN); + connection.handleClientCommand(p); + } + + // If above branch was taken, *this* has been removed and replaced, the new instance has been set + // on 'our' connection (which is now theirs, but we still have a ref). + if (connection.player.isChangingDimension()) { + connection.player.hasChangedDimension(); + } + return connection.player; + } +} \ No newline at end of file diff --git a/oldSrc/io/github/skippyall/minions/fakeplayer/NetHandlerPlayServerFake.java b/oldSrc/io/github/skippyall/minions/fakeplayer/NetHandlerPlayServerFake.java new file mode 100644 index 0000000..47f724e --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/fakeplayer/NetHandlerPlayServerFake.java @@ -0,0 +1,46 @@ +package io.github.skippyall.minions.fakeplayer; + +import net.minecraft.network.Connection; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.contents.TranslatableContents; +import net.minecraft.network.protocol.Packet; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.entity.RelativeMovement; + +import java.util.Set; + +public class NetHandlerPlayServerFake extends ServerGamePacketListenerImpl +{ + public NetHandlerPlayServerFake(final MinecraftServer minecraftServer, final Connection connection, final ServerPlayer serverPlayer, final CommonListenerCookie i) + { + super(minecraftServer, connection, serverPlayer, i); + } + + @Override + public void send(final Packet packetIn) + { + } + + @Override + public void disconnect(Component message) + { + if (message.getContents() instanceof TranslatableContents text && (text.getKey().equals("multiplayer.disconnect.idling") || text.getKey().equals("multiplayer.disconnect.duplicate_login"))) + { + ((MinionFakePlayer) player).kill(message); + } + } + + @Override + public void teleport(double d, double e, double f, float g, float h, Set set) + { + super.teleport(d, e, f, g, h, set); + if (player.serverLevel().getPlayerByUUID(player.getUUID()) != null) { + resetPosition(); + player.serverLevel().getChunkSource().move(player); + } + } + +} diff --git a/oldSrc/io/github/skippyall/minions/fakeplayer/ServerPlayerInterface.java b/oldSrc/io/github/skippyall/minions/fakeplayer/ServerPlayerInterface.java new file mode 100644 index 0000000..f75600d --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/fakeplayer/ServerPlayerInterface.java @@ -0,0 +1,8 @@ +package io.github.skippyall.minions.fakeplayer; + +import io.github.skippyall.minions.fakeplayer.EntityPlayerActionPack; + +public interface ServerPlayerInterface +{ + EntityPlayerActionPack getActionPack(); +} diff --git a/oldSrc/io/github/skippyall/minions/fakeplayer/Tracer.java b/oldSrc/io/github/skippyall/minions/fakeplayer/Tracer.java new file mode 100644 index 0000000..7ef007f --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/fakeplayer/Tracer.java @@ -0,0 +1,90 @@ +package io.github.skippyall.minions.fakeplayer; + +import java.util.Optional; +import java.util.function.Predicate; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +public class Tracer +{ + public static HitResult rayTrace(Entity source, float partialTicks, double reach, boolean fluids) + { + BlockHitResult blockHit = rayTraceBlocks(source, partialTicks, reach, fluids); + double maxSqDist = reach * reach; + if (blockHit != null) + { + maxSqDist = blockHit.getLocation().distanceToSqr(source.getEyePosition(partialTicks)); + } + EntityHitResult entityHit = rayTraceEntities(source, partialTicks, reach, maxSqDist); + return entityHit == null ? blockHit : entityHit; + } + + public static BlockHitResult rayTraceBlocks(Entity source, float partialTicks, double reach, boolean fluids) + { + Vec3 pos = source.getEyePosition(partialTicks); + Vec3 rotation = source.getViewVector(partialTicks); + Vec3 reachEnd = pos.add(rotation.x * reach, rotation.y * reach, rotation.z * reach); + return source.level().clip(new ClipContext(pos, reachEnd, ClipContext.Block.OUTLINE, fluids ? + ClipContext.Fluid.ANY : ClipContext.Fluid.NONE, source)); + } + + public static EntityHitResult rayTraceEntities(Entity source, float partialTicks, double reach, double maxSqDist) + { + Vec3 pos = source.getEyePosition(partialTicks); + Vec3 reachVec = source.getViewVector(partialTicks).scale(reach); + AABB box = source.getBoundingBox().expandTowards(reachVec).inflate(1); + return rayTraceEntities(source, pos, pos.add(reachVec), box, e -> !e.isSpectator() && e.isPickable(), maxSqDist); + } + + public static EntityHitResult rayTraceEntities(Entity source, Vec3 start, Vec3 end, AABB box, Predicate predicate, double maxSqDistance) + { + Level world = source.level(); + double targetDistance = maxSqDistance; + Entity target = null; + Vec3 targetHitPos = null; + for (Entity current : world.getEntities(source, box, predicate)) + { + AABB currentBox = current.getBoundingBox().inflate(current.getPickRadius()); + Optional currentHit = currentBox.clip(start, end); + if (currentBox.contains(start)) + { + if (targetDistance >= 0) + { + target = current; + targetHitPos = currentHit.orElse(start); + targetDistance = 0; + } + } + else if (currentHit.isPresent()) + { + Vec3 currentHitPos = currentHit.get(); + double currentDistance = start.distanceToSqr(currentHitPos); + if (currentDistance < targetDistance || targetDistance == 0) + { + if (current.getRootVehicle() == source.getRootVehicle()) + { + if (targetDistance == 0) + { + target = current; + targetHitPos = currentHitPos; + } + } + else + { + target = current; + targetHitPos = currentHitPos; + targetDistance = currentDistance; + } + } + } + } + return target == null ? null : new EntityHitResult(target, targetHitPos); + } +} diff --git a/oldSrc/io/github/skippyall/minions/mixins/ConnectionMixin.java b/oldSrc/io/github/skippyall/minions/mixins/ConnectionMixin.java new file mode 100644 index 0000000..889ab4d --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/mixins/ConnectionMixin.java @@ -0,0 +1,14 @@ +package io.github.skippyall.minions.mixins; + +import io.github.skippyall.minions.fakeplayer.ClientConnectionInterface; +import io.netty.channel.Channel; +import net.minecraft.network.Connection; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(Connection.class) +public abstract class ConnectionMixin implements ClientConnectionInterface { + @Override + @Accessor //Compat with adventure-platform-fabric + public abstract void setChannel(Channel channel); +} diff --git a/oldSrc/io/github/skippyall/minions/mixins/PlayerListMixin.java b/oldSrc/io/github/skippyall/minions/mixins/PlayerListMixin.java new file mode 100644 index 0000000..aab61ea --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/mixins/PlayerListMixin.java @@ -0,0 +1,56 @@ +package io.github.skippyall.minions.mixins; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.mojang.authlib.GameProfile; +import io.github.skippyall.minions.fakeplayer.MinionFakePlayer; +import io.github.skippyall.minions.fakeplayer.NetHandlerPlayServerFake; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.Connection; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.server.players.PlayerList; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(PlayerList.class) +public class PlayerListMixin { + @Shadow + @Final + private MinecraftServer server; + + @Inject(method = "load", at = @At(value = "RETURN", shift = At.Shift.BEFORE)) + private void fixStartingPos(ServerPlayer serverPlayerEntity_1, CallbackInfoReturnable cir) + { + if (serverPlayerEntity_1 instanceof MinionFakePlayer) + { + ((MinionFakePlayer) serverPlayerEntity_1).fixStartingPosition.run(); + } + } + + @WrapOperation(method = "placeNewPlayer", at = @At(value = "NEW", target = "(Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/network/Connection;Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/server/network/CommonListenerCookie;)Lnet/minecraft/server/network/ServerGamePacketListenerImpl;")) + private ServerGamePacketListenerImpl replaceNetworkHandler(MinecraftServer minecraftServer, Connection connection, ServerPlayer serverPlayer, CommonListenerCookie commonListenerCookie, Operation original) + { + if (serverPlayer instanceof MinionFakePlayer fake) { + return new NetHandlerPlayServerFake(this.server, connection, fake, commonListenerCookie); + } else { + return original.call(minecraftServer, connection, serverPlayer, commonListenerCookie); + } + } + + @WrapOperation(method = "respawn", at = @At(value = "NEW", target = "(Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/server/level/ServerLevel;Lcom/mojang/authlib/GameProfile;Lnet/minecraft/server/level/ClientInformation;)Lnet/minecraft/server/level/ServerPlayer;")) + public ServerPlayer makePlayerForRespawn(MinecraftServer minecraftServer, ServerLevel serverLevel, GameProfile gameProfile, ClientInformation clientInformation, Operation original, ServerPlayer serverPlayer, boolean bl) { + if (serverPlayer instanceof MinionFakePlayer) { + return MinionFakePlayer.respawnFake(minecraftServer, serverLevel, gameProfile, clientInformation); + } + return original.call(minecraftServer, serverLevel, gameProfile, clientInformation); + } +} diff --git a/oldSrc/io/github/skippyall/minions/mixins/ServerPlayerMixin.java b/oldSrc/io/github/skippyall/minions/mixins/ServerPlayerMixin.java new file mode 100644 index 0000000..3f1be9b --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/mixins/ServerPlayerMixin.java @@ -0,0 +1,37 @@ +package io.github.skippyall.minions.mixins; + +import com.mojang.authlib.GameProfile; +import io.github.skippyall.minions.fakeplayer.EntityPlayerActionPack; +import io.github.skippyall.minions.fakeplayer.ServerPlayerInterface; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ServerPlayer.class) +public abstract class ServerPlayerMixin implements ServerPlayerInterface { + @Unique + public EntityPlayerActionPack actionPack; + @Override + public EntityPlayerActionPack getActionPack() + { + return actionPack; + } + + @Inject(method = "", at = @At(value = "RETURN")) + private void onServerPlayerEntityContructor(MinecraftServer minecraftServer, ServerLevel serverLevel, GameProfile gameProfile, ClientInformation clientInformation, CallbackInfo ci) + { + this.actionPack = new EntityPlayerActionPack((ServerPlayer) (Object) this); + } + + @Inject(method = "tick", at = @At(value = "HEAD")) + private void onTick(CallbackInfo ci) + { + actionPack.onUpdate(); + } +} diff --git a/oldSrc/io/github/skippyall/minions/networking/ClientToServerNetworking.java b/oldSrc/io/github/skippyall/minions/networking/ClientToServerNetworking.java new file mode 100644 index 0000000..a4760f5 --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/networking/ClientToServerNetworking.java @@ -0,0 +1,41 @@ +package io.github.skippyall.minions.networking; + +import io.github.skippyall.minions.Minions; +import io.netty.buffer.Unpooled; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; +import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientConfigurationPacketListenerImpl; +import net.minecraft.client.multiplayer.ClientHandshakePacketListenerImpl; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerConfigurationPacketListenerImpl; +import net.minecraft.world.entity.player.Player; + +public class ClientToServerNetworking { + public static final ResourceLocation RL = new ResourceLocation(Minions.MOD_ID, "network"); + @Environment(EnvType.CLIENT) + public static void sendJoinPacket(Player player) { + FriendlyByteBuf pbf = new FriendlyByteBuf(Unpooled.buffer()); + pbf.writeUtf("BN|Init|V0.1"); + ClientConfigurationNetworking.send(RL, pbf); + } + + @Environment(EnvType.CLIENT) + public static void onConfigurationInit(ClientConfigurationPacketListenerImpl handler, Minecraft client) { + sendJoinPacket(client.player); + } + + @Environment(EnvType.SERVER) + public static void receive(MinecraftServer server, ServerConfigurationPacketListenerImpl handler, FriendlyByteBuf buf, PacketSender responseSender) { + String message = buf.readUtf(); + if (!message.startsWith("BN|")) { + Minions.LOGGER.debug("Message with wrong format: " + message); + } + String[] parts = message.split("|"); + + } +} diff --git a/oldSrc/io/github/skippyall/minions/networking/VersionChecker.java b/oldSrc/io/github/skippyall/minions/networking/VersionChecker.java new file mode 100644 index 0000000..cecb824 --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/networking/VersionChecker.java @@ -0,0 +1,22 @@ +package io.github.skippyall.minions.networking; + +import net.minecraft.world.entity.player.Player; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class VersionChecker { + protected static List hasSupportedMod = new ArrayList<>(); + public static boolean supportVersion(String version) { + return version.equals("v0.1"); + } + + public static boolean useSupportedMod(Player p) { + return hasSupportedMod.contains(p.getUUID()); + } + + public static void resetPlayer(UUID uuid) { + hasSupportedMod.remove(uuid); + } +} diff --git a/oldSrc/io/github/skippyall/minions/program/block/CodeBlock.java b/oldSrc/io/github/skippyall/minions/program/block/CodeBlock.java new file mode 100644 index 0000000..46d0723 --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/program/block/CodeBlock.java @@ -0,0 +1,12 @@ +package io.github.skippyall.minions.program.block; + +import io.github.skippyall.minions.program.variables.Type; + +import java.util.List; + +public abstract class CodeBlock { + public CodeBlock(String name, List arguments) { + } + + public abstract Object execute(Object... args); +} diff --git a/oldSrc/io/github/skippyall/minions/program/block/CodeBlocks.java b/oldSrc/io/github/skippyall/minions/program/block/CodeBlocks.java new file mode 100644 index 0000000..7d834bb --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/program/block/CodeBlocks.java @@ -0,0 +1,5 @@ +package io.github.skippyall.minions.program.block; + +public class CodeBlocks { + public static final ForwardBlock FORWARD = new ForwardBlock(); +} diff --git a/oldSrc/io/github/skippyall/minions/program/block/ForwardBlock.java b/oldSrc/io/github/skippyall/minions/program/block/ForwardBlock.java new file mode 100644 index 0000000..e06f01d --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/program/block/ForwardBlock.java @@ -0,0 +1,19 @@ +package io.github.skippyall.minions.program.block; + +import io.github.skippyall.minions.program.variables.IntegerType; +import io.github.skippyall.minions.program.variables.Type; +import io.github.skippyall.minions.program.variables.Types; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ForwardBlock extends CodeBlock{ + public ForwardBlock() { + super("forward", Arrays.asList(Types.INTEGER)); + } + + public Object execute(Object... args) { + return null; + } +} diff --git a/oldSrc/io/github/skippyall/minions/program/module/Modul.java b/oldSrc/io/github/skippyall/minions/program/module/Modul.java new file mode 100644 index 0000000..d9756bc --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/program/module/Modul.java @@ -0,0 +1,15 @@ +package io.github.skippyall.minions.program.module; + +import eu.pb4.polymer.core.api.item.PolymerItem; +import io.github.skippyall.minions.program.block.CodeBlock; + +import java.util.List; + +public abstract class Modul implements PolymerItem { + private final String name; + Modul(String name) { + this.name = name; + } + + public abstract List getCodeBlocks(); +} diff --git a/oldSrc/io/github/skippyall/minions/program/module/Modules.java b/oldSrc/io/github/skippyall/minions/program/module/Modules.java new file mode 100644 index 0000000..621cd19 --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/program/module/Modules.java @@ -0,0 +1,5 @@ +package io.github.skippyall.minions.program.module; + +public class Modules { + MoveModul MOVE = new MoveModul(); +} diff --git a/oldSrc/io/github/skippyall/minions/program/module/MoveModul.java b/oldSrc/io/github/skippyall/minions/program/module/MoveModul.java new file mode 100644 index 0000000..861429d --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/program/module/MoveModul.java @@ -0,0 +1,30 @@ +package io.github.skippyall.minions.program.module; + +import io.github.skippyall.minions.program.block.CodeBlock; +import io.github.skippyall.minions.program.block.CodeBlocks; +import io.github.skippyall.minions.program.block.ForwardBlock; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class MoveModul extends Modul{ + MoveModul() { + super("Movement"); + } + + public List getCodeBlocks() { + List codeBlocks = new ArrayList<>(); + codeBlocks.add(CodeBlocks.FORWARD); + return codeBlocks; + } + + @Override + public Item getPolymerItem(ItemStack itemStack, @Nullable ServerPlayer player) { + return Items.PURPLE_GLAZED_TERRACOTTA; + } +} diff --git a/oldSrc/io/github/skippyall/minions/program/variables/IntegerType.java b/oldSrc/io/github/skippyall/minions/program/variables/IntegerType.java new file mode 100644 index 0000000..e868ed3 --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/program/variables/IntegerType.java @@ -0,0 +1,4 @@ +package io.github.skippyall.minions.program.variables; + +public class IntegerType extends Type{ +} diff --git a/oldSrc/io/github/skippyall/minions/program/variables/Type.java b/oldSrc/io/github/skippyall/minions/program/variables/Type.java new file mode 100644 index 0000000..8a019d0 --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/program/variables/Type.java @@ -0,0 +1,4 @@ +package io.github.skippyall.minions.program.variables; + +public abstract class Type { +} diff --git a/oldSrc/io/github/skippyall/minions/program/variables/Types.java b/oldSrc/io/github/skippyall/minions/program/variables/Types.java new file mode 100644 index 0000000..547720e --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/program/variables/Types.java @@ -0,0 +1,5 @@ +package io.github.skippyall.minions.program.variables; + +public class Types { + public static final IntegerType INTEGER = new IntegerType(); +} diff --git a/oldSrc/io/github/skippyall/minions/server/MinionsServer.java b/oldSrc/io/github/skippyall/minions/server/MinionsServer.java new file mode 100644 index 0000000..d688253 --- /dev/null +++ b/oldSrc/io/github/skippyall/minions/server/MinionsServer.java @@ -0,0 +1,22 @@ +package io.github.skippyall.minions.server; + +import io.github.skippyall.minions.networking.ClientToServerNetworking; +import io.github.skippyall.minions.networking.VersionChecker; +import net.fabricmc.api.DedicatedServerModInitializer; +import net.fabricmc.fabric.api.networking.v1.ServerConfigurationConnectionEvents; +import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerConfigurationPacketListenerImpl; + +public class MinionsServer implements DedicatedServerModInitializer { + @Override + public void onInitializeServer() { + ServerConfigurationNetworking.registerGlobalReceiver(ClientToServerNetworking.RL, ClientToServerNetworking::receive); + ServerConfigurationConnectionEvents.CONFIGURE.register(new ServerConfigurationConnectionEvents.Configure() { + @Override + public void onSendConfiguration(ServerConfigurationPacketListenerImpl handler, MinecraftServer server) { + VersionChecker.resetPlayer(handler.getOwner().getId()); + } + }); + } +} diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..f91a4fe --- /dev/null +++ b/settings.gradle @@ -0,0 +1,9 @@ +pluginManagement { + repositories { + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + gradlePluginPortal() + } +} diff --git a/src/main/java/io/github/skippyall/minions/Minions.java b/src/main/java/io/github/skippyall/minions/Minions.java new file mode 100644 index 0000000..0485d45 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/Minions.java @@ -0,0 +1,21 @@ +package io.github.skippyall.minions; + +import eu.pb4.polymer.core.api.entity.PolymerEntityUtils; +import io.github.skippyall.minions.minion.MinionItem; +import net.fabricmc.api.ModInitializer; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.util.Identifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Minions implements ModInitializer { + public static final String MOD_ID = "minions"; + public static final MinionItem MINION_ITEM = Registry.register(Registries.ITEM, new Identifier(MOD_ID, "minion"), new MinionItem()); + + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + @Override + public void onInitialize() { + PolymerEntityUtils.registerType(); + } +} diff --git a/src/main/java/io/github/skippyall/minions/client/MinionsClient.java b/src/main/java/io/github/skippyall/minions/client/MinionsClient.java new file mode 100644 index 0000000..4c8282f --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/client/MinionsClient.java @@ -0,0 +1,16 @@ +package io.github.skippyall.minions.client; + +import io.github.skippyall.minions.networking.ClientToServerNetworking; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationConnectionEvents; +import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents; + +public class MinionsClient implements ClientModInitializer { + /** + * Runs the mod initializer on the client environment. + */ + @Override + public void onInitializeClient() { + ClientConfigurationConnectionEvents.INIT.register(ClientToServerNetworking::onConfigurationInit); + } +} diff --git a/src/main/java/io/github/skippyall/minions/fakeplayer/ClientConnectionInterface.java b/src/main/java/io/github/skippyall/minions/fakeplayer/ClientConnectionInterface.java new file mode 100644 index 0000000..a199f98 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/fakeplayer/ClientConnectionInterface.java @@ -0,0 +1,7 @@ +package io.github.skippyall.minions.fakeplayer; + +import io.netty.channel.Channel; + +public interface ClientConnectionInterface { + void setChannel(Channel channel); +} diff --git a/src/main/java/io/github/skippyall/minions/fakeplayer/EntityPlayerActionPack.java b/src/main/java/io/github/skippyall/minions/fakeplayer/EntityPlayerActionPack.java new file mode 100644 index 0000000..3794471 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/fakeplayer/EntityPlayerActionPack.java @@ -0,0 +1,625 @@ +package io.github.skippyall.minions.fakeplayer; + + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import net.minecraft.block.BlockState; +import net.minecraft.command.argument.EntityAnchorArgumentType; +import net.minecraft.entity.Entity; +import net.minecraft.entity.decoration.ItemFrameEntity; +import net.minecraft.entity.passive.AbstractHorseEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.entity.vehicle.BoatEntity; +import net.minecraft.entity.vehicle.MinecartEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; +import net.minecraft.network.packet.s2c.play.UpdateSelectedSlotS2CPacket; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec2f; +import net.minecraft.util.math.Vec3d; + +public class EntityPlayerActionPack +{ + private final ServerPlayerEntity player; + + private final Map actions = new EnumMap<>(ActionType.class); + + private BlockPos currentBlock; + private int blockHitDelay; + private boolean isHittingBlock; + private float curBlockDamageMP; + + private boolean sneaking; + private boolean sprinting; + private float forward; + private float strafing; + + private int itemUseCooldown; + + public EntityPlayerActionPack(ServerPlayerEntity playerIn) + { + player = playerIn; + stopAll(); + } + public void copyFrom(EntityPlayerActionPack other) + { + actions.putAll(other.actions); + currentBlock = other.currentBlock; + blockHitDelay = other.blockHitDelay; + isHittingBlock = other.isHittingBlock; + curBlockDamageMP = other.curBlockDamageMP; + + sneaking = other.sneaking; + sprinting = other.sprinting; + forward = other.forward; + strafing = other.strafing; + + itemUseCooldown = other.itemUseCooldown; + } + + public EntityPlayerActionPack start(ActionType type, Action action) + { + Action previous = actions.remove(type); + if (previous != null) type.stop(player, previous); + if (action != null) + { + actions.put(type, action); + type.start(player, action); // noop + } + return this; + } + + public EntityPlayerActionPack setSneaking(boolean doSneak) + { + sneaking = doSneak; + player.setSneaking(doSneak); + if (sprinting && sneaking) + setSprinting(false); + return this; + } + public EntityPlayerActionPack setSprinting(boolean doSprint) + { + sprinting = doSprint; + player.setSprinting(doSprint); + if (sneaking && sprinting) + setSneaking(false); + return this; + } + + public EntityPlayerActionPack setForward(float value) + { + forward = value; + return this; + } + public EntityPlayerActionPack setStrafing(float value) + { + strafing = value; + return this; + } + public EntityPlayerActionPack look(Direction direction) + { + return switch (direction) + { + case NORTH -> look(180, 0); + case SOUTH -> look(0, 0); + case EAST -> look(-90, 0); + case WEST -> look(90, 0); + case UP -> look(player.getYaw(), -90); + case DOWN -> look(player.getYaw(), 90); + }; + } + public EntityPlayerActionPack look(Vec2f rotation) + { + return look(rotation.x, rotation.y); + } + + public EntityPlayerActionPack look(float yaw, float pitch) + { + player.setYaw(yaw % 360); //setYaw + player.setPitch(MathHelper.clamp(pitch, -90, 90)); // setPitch + // maybe player.moveTo(player.getX(), player.getY(), player.getZ(), yaw, Mth.clamp(pitch,-90.0F, 90.0F)); + return this; + } + + public EntityPlayerActionPack lookAt(Vec3d position) + { + player.lookAt(EntityAnchorArgumentType.EntityAnchor.EYES, position); + return this; + } + + public EntityPlayerActionPack turn(float yaw, float pitch) + { + return look(player.getYaw() + yaw, player.getPitch() + pitch); + } + + public EntityPlayerActionPack turn(Vec2f rotation) + { + return turn(rotation.x, rotation.y); + } + + public EntityPlayerActionPack stopMovement() + { + setSneaking(false); + setSprinting(false); + forward = 0.0F; + strafing = 0.0F; + return this; + } + + + public EntityPlayerActionPack stopAll() + { + for (ActionType type : actions.keySet()) type.stop(player, actions.get(type)); + actions.clear(); + return stopMovement(); + } + + public EntityPlayerActionPack mount(boolean onlyRideables) + { + //test what happens + List entities; + if (onlyRideables) + { + entities = player.getWorld().getOtherEntities(player, player.getBoundingBox().expand(3.0D, 1.0D, 3.0D), + e -> e instanceof MinecartEntity || e instanceof BoatEntity || e instanceof AbstractHorseEntity); + } + else + { + entities = player.getWorld().getOtherEntities(player, player.getBoundingBox().expand(3.0D, 1.0D, 3.0D)); + } + if (entities.size()==0) + return this; + Entity closest = null; + double distance = Double.POSITIVE_INFINITY; + Entity currentVehicle = player.getVehicle(); + for (Entity e: entities) + { + if (e == player || (currentVehicle == e)) + continue; + double dd = player.squaredDistanceTo(e); + if (dd actionAttempts = new HashMap<>(); + actions.values().removeIf(e -> e.done); + for (Map.Entry e : actions.entrySet()) + { + ActionType type = e.getKey(); + Action action = e.getValue(); + // skipping attack if use was successful + if (!(actionAttempts.getOrDefault(ActionType.USE, false) && type == ActionType.ATTACK)) + { + Boolean actionStatus = action.tick(this, type); + if (actionStatus != null) + actionAttempts.put(type, actionStatus); + } + // optionally retrying use after successful attack and unsuccessful use + if (type == ActionType.ATTACK + && actionAttempts.getOrDefault(ActionType.ATTACK, false) + && !actionAttempts.getOrDefault(ActionType.USE, true) ) + { + // according to MinecraftClient.handleInputEvents + Action using = actions.get(ActionType.USE); + if (using != null) // this is always true - we know use worked, but just in case + { + using.retry(this, ActionType.USE); + } + } + } + float vel = sneaking?0.3F:1.0F; + // The != 0.0F checks are needed given else real players can't control minecarts, however it works with fakes and else they don't stop immediately + if (forward != 0.0F || player instanceof MinionFakePlayer) { + player.forwardSpeed = forward * vel; + } + if (strafing != 0.0F || player instanceof MinionFakePlayer) { + player.sidewaysSpeed = strafing * vel; + } + } + + static HitResult getTarget(ServerPlayerEntity player) + { + double reach = player.interactionManager.isCreative() ? 5 : 4.5f; + return Tracer.rayTrace(player, 1, reach, false); + } + + private void dropItemFromSlot(int slot, boolean dropAll) + { + PlayerInventory inv = player.getInventory(); // getInventory; + if (!inv.getStack(slot).isEmpty()) + player.dropItem(inv.removeStack(slot, + dropAll ? inv.getStack(slot).getCount() : 1 + ), false, true); // scatter, keep owner + } + + public void drop(int selectedSlot, boolean dropAll) + { + PlayerInventory inv = player.getInventory(); // getInventory; + if (selectedSlot == -2) // all + { + for (int i = inv.size(); i >= 0; i--) + dropItemFromSlot(i, dropAll); + } + else // one slot + { + if (selectedSlot == -1) + selectedSlot = inv.selectedSlot; + dropItemFromSlot(selectedSlot, dropAll); + } + } + + public void setSlot(int slot) + { + player.getInventory().selectedSlot = slot-1; + player.networkHandler.sendPacket(new UpdateSelectedSlotS2CPacket(slot-1)); + } + + public enum ActionType + { + USE(true) + { + @Override + boolean execute(ServerPlayerEntity player, Action action) + { + EntityPlayerActionPack ap = ((ServerPlayerInterface) player).getActionPack(); + if (ap.itemUseCooldown > 0) + { + ap.itemUseCooldown--; + return true; + } + if (player.isUsingItem()) + { + return true; + } + HitResult hit = getTarget(player); + for (Hand hand : Hand.values()) + { + switch (hit.getType()) + { + case BLOCK: + { + player.updateLastActionTime(); + ServerWorld world = player.getServerWorld(); + BlockHitResult blockHit = (BlockHitResult) hit; + BlockPos pos = blockHit.getBlockPos(); + Direction side = blockHit.getSide(); + if (pos.getY() < player.getWorld().getTopY() - (side == Direction.UP ? 1 : 0) && world.canPlayerModifyAt(player, pos)) + { + ActionResult result = player.interactionManager.interactBlock(player, world, player.getStackInHand(hand), hand, blockHit); + if (result.isAccepted()) + { + if (result.shouldSwingHand()) player.swingHand(hand); + ap.itemUseCooldown = 3; + return true; + } + } + break; + } + case ENTITY: + { + player.updateLastActionTime(); + EntityHitResult entityHit = (EntityHitResult) hit; + Entity entity = entityHit.getEntity(); + boolean handWasEmpty = player.getStackInHand(hand).isEmpty(); + boolean itemFrameEmpty = (entity instanceof ItemFrameEntity) && ((ItemFrameEntity) entity).getHeldItemStack().isEmpty(); + Vec3d relativeHitPos = entityHit.getPos().subtract(entity.getX(), entity.getY(), entity.getZ()); + if (entity.interactAt(player, relativeHitPos, hand).isAccepted()) + { + ap.itemUseCooldown = 3; + return true; + } + // fix for SS itemframe always returns CONSUME even if no action is performed + if (player.interact(entity, hand).isAccepted() && !(handWasEmpty && itemFrameEmpty)) + { + ap.itemUseCooldown = 3; + return true; + } + break; + } + } + ItemStack handItem = player.getStackInHand(hand); + if (player.interactionManager.interactItem(player, player.getWorld(), handItem, hand).isAccepted()) + { + ap.itemUseCooldown = 3; + return true; + } + } + return false; + } + + @Override + void inactiveTick(ServerPlayerEntity player, Action action) + { + EntityPlayerActionPack ap = ((ServerPlayerInterface) player).getActionPack(); + ap.itemUseCooldown = 0; + player.stopUsingItem(); + } + }, + ATTACK(true) { + @Override + boolean execute(ServerPlayerEntity player, Action action) { + HitResult hit = getTarget(player); + switch (hit.getType()) { + case ENTITY: { + EntityHitResult entityHit = (EntityHitResult) hit; + if (!action.isContinuous) + { + player.attack(entityHit.getEntity()); + player.swingHand(Hand.MAIN_HAND); + } + player.resetLastAttackedTicks(); + player.updateLastActionTime(); + return true; + } + case BLOCK: { + EntityPlayerActionPack ap = ((ServerPlayerInterface) player).getActionPack(); + if (ap.blockHitDelay > 0) + { + ap.blockHitDelay--; + return false; + } + BlockHitResult blockHit = (BlockHitResult) hit; + BlockPos pos = blockHit.getBlockPos(); + Direction side = blockHit.getSide(); + if (player.isBlockBreakingRestricted(player.getWorld(), pos, player.interactionManager.getGameMode())) return false; + if (ap.currentBlock != null && player.getWorld().getBlockState(ap.currentBlock).isAir()) + { + ap.currentBlock = null; + return false; + } + BlockState state = player.getWorld().getBlockState(pos); + boolean blockBroken = false; + if (player.interactionManager.getGameMode().isCreative()) + { + player.interactionManager.processBlockBreakingAction(pos, PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, side, player.getWorld().getTopY(), -1); + ap.blockHitDelay = 5; + blockBroken = true; + } + else if (ap.currentBlock == null || !ap.currentBlock.equals(pos)) + { + if (ap.currentBlock != null) + { + player.interactionManager.processBlockBreakingAction(ap.currentBlock, PlayerActionC2SPacket.Action.ABORT_DESTROY_BLOCK, side, player.getWorld().getTopY(), -1); + } + player.interactionManager.processBlockBreakingAction(pos, PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, side, player.getWorld().getTopY(), -1); + boolean notAir = !state.isAir(); + if (notAir && ap.curBlockDamageMP == 0) + { + state.onBlockBreakStart(player.getWorld(), pos, player); + } + if (notAir && state.calcBlockBreakingDelta(player, player.getWorld(), pos) >= 1) + { + ap.currentBlock = null; + //instamine?? + blockBroken = true; + } + else + { + ap.currentBlock = pos; + ap.curBlockDamageMP = 0; + } + } + else + { + ap.curBlockDamageMP += state.calcBlockBreakingDelta(player, player.getWorld(), pos); + if (ap.curBlockDamageMP >= 1) + { + player.interactionManager.processBlockBreakingAction(pos, PlayerActionC2SPacket.Action.STOP_DESTROY_BLOCK, side, player.getWorld().getTopY(), -1); + ap.currentBlock = null; + ap.blockHitDelay = 5; + blockBroken = true; + } + player.getWorld().setBlockBreakingInfo(-1, pos, (int) (ap.curBlockDamageMP * 10)); + + } + player.updateLastActionTime(); + player.swingHand(Hand.MAIN_HAND); + return blockBroken; + } + } + return false; + } + + @Override + void inactiveTick(ServerPlayerEntity player, Action action) + { + EntityPlayerActionPack ap = ((ServerPlayerInterface) player).getActionPack(); + if (ap.currentBlock == null) return; + player.getWorld().setBlockBreakingInfo(-1, ap.currentBlock, -1); + player.interactionManager.processBlockBreakingAction(ap.currentBlock, PlayerActionC2SPacket.Action.ABORT_DESTROY_BLOCK, Direction.DOWN, player.getWorld().getTopY(), -1); + ap.currentBlock = null; + } + }, + JUMP(true) + { + @Override + boolean execute(ServerPlayerEntity player, Action action) + { + if (action.limit == 1) + { + if (player.isOnGround()) player.jump(); // onGround + } + else + { + player.setJumping(true); + } + return false; + } + + @Override + void inactiveTick(ServerPlayerEntity player, Action action) + { + player.setJumping(false); + } + }, + DROP_ITEM(true) + { + @Override + boolean execute(ServerPlayerEntity player, Action action) + { + player.updateLastActionTime(); + player.dropSelectedItem(false); // dropSelectedItem + return false; + } + }, + DROP_STACK(true) + { + @Override + boolean execute(ServerPlayerEntity player, Action action) + { + player.updateLastActionTime(); + player.dropSelectedItem(true); // dropSelectedItem + return false; + } + }, + SWAP_HANDS(true) + { + @Override + boolean execute(ServerPlayerEntity player, Action action) + { + player.updateLastActionTime(); + ItemStack itemStack_1 = player.getStackInHand(Hand.OFF_HAND); + player.setStackInHand(Hand.OFF_HAND, player.getStackInHand(Hand.MAIN_HAND)); + player.setStackInHand(Hand.MAIN_HAND, itemStack_1); + return false; + } + }; + + public final boolean preventSpectator; + + ActionType(boolean preventSpectator) + { + this.preventSpectator = preventSpectator; + } + + void start(ServerPlayerEntity player, Action action) {} + abstract boolean execute(ServerPlayerEntity player, Action action); + void inactiveTick(ServerPlayerEntity player, Action action) {} + void stop(ServerPlayerEntity player, Action action) + { + inactiveTick(player, action); + } + } + + public static class Action + { + public boolean done = false; + public final int limit; + public final int interval; + public final int offset; + private int count; + private int next; + private final boolean isContinuous; + + private Action(int limit, int interval, int offset, boolean continuous) + { + this.limit = limit; + this.interval = interval; + this.offset = offset; + next = interval + offset; + isContinuous = continuous; + } + + public static Action once() + { + return new Action(1, 1, 0, false); + } + + public static Action continuous() + { + return new Action(-1, 1, 0, true); + } + + public static Action interval(int interval) + { + return new Action(-1, interval, 0, false); + } + + public static Action interval(int interval, int offset) + { + return new Action(-1, interval, offset, false); + } + + Boolean tick(EntityPlayerActionPack actionPack, ActionType type) + { + next--; + Boolean cancel = null; + if (next <= 0) + { + if (interval == 1 && !isContinuous) + { + // need to allow entity to tick, otherwise won't have effect (bow) + // actions are 20 tps, so need to clear status mid tick, allowing entities process it till next time + if (!type.preventSpectator || !actionPack.player.isSpectator()) + { + type.inactiveTick(actionPack.player, this); + } + } + + if (!type.preventSpectator || !actionPack.player.isSpectator()) + { + cancel = type.execute(actionPack.player, this); + } + count++; + if (count == limit) + { + type.stop(actionPack.player, null); + done = true; + return cancel; + } + next = interval; + } + else + { + if (!type.preventSpectator || !actionPack.player.isSpectator()) + { + type.inactiveTick(actionPack.player, this); + } + } + return cancel; + } + + void retry(EntityPlayerActionPack actionPack, ActionType type) + { + //assuming action run but was unsuccesful that tick, but opportunity emerged to retry it, lets retry it. + if (!type.preventSpectator || !actionPack.player.isSpectator()) + { + type.execute(actionPack.player, this); + } + count++; + if (count == limit) + { + type.stop(actionPack.player, null); + done = true; + } + } + } +} diff --git a/src/main/java/io/github/skippyall/minions/fakeplayer/FakeClientConnection.java b/src/main/java/io/github/skippyall/minions/fakeplayer/FakeClientConnection.java new file mode 100644 index 0000000..9fe28ef --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/fakeplayer/FakeClientConnection.java @@ -0,0 +1,37 @@ +package io.github.skippyall.minions.fakeplayer; + +import io.netty.channel.embedded.EmbeddedChannel; +import net.minecraft.network.ClientConnection; +import net.minecraft.network.NetworkSide; +import net.minecraft.network.listener.PacketListener; +import net.minecraft.text.Text; + +public class FakeClientConnection extends ClientConnection { + public FakeClientConnection(NetworkSide p) + { + super(p); + // compat with adventure-platform-fabric. This does NOT trigger other vanilla handlers for establishing a channel + // also makes #isOpen return true, allowing enderpearls to teleport fake players + ((ClientConnectionInterface)this).setChannel(new EmbeddedChannel()); + } + + @Override + public void tryDisableAutoRead() + { + } + + @Override + public void handleDisconnection() { + getPacketListener().onDisconnected(getDisconnectReason()==null ? Text.literal("Disconnected"): getDisconnectReason()); + } + + @Override + public void setInitialPacketListener(PacketListener packetListener) + { + } + + @Override + public void setPacketListener(PacketListener packetListener) { + + } +} diff --git a/src/main/java/io/github/skippyall/minions/fakeplayer/MinionFakePlayer.java b/src/main/java/io/github/skippyall/minions/fakeplayer/MinionFakePlayer.java new file mode 100644 index 0000000..d6377b7 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/fakeplayer/MinionFakePlayer.java @@ -0,0 +1,277 @@ +package io.github.skippyall.minions.fakeplayer; + +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.yggdrasil.ProfileResult; +import io.github.skippyall.minions.minion.MinionInventory; +import io.github.skippyall.minions.minion.ModuleInventory; +import net.fabricmc.fabric.api.entity.FakePlayer; +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.MovementType; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.player.HungerManager; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.network.NetworkSide; +import net.minecraft.network.packet.c2s.common.SyncedClientOptions; +import net.minecraft.network.packet.c2s.play.ClientStatusC2SPacket; +import net.minecraft.network.packet.s2c.play.EntityPositionS2CPacket; +import net.minecraft.network.packet.s2c.play.EntitySetHeadYawS2CPacket; +import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.ServerTask; +import net.minecraft.server.network.ConnectedClientData; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableTextContent; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.Uuids; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.GameMode; +import java.util.UUID; + +public class MinionFakePlayer extends ServerPlayerEntity { + public Runnable fixStartingPosition = () -> {}; + public boolean isAShadow; + + private float moveForward; + private float moveSideways; + + private boolean programmable; + private ModuleInventory moduleInventory = new ModuleInventory(); + + public static void createMinion(String username, ServerWorld level, ServerPlayerEntity owner, boolean canProgram, Vec3d pos, double yaw, double pitch) { + MinecraftServer server = level.getServer(); + server.getUserCache().findByNameAsync(username).thenAcceptAsync((optional) -> { + GameProfile profile = null; + if(optional.isPresent()){ + UUID uuid = optional.get().getId(); + ProfileResult result = server.getSessionService().fetchProfile(uuid, true); + if(result != null) { + profile = result.profile(); + } + } + if(profile == null) { + profile = new GameProfile(Uuids.getOfflinePlayerUuid(username), username); + } + MinionFakePlayer instance = new MinionFakePlayer(server, level, profile, SyncedClientOptions.createDefault(), false, canProgram); + instance.fixStartingPosition = () -> instance.refreshPositionAndAngles(pos.x, pos.y, pos.z, (float) yaw, (float) pitch); + server.getPlayerManager().onPlayerConnect(new FakeClientConnection(NetworkSide.SERVERBOUND), instance, new ConnectedClientData(profile, 0, instance.getClientOptions())); + instance.teleport(level, pos.x, pos.y, pos.z, (float) yaw, (float) pitch); + instance.setHealth(20.0F); + instance.unsetRemoved(); + instance.interactionManager.changeGameMode(GameMode.SURVIVAL); + server.getPlayerManager().sendToDimension(new EntitySetHeadYawS2CPacket(instance, (byte) (instance.headYaw * 256 / 360)), level.getRegistryKey());//instance.dimension); + server.getPlayerManager().sendToDimension(new EntityPositionS2CPacket(instance), level.getRegistryKey());//instance.dimension); + //instance.world.getChunkManager(). updatePosition(instance); + instance.dataTracker.set(PLAYER_MODEL_PARTS, (byte) 0x7f); // show all model layers (incl. capes) + instance.getAbilities().flying = false; + instance.setStepHeight(0.6F); + }); + + + } + + @SuppressWarnings("unused") //Don't know if I'll need this + public static MinionFakePlayer createShadow(MinecraftServer server, ServerPlayerEntity player) + { + player.getServer().getPlayerManager().remove(player); + player.networkHandler.disconnect(Text.translatable("multiplayer.disconnect.duplicate_login")); + ServerWorld worldIn = player.getServerWorld();//.getWorld(player.dimension); + GameProfile gameprofile = player.getGameProfile(); + MinionFakePlayer playerShadow = new MinionFakePlayer(server, worldIn, gameprofile, player.getClientOptions(), true, false); + playerShadow.setSession(player.getSession()); + server.getPlayerManager().onPlayerConnect(new FakeClientConnection(NetworkSide.SERVERBOUND), playerShadow, new ConnectedClientData(gameprofile, 0, player.getClientOptions())); + + playerShadow.setHealth(player.getHealth()); + playerShadow.networkHandler.requestTeleport(player.getX(), player.getY(), player.getZ(), player.getYaw(), player.getPitch()); + playerShadow.interactionManager.changeGameMode(player.interactionManager.getGameMode()); + ((ServerPlayerInterface) playerShadow).getActionPack().copyFrom(((ServerPlayerInterface) player).getActionPack()); + playerShadow.dataTracker.set(PLAYER_MODEL_PARTS, player.getDataTracker().get(PLAYER_MODEL_PARTS)); + + + server.getPlayerManager().sendToDimension(new EntitySetHeadYawS2CPacket(playerShadow, (byte) (player.headYaw * 256 / 360)), playerShadow.getWorld().getRegistryKey()); + server.getPlayerManager().sendToAll(new PlayerListS2CPacket(PlayerListS2CPacket.Action.ADD_PLAYER, playerShadow)); + //player.world.getChunkManager().updatePosition(playerShadow); + playerShadow.getAbilities().flying = player.getAbilities().flying; + return playerShadow; + } + + public static MinionFakePlayer respawnFake(MinecraftServer server, ServerWorld level, GameProfile profile, SyncedClientOptions cli, boolean programmable) + { + return new MinionFakePlayer(server, level, profile, cli, false, programmable); + } + + private MinionFakePlayer(MinecraftServer server, ServerWorld worldIn, GameProfile profile, SyncedClientOptions cli, boolean shadow, boolean programmable) + { + super(server, worldIn, profile, cli); + isAShadow = shadow; + + } + + public boolean isProgrammable() { + return programmable; + } + + public ModuleInventory getModuleInventory() { + return moduleInventory; + } + + public EntityPlayerActionPack getActionPack() { + return ((ServerPlayerInterface)this).getActionPack(); + } + + @Override + public ActionResult interact(PlayerEntity player, Hand hand) { + if(player instanceof ServerPlayerEntity spe) { + MinionInventory.openInventory(spe, this); + } + return ActionResult.CONSUME; + } + + @Override + public ActionResult interactAt(PlayerEntity player, Vec3d hitPos, Hand hand) { + return interact(player, hand); + } + + @Override + public void onEquipStack(final EquipmentSlot slot, final ItemStack previous, final ItemStack stack) + { + if (!isUsingItem()) super.onEquipStack(slot, previous, stack); + } + + @Override + public void kill() + { + kill(Text.literal("Killed")); + } + + public void kill(Text reason) + { + shakeOff(); + + if (reason.getContent() instanceof TranslatableTextContent text && text.getKey().equals("multiplayer.disconnect.duplicate_login")) { + this.networkHandler.onDisconnected(reason); + } else { + this.server.send(new ServerTask(this.server.getTicks(), () -> { + this.networkHandler.onDisconnected(reason); + })); + } + } + + @Override + public void tick() + { + if (this.getServer().getTicks() % 10 == 0) + { + this.networkHandler.syncWithPlayerPosition(); + this.getServerWorld().getChunkManager().updatePosition(this); + } + try + { + super.tick(); + this.playerTick(); + } + catch (NullPointerException ignored) + { + // happens with that paper port thingy - not sure what that would fix, but hey + // the game not gonna crash violently. + } + + + } + + private void shakeOff() + { + if (getVehicle() instanceof PlayerEntity) stopRiding(); + for (Entity passenger : getPassengersDeep()) + { + if (passenger instanceof PlayerEntity) passenger.stopRiding(); + } + } + + @Override + public void onDeath(DamageSource cause) + { + shakeOff(); + super.onDeath(cause); + setHealth(20); + this.hungerManager = new HungerManager(); + kill(this.getDamageTracker().getDeathMessage()); + } + + @Override + public String getIp() + { + return "127.0.0.1"; + } + + @Override + public boolean allowsServerListing() { + return false; + } + + @Override + protected void fall(double y, boolean onGround, BlockState state, BlockPos pos) { + handleFall(0.0, y, 0.0, onGround); + } + + @Override + public Entity moveToWorld(ServerWorld serverLevel) + { + super.moveToWorld(serverLevel); + if (notInAnyWorld) { + ClientStatusC2SPacket p = new ClientStatusC2SPacket(ClientStatusC2SPacket.Mode.PERFORM_RESPAWN); + networkHandler.onClientStatus(p); + } + + // If above branch was taken, *this* has been removed and replaced, the new instance has been set + // on 'our' connection (which is now theirs, but we still have a ref). + if (networkHandler.player.isInTeleportationState()) { + networkHandler.player.onTeleportationDone(); + } + return networkHandler.player; + } + + public void moveForward(float forward) { + this.moveForward += forward; + EntityPlayerActionPack actionPack = getActionPack(); + if (moveForward != 0) { + actionPack.setForward(moveForward > 0 ? 1 : -1); + } + } + + public void moveSideways(float sideways) { + this.moveSideways += sideways; + EntityPlayerActionPack actionPack = getActionPack(); + if (moveSideways != 0) { + actionPack.setStrafing(moveSideways > 0 ? 1 : -1); + } + } + + @Override + public void move(MovementType movementType, Vec3d movement) { + float newForward = (float) (moveForward - movement.z); + float newSideways = (float) (moveSideways - movement.x); + Vec3d newMovement = movement; + if ((newForward < 0 && moveForward >= 0) || (newForward > 0 && moveForward <= 0)) { + newMovement = new Vec3d(newMovement.x, newMovement.y, moveForward); + moveForward = 0; + getActionPack().setForward(0); + }else { + moveForward = newForward; + } + if ((newSideways < 0 && moveSideways >= 0) || (newSideways > 0 && moveSideways <= 0)) { + newMovement = new Vec3d(newMovement.x, newMovement.y, moveSideways); + moveSideways = 0; + getActionPack().setStrafing(0); + }else { + moveSideways = newSideways; + } + super.move(movementType, newMovement); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/fakeplayer/NetHandlerPlayServerFake.java b/src/main/java/io/github/skippyall/minions/fakeplayer/NetHandlerPlayServerFake.java new file mode 100644 index 0000000..6db7a61 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/fakeplayer/NetHandlerPlayServerFake.java @@ -0,0 +1,45 @@ +package io.github.skippyall.minions.fakeplayer; + +import net.minecraft.network.ClientConnection; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.s2c.play.PositionFlag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ConnectedClientData; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableTextContent; +import java.util.Set; + +public class NetHandlerPlayServerFake extends ServerPlayNetworkHandler +{ + public NetHandlerPlayServerFake(final MinecraftServer minecraftServer, final ClientConnection connection, final ServerPlayerEntity serverPlayer, final ConnectedClientData i) + { + super(minecraftServer, connection, serverPlayer, i); + } + + @Override + public void sendPacket(final Packet packetIn) + { + } + + @Override + public void disconnect(Text message) + { + if (message.getContent() instanceof TranslatableTextContent text && (text.getKey().equals("multiplayer.disconnect.idling") || text.getKey().equals("multiplayer.disconnect.duplicate_login"))) + { + ((MinionFakePlayer) player).kill(message); + } + } + + @Override + public void requestTeleport(double d, double e, double f, float g, float h, Set set) + { + super.requestTeleport(d, e, f, g, h, set); + if (player.getServerWorld().getPlayerByUuid(player.getUuid()) != null) { + syncWithPlayerPosition(); + player.getServerWorld().getChunkManager().updatePosition(player); + } + } + +} diff --git a/src/main/java/io/github/skippyall/minions/fakeplayer/ServerPlayerInterface.java b/src/main/java/io/github/skippyall/minions/fakeplayer/ServerPlayerInterface.java new file mode 100644 index 0000000..f75600d --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/fakeplayer/ServerPlayerInterface.java @@ -0,0 +1,8 @@ +package io.github.skippyall.minions.fakeplayer; + +import io.github.skippyall.minions.fakeplayer.EntityPlayerActionPack; + +public interface ServerPlayerInterface +{ + EntityPlayerActionPack getActionPack(); +} diff --git a/src/main/java/io/github/skippyall/minions/fakeplayer/Tracer.java b/src/main/java/io/github/skippyall/minions/fakeplayer/Tracer.java new file mode 100644 index 0000000..c4cd9fe --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/fakeplayer/Tracer.java @@ -0,0 +1,89 @@ +package io.github.skippyall.minions.fakeplayer; + +import java.util.Optional; +import java.util.function.Predicate; +import net.minecraft.entity.Entity; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.RaycastContext; +import net.minecraft.world.World; + +public class Tracer +{ + public static HitResult rayTrace(Entity source, float partialTicks, double reach, boolean fluids) + { + BlockHitResult blockHit = rayTraceBlocks(source, partialTicks, reach, fluids); + double maxSqDist = reach * reach; + if (blockHit != null) + { + maxSqDist = blockHit.getPos().squaredDistanceTo(source.getCameraPosVec(partialTicks)); + } + EntityHitResult entityHit = rayTraceEntities(source, partialTicks, reach, maxSqDist); + return entityHit == null ? blockHit : entityHit; + } + + public static BlockHitResult rayTraceBlocks(Entity source, float partialTicks, double reach, boolean fluids) + { + Vec3d pos = source.getCameraPosVec(partialTicks); + Vec3d rotation = source.getRotationVec(partialTicks); + Vec3d reachEnd = pos.add(rotation.x * reach, rotation.y * reach, rotation.z * reach); + return source.getWorld().raycast(new RaycastContext(pos, reachEnd, RaycastContext.ShapeType.OUTLINE, fluids ? + RaycastContext.FluidHandling.ANY : RaycastContext.FluidHandling.NONE, source)); + } + + public static EntityHitResult rayTraceEntities(Entity source, float partialTicks, double reach, double maxSqDist) + { + Vec3d pos = source.getCameraPosVec(partialTicks); + Vec3d reachVec = source.getRotationVec(partialTicks).multiply(reach); + Box box = source.getBoundingBox().stretch(reachVec).expand(1); + return rayTraceEntities(source, pos, pos.add(reachVec), box, e -> !e.isSpectator() && e.canHit(), maxSqDist); + } + + public static EntityHitResult rayTraceEntities(Entity source, Vec3d start, Vec3d end, Box box, Predicate predicate, double maxSqDistance) + { + World world = source.getWorld(); + double targetDistance = maxSqDistance; + Entity target = null; + Vec3d targetHitPos = null; + for (Entity current : world.getOtherEntities(source, box, predicate)) + { + Box currentBox = current.getBoundingBox().expand(current.getTargetingMargin()); + Optional currentHit = currentBox.raycast(start, end); + if (currentBox.contains(start)) + { + if (targetDistance >= 0) + { + target = current; + targetHitPos = currentHit.orElse(start); + targetDistance = 0; + } + } + else if (currentHit.isPresent()) + { + Vec3d currentHitPos = currentHit.get(); + double currentDistance = start.squaredDistanceTo(currentHitPos); + if (currentDistance < targetDistance || targetDistance == 0) + { + if (current.getRootVehicle() == source.getRootVehicle()) + { + if (targetDistance == 0) + { + target = current; + targetHitPos = currentHitPos; + } + } + else + { + target = current; + targetHitPos = currentHitPos; + targetDistance = currentDistance; + } + } + } + } + return target == null ? null : new EntityHitResult(target, targetHitPos); + } +} diff --git a/src/main/java/io/github/skippyall/minions/minion/ImplementedInventory.java b/src/main/java/io/github/skippyall/minions/minion/ImplementedInventory.java new file mode 100644 index 0000000..ec59747 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/minion/ImplementedInventory.java @@ -0,0 +1,132 @@ +package io.github.skippyall.minions.minion; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.Inventories; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.collection.DefaultedList; + +/** + * A simple {@code Inventory} implementation with only default methods + an item list getter. + * + * Originally by Juuz + */ +public interface ImplementedInventory extends Inventory { + + /** + * Retrieves the item list of this inventory. + * Must return the same instance every time it's called. + */ + DefaultedList getItems(); + + /** + * Creates an inventory from the item list. + */ + static ImplementedInventory of(DefaultedList items) { + return () -> items; + } + + /** + * Creates a new inventory with the specified size. + */ + static ImplementedInventory ofSize(int size) { + return of(DefaultedList.ofSize(size, ItemStack.EMPTY)); + } + + /** + * Returns the inventory size. + */ + @Override + default int size() { + return getItems().size(); + } + + /** + * Checks if the inventory is empty. + * @return true if this inventory has only empty stacks, false otherwise. + */ + @Override + default boolean isEmpty() { + for (int i = 0; i < size(); i++) { + ItemStack stack = getStack(i); + if (!stack.isEmpty()) { + return false; + } + } + return true; + } + + /** + * Retrieves the item in the slot. + */ + @Override + default ItemStack getStack(int slot) { + return getItems().get(slot); + } + + /** + * Removes items from an inventory slot. + * @param slot The slot to remove from. + * @param count How many items to remove. If there are less items in the slot than what are requested, + * takes all items in that slot. + */ + @Override + default ItemStack removeStack(int slot, int count) { + ItemStack result = Inventories.splitStack(getItems(), slot, count); + if (!result.isEmpty()) { + markDirty(); + } + return result; + } + + /** + * Removes all items from an inventory slot. + * @param slot The slot to remove from. + */ + @Override + default ItemStack removeStack(int slot) { + return Inventories.removeStack(getItems(), slot); + } + + /** + * Replaces the current stack in an inventory slot with the provided stack. + * @param slot The inventory slot of which to replace the itemstack. + * @param stack The replacing itemstack. If the stack is too big for + * this inventory ({@link Inventory#getMaxCountPerStack()}), + * it gets resized to this inventory's maximum amount. + */ + @Override + default void setStack(int slot, ItemStack stack) { + getItems().set(slot, stack); + if (stack.getCount() > stack.getMaxCount()) { + stack.setCount(stack.getMaxCount()); + } + } + + /** + * Clears the inventory. + */ + @Override + default void clear() { + getItems().clear(); + } + + /** + * Marks the state as dirty. + * Must be called after changes in the inventory, so that the game can properly save + * the inventory contents and notify neighboring blocks of inventory changes. + */ + @Override + default void markDirty() { + // Override if you want behavior. + } + + /** + * @return true if the player can use the inventory, false otherwise. + */ + @Override + default boolean canPlayerUse(PlayerEntity player) { + return true; + } +} + diff --git a/src/main/java/io/github/skippyall/minions/minion/MinionInventory.java b/src/main/java/io/github/skippyall/minions/minion/MinionInventory.java new file mode 100644 index 0000000..827aa29 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/minion/MinionInventory.java @@ -0,0 +1,62 @@ +package io.github.skippyall.minions.minion; + +import eu.pb4.sgui.api.elements.GuiElementBuilder; +import eu.pb4.sgui.api.gui.SimpleGui; +import io.github.skippyall.minions.fakeplayer.MinionFakePlayer; +import net.minecraft.item.Items; +import net.minecraft.screen.GenericContainerScreenHandler; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.screen.SimpleNamedScreenHandlerFactory; +import net.minecraft.screen.slot.Slot; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; + +public class MinionInventory { + public static void openInventory(ServerPlayerEntity player, MinionFakePlayer minion) { + openServerSideInventory(player, minion); + } + + public static void openServerSideInventory(ServerPlayerEntity player, MinionFakePlayer minion) { + SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_3X3, player, false); + gui.setTitle(Text.literal("Minion")); + gui.setSlot(4, new GuiElementBuilder() + .setItem(Items.REDSTONE) + .setName(Text.literal("Programming")) + .setCallback((i, clickType, clickType1) -> { + openProgrammingInventory(player, minion); + }) + ); + gui.setSlot(3, new GuiElementBuilder() + .setItem(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE) + .setName(Text.literal("Modules and Detectors")) + .setCallback((i, clickType, clickType1) -> { + openModuleInventory(player, minion); + }) + ); + gui.setSlot(5, new GuiElementBuilder() + .setItem(Items.CHEST) + .setName(Text.literal("Inventory")) + .setCallback((i, clickType, clickType1) -> { + openMinionInventory(player, minion); + }) + ); + gui.open(); + } + + public static void openProgrammingInventory(ServerPlayerEntity player, MinionFakePlayer minion) { + + } + + public static void openModuleInventory(ServerPlayerEntity player, MinionFakePlayer minion) { + player.openHandledScreen(new SimpleNamedScreenHandlerFactory((syncId, playerInventory, player2) -> GenericContainerScreenHandler.createGeneric9x3(syncId, playerInventory, minion.getModuleInventory()), Text.literal(""))); + } + + public static void openMinionInventory(ServerPlayerEntity player, MinionFakePlayer minion) { + SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_9X5, player, false); + gui.setTitle(Text.literal("Minion")); + for (int i = 0; i < minion.getInventory().size(); i++) { + gui.setSlotRedirect(i, new Slot(minion.getInventory(), i, 0, 0)); + } + gui.open(); + } +} diff --git a/src/main/java/io/github/skippyall/minions/minion/MinionItem.java b/src/main/java/io/github/skippyall/minions/minion/MinionItem.java new file mode 100644 index 0000000..2c1f807 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/minion/MinionItem.java @@ -0,0 +1,50 @@ +package io.github.skippyall.minions.minion; + +import eu.pb4.polymer.core.api.item.PolymerItem; +import eu.pb4.polymer.core.api.item.PolymerItemUtils; +import io.github.skippyall.minions.fakeplayer.MinionFakePlayer; +import net.fabricmc.fabric.api.item.v1.FabricItemSettings; +import net.minecraft.client.item.TooltipContext; +import net.minecraft.enchantment.Enchantments; +import net.minecraft.item.*; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.PlainTextContent; +import net.minecraft.text.TextContent; +import net.minecraft.util.ActionResult; +import org.jetbrains.annotations.Nullable; + +public class MinionItem extends Item implements PolymerItem { + private boolean canProgram; + public MinionItem(boolean canProgram) { + super(new FabricItemSettings()); + } + + @Override + public Item getPolymerItem(ItemStack itemStack, @Nullable ServerPlayerEntity player) { + return Items.ARMOR_STAND; + } + + @Override + public ItemStack getPolymerItemStack(ItemStack stack, TooltipContext flag, ServerPlayerEntity player) { + ItemStack out = PolymerItemUtils.createItemStack(stack, flag, player); + out.addEnchantment(Enchantments.MENDING, 1); + return out; + } + + @Override + public ActionResult useOnBlock(ItemUsageContext context) { + String contents = context.getStack().getName().getLiteralString(); + String name; + if(contents != null) { + name = contents; + } else { + name = "Minion"; + } + if(!context.getWorld().isClient) { + MinionFakePlayer.createMinion(name, (ServerWorld) context.getWorld(), (ServerPlayerEntity) context.getPlayer(), canProgram, context.getBlockPos().toCenterPos().add(0,0.5,0), 0, 0); + } + return ActionResult.SUCCESS; + } +} diff --git a/src/main/java/io/github/skippyall/minions/minion/ModuleInventory.java b/src/main/java/io/github/skippyall/minions/minion/ModuleInventory.java new file mode 100644 index 0000000..0f6284c --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/minion/ModuleInventory.java @@ -0,0 +1,42 @@ +package io.github.skippyall.minions.minion; + +import io.github.skippyall.minions.Minions; +import net.minecraft.inventory.Inventories; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.tag.TagKey; +import net.minecraft.util.Identifier; +import net.minecraft.util.collection.DefaultedList; + +public class ModuleInventory implements ImplementedInventory { + private static final TagKey MODULES = TagKey.of(RegistryKeys.ITEM, new Identifier(Minions.MOD_ID,"modules")); + private DefaultedList stacks = DefaultedList.ofSize(27, ItemStack.EMPTY); + + public ModuleInventory() { + } + + @Override + public int getMaxCountPerStack() { + return 1; + } + + @Override + public boolean isValid(int slot, ItemStack stack) { + return (stack.getCount() <= getMaxCountPerStack()) && stack.isIn(MODULES); + } + + @Override + public DefaultedList getItems() { + return stacks; + } + + public void readNbt(NbtCompound nbt) { + Inventories.readNbt(nbt, stacks); + } + + public void writeNbt(NbtCompound nbt) { + Inventories.writeNbt(nbt, stacks); + } +} diff --git a/src/main/java/io/github/skippyall/minions/mixins/ConnectionMixin.java b/src/main/java/io/github/skippyall/minions/mixins/ConnectionMixin.java new file mode 100644 index 0000000..d967ef2 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/mixins/ConnectionMixin.java @@ -0,0 +1,14 @@ +package io.github.skippyall.minions.mixins; + +import io.github.skippyall.minions.fakeplayer.ClientConnectionInterface; +import io.netty.channel.Channel; +import net.minecraft.network.ClientConnection; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ClientConnection.class) +public abstract class ConnectionMixin implements ClientConnectionInterface { + @Override + @Accessor //Compat with adventure-platform-fabric + public abstract void setChannel(Channel channel); +} diff --git a/src/main/java/io/github/skippyall/minions/mixins/PlayerListMixin.java b/src/main/java/io/github/skippyall/minions/mixins/PlayerListMixin.java new file mode 100644 index 0000000..6ca61a0 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/mixins/PlayerListMixin.java @@ -0,0 +1,53 @@ +package io.github.skippyall.minions.mixins; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.mojang.authlib.GameProfile; +import io.github.skippyall.minions.fakeplayer.MinionFakePlayer; +import io.github.skippyall.minions.fakeplayer.NetHandlerPlayServerFake; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.network.ClientConnection; +import net.minecraft.network.packet.c2s.common.SyncedClientOptions; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.PlayerManager; +import net.minecraft.server.network.ConnectedClientData; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(PlayerManager.class) +public class PlayerListMixin { + + @Inject(method = "loadPlayerData", at = @At(value = "RETURN", shift = At.Shift.BEFORE)) + private void fixStartingPos(ServerPlayerEntity serverPlayerEntity_1, CallbackInfoReturnable cir) + { + if (serverPlayerEntity_1 instanceof MinionFakePlayer) + { + ((MinionFakePlayer) serverPlayerEntity_1).fixStartingPosition.run(); + } + } + + @WrapOperation(method = "onPlayerConnect", at = @At(value = "NEW", target = "(Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/network/ClientConnection;Lnet/minecraft/server/network/ServerPlayerEntity;Lnet/minecraft/server/network/ConnectedClientData;)Lnet/minecraft/server/network/ServerPlayNetworkHandler;")) + private ServerPlayNetworkHandler replaceNetworkHandler(MinecraftServer server, ClientConnection connection, ServerPlayerEntity serverPlayer, ConnectedClientData commonListenerCookie, Operation original) + { + if (serverPlayer instanceof MinionFakePlayer fake) { + return new NetHandlerPlayServerFake(server, connection, fake, commonListenerCookie); + } else { + return original.call(server, connection, serverPlayer, commonListenerCookie); + } + } + + @WrapOperation(method = "respawnPlayer", at = @At(value = "NEW", target = "(Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/server/world/ServerWorld;Lcom/mojang/authlib/GameProfile;Lnet/minecraft/network/packet/c2s/common/SyncedClientOptions;)Lnet/minecraft/server/network/ServerPlayerEntity;")) + public ServerPlayerEntity makePlayerForRespawn(MinecraftServer minecraftServer, ServerWorld serverLevel, GameProfile gameProfile, SyncedClientOptions clientInformation, Operation original, ServerPlayerEntity serverPlayer, boolean bl) { + if (serverPlayer instanceof MinionFakePlayer minion) { + return MinionFakePlayer.respawnFake(minecraftServer, serverLevel, gameProfile, clientInformation, minion.isProgrammable()); + } + return original.call(minecraftServer, serverLevel, gameProfile, clientInformation); + } +} diff --git a/src/main/java/io/github/skippyall/minions/mixins/ServerPlayerMixin.java b/src/main/java/io/github/skippyall/minions/mixins/ServerPlayerMixin.java new file mode 100644 index 0000000..c6d7275 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/mixins/ServerPlayerMixin.java @@ -0,0 +1,37 @@ +package io.github.skippyall.minions.mixins; + +import com.mojang.authlib.GameProfile; +import io.github.skippyall.minions.fakeplayer.EntityPlayerActionPack; +import io.github.skippyall.minions.fakeplayer.ServerPlayerInterface; +import net.minecraft.network.packet.c2s.common.SyncedClientOptions; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ServerPlayerEntity.class) +public abstract class ServerPlayerMixin implements ServerPlayerInterface { + @Unique + public EntityPlayerActionPack actionPack; + @Override + public EntityPlayerActionPack getActionPack() + { + return actionPack; + } + + @Inject(method = "", at = @At(value = "RETURN")) + private void onServerPlayerEntityConstructor(MinecraftServer minecraftServer, ServerWorld serverLevel, GameProfile gameProfile, SyncedClientOptions clientInformation, CallbackInfo ci) + { + this.actionPack = new EntityPlayerActionPack((ServerPlayerEntity) (Object) this); + } + + @Inject(method = "tick", at = @At(value = "HEAD")) + private void onTick(CallbackInfo ci) + { + actionPack.onUpdate(); + } +} diff --git a/src/main/java/io/github/skippyall/minions/networking/ClientToServerNetworking.java b/src/main/java/io/github/skippyall/minions/networking/ClientToServerNetworking.java new file mode 100644 index 0000000..682d5ea --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/networking/ClientToServerNetworking.java @@ -0,0 +1,40 @@ +package io.github.skippyall.minions.networking; + +import io.github.skippyall.minions.Minions; +import io.netty.buffer.Unpooled; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; +import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientConfigurationNetworkHandler; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerConfigurationNetworkHandler; +import net.minecraft.util.Identifier; + +public class ClientToServerNetworking { + public static final Identifier RL = new Identifier(Minions.MOD_ID, "network"); + @Environment(EnvType.CLIENT) + public static void sendJoinPacket(PlayerEntity player) { + PacketByteBuf pbf = new PacketByteBuf(Unpooled.buffer()); + pbf.writeString("BN|Init|V0.1"); + ClientConfigurationNetworking.send(RL, pbf); + } + + @Environment(EnvType.CLIENT) + public static void onConfigurationInit(ClientConfigurationNetworkHandler handler, MinecraftClient client) { + sendJoinPacket(client.player); + } + + @Environment(EnvType.SERVER) + public static void receive(MinecraftServer server, ServerConfigurationNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { + String message = buf.readString(); + if (!message.startsWith("BN|")) { + Minions.LOGGER.debug("Message with wrong format: " + message); + } + String[] parts = message.split("|"); + + } +} diff --git a/src/main/java/io/github/skippyall/minions/networking/VersionChecker.java b/src/main/java/io/github/skippyall/minions/networking/VersionChecker.java new file mode 100644 index 0000000..b65196b --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/networking/VersionChecker.java @@ -0,0 +1,21 @@ +package io.github.skippyall.minions.networking; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import net.minecraft.entity.player.PlayerEntity; + +public class VersionChecker { + protected static List hasSupportedMod = new ArrayList<>(); + public static boolean supportVersion(String version) { + return version.equals("v0.1"); + } + + public static boolean useSupportedMod(PlayerEntity p) { + return hasSupportedMod.contains(p.getUuid()); + } + + public static void resetPlayer(UUID uuid) { + hasSupportedMod.remove(uuid); + } +} diff --git a/src/main/java/io/github/skippyall/minions/program/MinionRuntime.java b/src/main/java/io/github/skippyall/minions/program/MinionRuntime.java new file mode 100644 index 0000000..2e6c0d0 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/MinionRuntime.java @@ -0,0 +1,26 @@ +package io.github.skippyall.minions.program; + +import io.github.skippyall.minions.program.statement.StatementList; +import io.github.skippyall.minions.program.variables.Variable; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class MinionRuntime implements Runnable{ + private boolean run = true; + public final Map variables = new HashMap<>(); + private final List runs = new ArrayList<>(); + + @Override + public void run() { + while(run) { + + } + } + + public void stop() { + run = false; + } +} diff --git a/src/main/java/io/github/skippyall/minions/program/block/CodeBlock.java b/src/main/java/io/github/skippyall/minions/program/block/CodeBlock.java new file mode 100644 index 0000000..ce6fe0b --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/block/CodeBlock.java @@ -0,0 +1,23 @@ +package io.github.skippyall.minions.program.block; + +import io.github.skippyall.minions.fakeplayer.MinionFakePlayer; +import io.github.skippyall.minions.program.statement.Arg; +import io.github.skippyall.minions.program.variables.Type; + +import java.util.List; + +public abstract class CodeBlock { + private String name; + private final List arguments; + private final Type returnType; + public CodeBlock(String name, List arguments, Type returnType) { + this.arguments = arguments; + this.returnType = returnType; + } + + public abstract Object execute(MinionFakePlayer minion, Object... args); + + public boolean fits(Arg arg, int slot) { + return arguments.get(slot) == arg.getType(); + } +} diff --git a/src/main/java/io/github/skippyall/minions/program/block/CodeBlocks.java b/src/main/java/io/github/skippyall/minions/program/block/CodeBlocks.java new file mode 100644 index 0000000..4284640 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/block/CodeBlocks.java @@ -0,0 +1,5 @@ +package io.github.skippyall.minions.program.block; + +public class CodeBlocks { + public static final GoBlock GO = new GoBlock(); +} diff --git a/src/main/java/io/github/skippyall/minions/program/block/CodeContainingCodeBlock.java b/src/main/java/io/github/skippyall/minions/program/block/CodeContainingCodeBlock.java new file mode 100644 index 0000000..10b92f4 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/block/CodeContainingCodeBlock.java @@ -0,0 +1,15 @@ +package io.github.skippyall.minions.program.block; + +import io.github.skippyall.minions.program.variables.Type; + +import java.util.List; + +public abstract class CodeContainingCodeBlock extends CodeBlock{ + public CodeContainingCodeBlock(String name, List arguments, Type returnType) { + super(name, arguments, returnType); + } + + protected void executeBlocks() { + + } +} diff --git a/src/main/java/io/github/skippyall/minions/program/block/GoBlock.java b/src/main/java/io/github/skippyall/minions/program/block/GoBlock.java new file mode 100644 index 0000000..a544d21 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/block/GoBlock.java @@ -0,0 +1,25 @@ +package io.github.skippyall.minions.program.block; + +import io.github.skippyall.minions.fakeplayer.EntityPlayerActionPack; +import io.github.skippyall.minions.fakeplayer.MinionFakePlayer; +import io.github.skippyall.minions.fakeplayer.ServerPlayerInterface; +import io.github.skippyall.minions.program.variables.IntegerType; +import io.github.skippyall.minions.program.variables.Type; +import io.github.skippyall.minions.program.variables.Types; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class GoBlock extends CodeBlock{ + public GoBlock() { + super("move", List.of(Types.FLOAT, Types.FLOAT), Types.VOID); + } + + public Object execute(MinionFakePlayer minion, Object... args) { + EntityPlayerActionPack action = ((ServerPlayerInterface)minion).getActionPack(); + minion.moveForward((Float) args[0]); + minion.moveSideways((Float) args[1]); + return null; + } +} \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/program/block/UseBlock.java b/src/main/java/io/github/skippyall/minions/program/block/UseBlock.java new file mode 100644 index 0000000..8983037 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/block/UseBlock.java @@ -0,0 +1,21 @@ +package io.github.skippyall.minions.program.block; + +import io.github.skippyall.minions.fakeplayer.EntityPlayerActionPack; +import io.github.skippyall.minions.fakeplayer.MinionFakePlayer; +import io.github.skippyall.minions.fakeplayer.ServerPlayerInterface; +import io.github.skippyall.minions.program.variables.Type; +import io.github.skippyall.minions.program.variables.Types; + +import java.util.List; + +public class UseBlock extends CodeBlock{ + public UseBlock(String name, List arguments, Type returnType) { + super("use", List.of(), Types.VOID); + } + + @Override + public Object execute(MinionFakePlayer minion, Object... args) { + minion.getActionPack().start(EntityPlayerActionPack.ActionType.USE, EntityPlayerActionPack.Action.once()); + return null; + } +} diff --git a/src/main/java/io/github/skippyall/minions/program/module/Module.java b/src/main/java/io/github/skippyall/minions/program/module/Module.java new file mode 100644 index 0000000..584487c --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/module/Module.java @@ -0,0 +1,22 @@ +package io.github.skippyall.minions.program.module; + +import eu.pb4.polymer.core.api.item.PolymerItem; +import io.github.skippyall.minions.program.block.CodeBlock; +import net.fabricmc.fabric.api.item.v1.FabricItemSettings; +import net.minecraft.item.Item; + +import java.util.List; + +public abstract class Module extends Item implements PolymerItem { + private final String name; + public Module(String name) { + super(new FabricItemSettings().maxCount(1)); + this.name = name; + } + + public String getModuleName() { + return name; + } + + public abstract List getCodeBlocks(); +} diff --git a/src/main/java/io/github/skippyall/minions/program/module/Modules.java b/src/main/java/io/github/skippyall/minions/program/module/Modules.java new file mode 100644 index 0000000..ba21ef3 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/module/Modules.java @@ -0,0 +1,5 @@ +package io.github.skippyall.minions.program.module; + +public class Modules { + MoveModule MOVE = new MoveModule(); +} diff --git a/src/main/java/io/github/skippyall/minions/program/module/MoveModule.java b/src/main/java/io/github/skippyall/minions/program/module/MoveModule.java new file mode 100644 index 0000000..09d40f9 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/module/MoveModule.java @@ -0,0 +1,29 @@ +package io.github.skippyall.minions.program.module; + +import io.github.skippyall.minions.program.block.CodeBlock; +import io.github.skippyall.minions.program.block.CodeBlocks; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.server.network.ServerPlayerEntity; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class MoveModule extends Module { + MoveModule() { + super("Movement"); + } + + public List getCodeBlocks() { + List codeBlocks = new ArrayList<>(); + codeBlocks.add(CodeBlocks.GO); + return codeBlocks; + } + + @Override + public Item getPolymerItem(ItemStack itemStack, @Nullable ServerPlayerEntity player) { + return Items.PURPLE_GLAZED_TERRACOTTA; + } +} diff --git a/src/main/java/io/github/skippyall/minions/program/statement/Arg.java b/src/main/java/io/github/skippyall/minions/program/statement/Arg.java new file mode 100644 index 0000000..8087a11 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/statement/Arg.java @@ -0,0 +1,8 @@ +package io.github.skippyall.minions.program.statement; + +import io.github.skippyall.minions.program.variables.Type; + +public interface Arg { + Object getValue(); + Type getType(); +} diff --git a/src/main/java/io/github/skippyall/minions/program/statement/Statement.java b/src/main/java/io/github/skippyall/minions/program/statement/Statement.java new file mode 100644 index 0000000..fd4ccb2 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/statement/Statement.java @@ -0,0 +1,15 @@ +package io.github.skippyall.minions.program.statement; + +import io.github.skippyall.minions.fakeplayer.MinionFakePlayer; +import io.github.skippyall.minions.program.block.CodeBlock; + +import java.util.List; + +public class Statement { + private CodeBlock codeBlock; + private List args; + + public void execute(MinionFakePlayer minion) { + + } +} diff --git a/src/main/java/io/github/skippyall/minions/program/statement/StatementList.java b/src/main/java/io/github/skippyall/minions/program/statement/StatementList.java new file mode 100644 index 0000000..5d64ddb --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/statement/StatementList.java @@ -0,0 +1,37 @@ +package io.github.skippyall.minions.program.statement; + +import java.util.ArrayList; +import java.util.List; + +public class StatementList { + private final List statements; + private boolean finish; + + StatementList() { + this(new ArrayList<>()); + } + + StatementList(List statements) { + this.statements = statements; + } + + public void runNext(Run run) { + + } + + public boolean canRunNext(Run run) { + return true; + } + + public boolean isFinish(Run run) { + return finish; + } + + public Run createRunInstance() { + return null; + } + + public class Run { + + } +} diff --git a/src/main/java/io/github/skippyall/minions/program/variables/FloatType.java b/src/main/java/io/github/skippyall/minions/program/variables/FloatType.java new file mode 100644 index 0000000..a15937b --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/variables/FloatType.java @@ -0,0 +1,4 @@ +package io.github.skippyall.minions.program.variables; + +public class FloatType extends Type{ +} diff --git a/src/main/java/io/github/skippyall/minions/program/variables/IntegerType.java b/src/main/java/io/github/skippyall/minions/program/variables/IntegerType.java new file mode 100644 index 0000000..e868ed3 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/variables/IntegerType.java @@ -0,0 +1,4 @@ +package io.github.skippyall.minions.program.variables; + +public class IntegerType extends Type{ +} diff --git a/src/main/java/io/github/skippyall/minions/program/variables/Type.java b/src/main/java/io/github/skippyall/minions/program/variables/Type.java new file mode 100644 index 0000000..8a019d0 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/variables/Type.java @@ -0,0 +1,4 @@ +package io.github.skippyall.minions.program.variables; + +public abstract class Type { +} diff --git a/src/main/java/io/github/skippyall/minions/program/variables/Types.java b/src/main/java/io/github/skippyall/minions/program/variables/Types.java new file mode 100644 index 0000000..b61b000 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/variables/Types.java @@ -0,0 +1,7 @@ +package io.github.skippyall.minions.program.variables; + +public class Types { + public static final IntegerType INTEGER = new IntegerType(); + public static final FloatType FLOAT = new FloatType(); + public static final Type VOID = new Type() {}; +} diff --git a/src/main/java/io/github/skippyall/minions/program/variables/Variable.java b/src/main/java/io/github/skippyall/minions/program/variables/Variable.java new file mode 100644 index 0000000..2ab27a3 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/variables/Variable.java @@ -0,0 +1,24 @@ +package io.github.skippyall.minions.program.variables; + +import io.github.skippyall.minions.program.statement.Arg; + +public class Variable implements Arg { + private final Type type; + private final String name; + private Object value; + + public Variable(Type type, String name) { + this.type = type; + this.name = name; + } + + @Override + public Object getValue() { + return value; + } + + @Override + public Type getType() { + return type; + } +} diff --git a/src/main/java/io/github/skippyall/minions/server/MinionsServer.java b/src/main/java/io/github/skippyall/minions/server/MinionsServer.java new file mode 100644 index 0000000..36deab6 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/server/MinionsServer.java @@ -0,0 +1,22 @@ +package io.github.skippyall.minions.server; + +import io.github.skippyall.minions.networking.ClientToServerNetworking; +import io.github.skippyall.minions.networking.VersionChecker; +import net.fabricmc.api.DedicatedServerModInitializer; +import net.fabricmc.fabric.api.networking.v1.ServerConfigurationConnectionEvents; +import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerConfigurationNetworkHandler; + +public class MinionsServer implements DedicatedServerModInitializer { + @Override + public void onInitializeServer() { + ServerConfigurationNetworking.registerGlobalReceiver(ClientToServerNetworking.RL, ClientToServerNetworking::receive); + ServerConfigurationConnectionEvents.CONFIGURE.register(new ServerConfigurationConnectionEvents.Configure() { + @Override + public void onSendConfiguration(ServerConfigurationNetworkHandler handler, MinecraftServer server) { + VersionChecker.resetPlayer(handler.getDebugProfile().getId()); + } + }); + } +} diff --git a/src/main/resources/TODO.txt b/src/main/resources/TODO.txt new file mode 100644 index 0000000..9a3bffb --- /dev/null +++ b/src/main/resources/TODO.txt @@ -0,0 +1,35 @@ +- Module: + - Bewegungsmodul <-- + - Angriffsmodul <-- + - Abbaumodul <-- + - Platziermodul / Verwendungsmodul <-- + - Werfmodul + - Inventarmanagementmodul <-- + - Inventaropenmodul + +- Detektoren: + - Blockdetektor <-- + - Entitydetektor < + - Dimensiondetektor + - Positiondetektor + - Inventardetektor + +- Programmieren: + - Variablen + - (Listen) + - Warten + - Wiederholen + - Wiederhole bis/während + - Wiederhole x mal/(für jedes Element) + - Bedingung + +- VariableTypen: + - Integer + - String + - Position + - Block + - BlockType + - (NBT) + - (World) + - (Chunk) + - Inventory diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..1802e31 --- /dev/null +++ b/src/main/resources/fabric.mod.json @@ -0,0 +1,33 @@ +{ + "schemaVersion": 1, + "id": "minions", + "version": "${version}", + "name": "Minions", + "description": "", + "authors": [], + "contact": { + "repo": "https://github.com/falko/Minions" + }, + "license": "MIT", + "icon": "assets/minions/icon.png", + "environment": "*", + "entrypoints": { + "client": [ + "io.github.skippyall.minions.client.MinionsClient" + ], + "main": [ + "io.github.skippyall.minions.Minions" + ], + "server": [ + "io.github.skippyall.minions.server.MinionsServer" + ] + }, + "mixins": [ + "minions.mixins.json" + ], + "depends": { + "fabricloader": ">=${loader_version}", + "fabric": "*", + "minecraft": "${minecraft_version}" + } +} diff --git a/src/main/resources/minions.mixins.json b/src/main/resources/minions.mixins.json new file mode 100644 index 0000000..079b3bd --- /dev/null +++ b/src/main/resources/minions.mixins.json @@ -0,0 +1,16 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "io.github.skippyall.minions.mixins", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "ConnectionMixin", + "PlayerListMixin", + "ServerPlayerMixin" + ], + "client": [], + "server": [], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file