Jump to content

Jack Richard

Members
  • Posts

    30
  • Joined

  • Last visited

Posts posted by Jack Richard

  1. 16 minutes ago, DaemonUmbra said:

    First of all, why are you shadowing log4j? Minecraft already provides log4j2.

    Second if build is running shadowjar instead of jar then you might need to tweak the line where it says jar.finalizedBy('reobfJar') to finalize shadowJar instead

    Thanks so much for your help!

    I removed the log4j dependency, I honesty don't remember when I put that there. Once I fixed the jar.finalizedBy line, everything worked! (One small issue where I was relocating all of "com.google" when I just should've relocated "com.google.common," too)

     

    Thanks again!

  2. I have multiple shadowed dependencies in my mod, and it seems that something isn't working correctly here...

     

    When I look in the jar file, all of my dependencies are properly relocated and included, but I seem to have an issue with Minecraft recognizing it as a mod. The error says 

    Quote

    Mod (modid) encountered an error during the load_registries event phase.

    AIR

    Very strange. The debug.log shows the mod failed to load because of a

    Quote

    java.lang.NoSuchFieldError: AIR

     

    Here's my build.gradle if that will be any help.

    buildscript {
        repositories {
            maven { url = 'https://files.minecraftforge.net/maven' }
            maven { url = "https://plugins.gradle.org/m2/" }
            jcenter()
            mavenCentral()
        }
        dependencies {
            classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true
        }
    }
    
    plugins {
        id "com.github.johnrengelman.shadow" version "2.0.4"
    }
    
    apply plugin: 'java'
    apply plugin: 'net.minecraftforge.gradle'
    apply plugin: 'eclipse'
    apply plugin: 'maven-publish'
    
    version = '1.0'
    group = 'com.mod.mod' // http://maven.apache.org/guides/mini/guide-naming-conventions.html
    archivesBaseName = 'mod'
    
    sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
    //Print out JVM information so that we know what version is running. Extreamly useful for people to know when helping you.
    println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
    
    minecraft {
        // The mappings can be changed at any time, and must be in the following format.
        // snapshot_YYYYMMDD   Snapshot are built nightly.
        // stable_#            Stables are built at the discretion of the MCP team.
        // Use non-default mappings at your own risk. they may not always work.
        // Simply re-run your setup task after changing the mappings to update your workspace.
        mappings channel: 'snapshot', version: '20200514-1.15.1'
        // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
        
        // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
    
        // Default run configurations.
        // These can be tweaked, removed, or duplicated as needed.
        runs {
            client {
                workingDirectory project.file('run')
    
                // Recommended logging data for a userdev environment
                property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
    
                // Recommended logging level for the console
                property 'forge.logging.console.level', 'debug'
    
                mods {
                    examplemod {
                        source sourceSets.main
                    }
                }
            }
    
            server {
                workingDirectory project.file('run')
    
                // Recommended logging data for a userdev environment
                property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
    
                // Recommended logging level for the console
                property 'forge.logging.console.level', 'debug'
    
                mods {
                    examplemod {
                        source sourceSets.main
                    }
                }
            }
    
            data {
                workingDirectory project.file('run')
    
                // Recommended logging data for a userdev environment
                property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
    
                // Recommended logging level for the console
                property 'forge.logging.console.level', 'debug'
    
                args '--mod', 'examplemod', '--all', '--output', file('src/generated/resources/')
    
                mods {
                    examplemod {
                        source sourceSets.main
                    }
                }
            }
        }
    }
    
    project.tasks.build.dependsOn project.tasks.shadowJar
    
    repositories {
        jcenter()
    }
    
    configurations {
        provided
        compile.extendsFrom provided
    }
    
    dependencies {
        minecraft 'net.minecraftforge:forge:1.15.2-31.2.36'
    
        compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.2'
        compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.2'
        compile group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.141.59'
    
        shadow group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.2'
        shadow group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.2'
        shadow group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.141.59'
    }
    
    shadowJar {
        configurations = [project.configurations.shadow]
    
        classifier ''
    
        relocate('org.apache', 'com.mod.apache')
        relocate('com.google', 'com.mod.google')
    }
    
    processResources {
        inputs.property "version", project.version
        inputs.property "mcversion", "1.15.2-31.2.36"
    
        from(sourceSets.main.resources.srcDirs) {
            include 'mcmod.info'
            expand 'version':project.version, 'mcversion': "1.15.2-31.2.36"
        }
    
        from(sourceSets.main.resources.srcDirs) {
            exclude 'mcmod.info'
        }
    }
    
    jar {
        manifest {
            attributes([
                    "Specification-Title": "mod",
                    "Specification-Vendor": "mod",
                    "Specification-Version": "1", // We are version 1 of ourselves
                    "Implementation-Title": project.name,
                    "Implementation-Version": "${version}",
                    "Implementation-Vendor" :"mod",
                    "Multi-Release": 'true',
                    "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
                    "ContainedDeps": "byte-buddy-1.8.15.jar client-combined-3.141.59.jar commons-exec-1.3.jar guava-25.0-jre.jar okhttp-3.11.0.jar okio-1.14.0.jar"
            ])
        }
    }
    
    // Example configuration to allow publishing using the maven-publish task
    // This is the preferred method to reobfuscate your jar file
    jar.finalizedBy('reobfJar')
    // However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing
    //publish.dependsOn('reobfJar')
    
    publishing {
        publications {
            mavenJava(MavenPublication) {
                artifact jar
            }
        }
        repositories {
            maven {
                url "file:///${project.projectDir}/mcmodsrepo"
            }
        }
    }
    

     

    My guess is that it is an error with the "minecraft" dependancy, I just don't know where to start on fixing it.

     

    Thanks in advance!

  3. 16 minutes ago, Jack Richard said:

    I changed my shadowJar config to this:

    
    shadowJar {
        relocate('com.google', 'org.(modid).google')
        configurations = [project.configurations.shadow]
    
        classifier ''
    
        relocate('org.apache', 'org.(modid).apache')
    }

    And I have success!

    But now that I've entered the game, I've noticed a fatal flaw. None of my block or items registered. I think it's because of ignoring the Minecraft dependencies, so I'll need to keep on working.

  4. 30 minutes ago, ChampionAsh5357 said:

    You seem to have copied the apache libraries that are already present in forge as well.

    I used this to get the libraries back:

    shadow group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.2'
    shadow group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.2'

    But now I'm getting this:

    java.lang.NoSuchMethodError: com.google.common.util.concurrent.SimpleTimeLimiter.create(Ljava/util/concurrent/ExecutorService;)Lcom/google/common/util/concurrent/SimpleTimeLimiter;

     

  5. 1 minute ago, ChampionAsh5357 said:

    I believe you would need to set the configurations to only include whichever you need using configurations = [project_configs]. That's why I said create a configuration called shade before so that you could call that.

    Now we're getting somewhere... here's my build.gradle:

    configurations {
        provided
        compile.extendsFrom provided
    }
    
    dependencies {
        minecraft 'net.minecraftforge:forge:1.15.2-31.2.36'
    
        shadow group: 'org.seleniumhq.selenium', name:'selenium-java', version:'3.141.59'
    }
    
    shadowJar {
        configurations = [project.configurations.shadow]
    
        classifier ''
    
        relocate('org.apache', 'org.(modid).apache')
    }
    
    processResources {
        inputs.property "version", project.version
        inputs.property "mcversion", "1.15.2-31.2.36"
    
        from(sourceSets.main.resources.srcDirs) {
            include 'mcmod.info'
            expand 'version':project.version, 'mcversion': "1.15.2-31.2.36"
        }
    
        from(sourceSets.main.resources.srcDirs) {
            exclude 'mcmod.info'
        }
    }
    
    project.tasks.build.dependsOn shadowJar

     

    The file size drastically shrinks, and Minecraft recognizes it as a mod! 

    But now, I'm getting:

    java.lang.NoClassDefFoundError: org/(modid)/apache/logging/log4j/LogManager

    So there might be more work to do...

  6. 56 minutes ago, ChampionAsh5357 said:

    Hmmm, my only guess is that it's iterating through the apache commons package directory and skipping yours. As for how to fix this, you might have to do something more with relocate, but that is the best I can think of.

     

    I've relocated the Apache libraries now, but it's still not recognizing. When I recompile the jar, it appears that it has additionally copied all of Minecraft Forge's files. I think Shadow is picking up the:

    minecraft 'net.minecraftforge:forge:1.15.2-31.2.36'

    in dependencies{}...

     

    I can't get exclude to work on this dependency, and I think this may be the solution.

  7. At this point, I've reimplemented the Shadow plugin, but it makes no changes to the jar unless I use:

    project.tasks.build.dependsOn shadowJar

    which makes a much larger jar, and I assume my dependencies are somewhere in there, but Minecraft does not recognize it as a mod. 

    When I used the dependencies{} block in the shadowJar{} block, and included my dependencies, it would generate a 1 KB jar, which is definitely not right at all.

     

    Other than including the plugin, here's the code that Shadow effects:

    dependencies {
        minecraft 'net.minecraftforge:forge:1.15.2-31.2.36'
    
        compile group: 'org.seleniumhq.selenium', name:'selenium-java', version:'3.141.59'
    }
    
    shadowJar {
        relocate 'org.apache.commons.exec', 'org.(modid).apache.commons.exec'
        classifier ''
    }

     

    Thanks all for your help.

  8. 26 minutes ago, DaemonUmbra said:

    That guide is ANCIENT, throw it away.

    I don't think that bit is needed now

    I'm guessing I still need to move the Apache library somehow, because I always get NoClassDefFoundError when calling it... If you still aren't allowed to use Apache libraries (I read old forum posts saying you can't include those normally), I guess that would explain the error. 

    I couldn't figure out the Shadow plugin, it didn't seem to include any dependencies, so I used that guide, I'll try again with Shadow.

     

    Thanks.

  9. 17 minutes ago, ChampionAsh5357 said:

    You shouldn't need to edit the buildscript at all. Plugins are applied using the plugins{} block although what you are doing will work as well.

    I changed it to use the plugins{} block instead.

    17 minutes ago, ChampionAsh5357 said:

    I believe the keyword to use is shade instead of shadow with shade being a configuration.

    shade wasn't a valid option, so I stuck with shadow. But I see some examples just using compile, does that work anyway?

    19 minutes ago, ChampionAsh5357 said:

    You would also need a shadowJar{} block to specify where to relocate the files to.

    Okay, here's my shadowJar{} block I added:

    shadowJar {
        relocate 'org.apache', 'org.(modid).apache'
    }

     

    I'm still getting NoClassDefFoundError, though.

     

    Thanks for your help so far.

  10. 27 minutes ago, ChampionAsh5357 said:

    Well technically, that's what you have to do by shadowing the jar into your own using Gradle.

    I looked into shadowing, and I added the plugin to my Gradle file. Before, I was "shading" using this:

    configurations.shade.each { dep ->
            from(project.zipTree(dep)){
                exclude 'META-INF', 'META-INF/**'
            }
        }

    ...but I'm guessing that isn't the same thing.

     

    I needed to use version 4.0.4, because 6.0 didn't support the version of Gradle I'm using.

    When I build the jar, the logs show a NoClassDefFoundError for the main package of the dependency.

     

    All I've added to build.gradle is:

    buildscript {
        repositories {
            maven { url = 'https://files.minecraftforge.net/maven' }
            maven { url = "https://plugins.gradle.org/m2/" }
            jcenter()
            mavenCentral()
        }
        dependencies {
            classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true
            classpath "com.github.jengelman.gradle.plugins:shadow:4.0.4"
        }
    }
    apply plugin: 'net.minecraftforge.gradle'
    apply plugin: 'eclipse'
    apply plugin: 'maven-publish'
    apply plugin: "com.github.johnrengelman.shadow"
    dependencies {
        minecraft 'net.minecraftforge:forge:1.15.2-31.2.36'
    
        shadow 'nameofdependency'
    }

     

    Maybe there is more configuration needed?

  11. I'm using version 1.15.2, and I'm trying to include Apache Commons Exec in my mod. 

    From what I've read, you can't use it like a normal dependency. But, the Apache library is a prerequisite for the dependency I am adding, so I don't think I can simply relocate it.

    How can I use this?

     

    Thanks in advance.

  12. 16 minutes ago, ChampionAsh5357 said:

    Yes, that's the use of a packet through the network. But that should only be sent as needed as otherwise you just bottleneck the network creating more issues.

    No, that should be used in your registry instance for your ContainerType.

    Got it, and got it.

     

    16 minutes ago, ChampionAsh5357 said:

    Imagine it like this. You have two instances, a server and the client. The server creates a container with a specific window id. The client creates a container with the same window id and a screen that can get information from the container. The server container sends default information to the client container which is read by the screen. A client screen clicks something, which gets sent as a packet to the server container, which updates the client container, which updates the screen. Note that the client creates a new instance of the container on open so the information needs to be synced. By default, only slots and tracked integers are synced. If you want to handle something else, you need to send it yourself.

    Thanks for explaining it to me, I'll try to wrap my head around that, and send an update soon.

     

    Thank you!

  13. 7 minutes ago, ChampionAsh5357 said:

    That still makes no sense. You're just bottlenecking the network. The data doesn't change until you send it. Also, the button shouldn't be the one doing it. It should be handled on the server once again. NOTHING should be handled on the client itself. It all gets synchronized via the gui. Only thing that doesn't is the string which should be what you send on button click.

    You missed the part where I said IForgeContainerType. Doesn't matter if their registered. If it's not using the correct type it won't send the packet.

    Not being rude, the original theory is wrong. The client doesn't hold data from the server. It will be reinitialized since it's pulling information from the empty client container.

    I know, it's very confusing, and frankly, I might just rework the GUI if I can't get this to work, anyway.

    Is it possible to get data from the Screen class to the TileEntity class? 

     

    Also, should I implement IForgeContainerType in my Container class?

    I understand, the original theory was a little far-fetched. So an empty client container could be it? Just trying to understand.

     

    Thanks again.

  14. 1 minute ago, ChampionAsh5357 said:

    You are using IInventory. Go and fix that and properly attach it with capabilities. But I won't be so stingy since you have been trying and cooperating so apologies for my agressiveness.

    I understand that IInventory is not accepted, so I'll be working to fix that soon. No problem, I'm just happy with whatever you're able to contribute. 

     

    2 minutes ago, ChampionAsh5357 said:

    As a precursor, try to avoid using Server or Client in your names, it confuses everyone.

    Yeah, that wasn't the best choice.

     

    3 minutes ago, ChampionAsh5357 said:

    You're writing the carrier name twice?

    I guess so. I was a little confused once functions like getUpdatePacket() and onDataPacket() were used.

     

    4 minutes ago, ChampionAsh5357 said:

    You're doing this every tick, only send it when the button is pressed.

    This should not really be handled on the client once again. This is not necessary if you send the information to the server. You will need to resync the values anyways whenever the inventory is opened regardless.

    I'm sending the data every tick, the button writes the data to an item in the one slot of the GUI. Here's the code for the .sendtoServer() handler:

    public static void handle(CarrierServerSync msg, Supplier<NetworkEvent.Context> ctx) {
            ctx.get().enqueueWork(() -> {
                PlayerEntity sender = ctx.get().getSender();
                ServerTileEntity server = getTileEntity(sender.inventory, msg.tileEntity);
                server.setCarrierName(msg.data);
            });
            ctx.get().setPacketHandled(true);
        }
    
        private static ServerTileEntity getTileEntity(final PlayerInventory playerInventory, final BlockPos tileEntity) {
            Objects.requireNonNull(playerInventory, "playerInventory cannot be null");
            final TileEntity tileAtPos = playerInventory.player.world.getTileEntity(tileEntity);
    
            if (tileAtPos instanceof ServerTileEntity) {
                return (ServerTileEntity) tileAtPos;
            }
            throw new IllegalStateException("Tile entity is not correct! " + tileAtPos);
        }

    This is probably not the best way to do this...

     

    9 minutes ago, ChampionAsh5357 said:

    This should not really be handled on the client once again. This is not necessary if you send the information to the server. You will need to resync the values anyways whenever the inventory is opened regardless.

    Finally, if your container is not registered using IForgeContainerType, then the packet information will never be sent to the client. You should also store the block pos and not the te itself. That's rather pointless to do as all it's used for sending the position back to the server. The tile entity will still not store the position anyways.

    Luckily, I do have my container, messages, and tile entity registered. 

    Looping back to my original theory, is Block#createTileEntity() run when you open a GUI?

     

    Thanks again.

  15. 4 minutes ago, ChampionAsh5357 said:

    Yes. Synchronization the wrong direction. Always good.

     

    I doubt you need to synchronize from the client->server as this probably just uses a standard inventory and primitives.  In that case, you only need to sync from server->client. Which, you are still neglecting to listen and do.

     

    Please show your entire tile entity, block, container, and screen code. I am curious on what you're doing and how you're doing it since I'm pretty sure it's some variation of vanilla code which will not work in most cases.

    public class ServerContainer extends Container {
    
        public ServerTileEntity entity;
    
        public ServerContainer(final int windowId, final PlayerInventory playerInventory, final PacketBuffer data) {
            this(windowId, playerInventory, getTileEntity(playerInventory, data));
        }
    
        public ServerContainer(final int windowId, final PlayerInventory playerInventory,
                               final TileEntity tileEntity) {
            super(ContainerTypes.SERVER.get(), windowId);
    
            this.entity = (ServerTileEntity) tileEntity;
    
            int startX = 8;
            int startY = 84;
            int slotSizePlus2 = 18;
    
            for (int row = 0; row < 3; ++row) {
                for (int column = 0; column < 9; ++column) {
                    this.addSlot(new Slot(playerInventory, 9 + (row * 9) + column, startX + (column * slotSizePlus2),
                            startY + (row * slotSizePlus2)));
                }
            }
    
            int hotbarY = 142;
            for (int column = 0; column < 9; ++column) {
                this.addSlot(new Slot(playerInventory, column, startX + (column * slotSizePlus2), hotbarY));
            }
    
            this.addSlot(new CustomSlot(entity, 0, 7, 35));
        }
    
        @Override
        public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) {
            ItemStack itemstack = ItemStack.EMPTY;
            Slot slot = this.inventorySlots.get(index);
            if (slot != null && slot.getHasStack()) {
                ItemStack itemstack1 = slot.getStack();
                itemstack = itemstack1.copy();
                if (index < 36) {
                    if (!this.mergeItemStack(itemstack1, 36, this.inventorySlots.size(), true)) {
                        return ItemStack.EMPTY;
                    }
                } else if (!this.mergeItemStack(itemstack1, 0, 36, false)) {
                    return ItemStack.EMPTY;
                }
    
                if (itemstack1.isEmpty()) {
                    slot.putStack(ItemStack.EMPTY);
                } else {
                    slot.onSlotChanged();
                }
            }
            return itemstack;
        }
    
        @Override
        public boolean canInteractWith(PlayerEntity playerIn) {
            return true;
        }
    
        private static ServerTileEntity getTileEntity(final PlayerInventory playerInventory,
                                                     final PacketBuffer data) {
            Objects.requireNonNull(playerInventory, "playerInventory cannot be null");
            Objects.requireNonNull(data, "data cannot be null");
            final TileEntity tileAtPos = playerInventory.player.world.getTileEntity(data.readBlockPos());
    
            if (tileAtPos instanceof ServerTileEntity) {
                return (ServerTileEntity) tileAtPos;
            }
            throw new IllegalStateException("Tile entity is not correct! " + tileAtPos);
        }
    
    }
    @OnlyIn(Dist.CLIENT)
    public class ServerScreen extends ContainerScreen<ServerContainer> {
    
        private static final ResourceLocation TEXTURES = new ResourceLocation("modid:textures/gui/server.png");
        private final PlayerInventory player;
        private ServerTileEntity entity;
        private TextFieldWidget carrierName;
    
        public ServerScreen(ServerContainer container, PlayerInventory player, ITextComponent title) {
            super(container, player, title);
            this.player = player;
            this.entity = getTileEntity(player, container);
            this.guiLeft = 0;
            this.guiTop = 0;
            this.xSize = 176;
            this.ySize = 166;
        }
    
        @Override
        protected void init() {
            super.init();
    
            int x = (this.width - this.xSize) / 2;
            int y = (this.height - this.ySize) / 2;
    
            this.carrierName = new TextFieldWidget(font, x + 84, y + 11, 86, 18, "Carrier Name");
            this.carrierName.setMaxStringLength(13);
            this.carrierName.setEnableBackgroundDrawing(false);
            this.carrierName.setVisible(true);
            this.carrierName.setTextColor(16777215);
            this.carrierName.setText(this.entity.getCarrierName());
            System.out.println(this.entity.getCarrierName());
            System.out.println("Above set");
        }
    
        private static ServerTileEntity getTileEntity(final PlayerInventory playerInventory, final ServerContainer container) {
            Objects.requireNonNull(playerInventory, "playerInventory cannot be null");
            final TileEntity tileAtPos = playerInventory.player.world.getTileEntity(container.entity.getPos());
    
            if (tileAtPos instanceof ServerTileEntity) {
                return (ServerTileEntity) tileAtPos;
            }
            throw new IllegalStateException("Tile entity is not correct! " + tileAtPos);
        }
    
        @Override
        public void render(final int mouseX, final int mouseY, final float partialTicks) {
            this.renderBackground();
            this.carrierName.render(mouseX, mouseY, partialTicks);
            super.render(mouseX, mouseY, partialTicks);
            this.renderHoveredToolTip(mouseX, mouseY);
        }
    
        @Override
        public boolean mouseClicked(double p_mouseClicked_1_, double p_mouseClicked_3_, int p_mouseClicked_5_) {
            this.carrierName.mouseClicked(p_mouseClicked_1_, p_mouseClicked_3_, p_mouseClicked_5_);
            return super.mouseClicked(p_mouseClicked_1_, p_mouseClicked_3_, p_mouseClicked_5_);
        }
    
        @Override
        protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {
            RenderSystem.color4f(1.0f, 1.0f, 1.0f, 1.0f);
            this.getMinecraft().getTextureManager().bindTexture(TEXTURES);
    
            int x = (this.width - this.xSize) / 2;
            int y = (this.height - this.ySize) / 2;
    
            this.blit(x, y, 0, 0, 176, 166);
            this.font.drawString("Server", x + 10, y + 10, 16777215);
    
            this.entity.setCarrierName(carrierName.getText());
            ModClass.INSTANCE.sendToServer(new CarrierServerSync(carrierName.getText(), this.entity.getPos()));
        }
    
        @Override
        protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) {
            super.drawGuiContainerForegroundLayer(mouseX, mouseY);
    
            int x = (this.width - this.xSize) / 2;
            int y = (this.height - this.ySize) / 2;
    
            this.addButton(new Button(x + 30, y + 33, 50, 20, "Register", new Button.IPressable() {
                @Override
                public void onPress(Button p_onPress_1_) {
                    System.out.println("pressed");
                    if (!entity.getStackInSlot(0).isEmpty()) {
                        System.out.println("not empty");
                        if (entity.getStackInSlot(0).getStack().getTag() != null) {
                            System.out.println("not null");
                            CompoundNBT compoundNBT = entity.getStackInSlot(0).getTag().copy();
                            compoundNBT.putString("carrier", carrierName.getText());
                            entity.getStackInSlot(0).setTag(compoundNBT);
                        } else {
                            System.out.println("null");
                            CompoundNBT compoundNBT = new CompoundNBT();
                            compoundNBT.putString("carrier", carrierName.getText());
                            entity.getStackInSlot(0).getStack().setTag(compoundNBT);
                        }
                    }
                }
            }));
    
            this.addButton(carrierName);
        }
    
    }
    public class ServerTileEntity extends TileEntity implements INamedContainerProvider, ITickableTileEntity, IInventory {
    
        private NonNullList<ItemStack> inventory = NonNullList.<ItemStack>withSize(1, ItemStack.EMPTY);
        private IItemHandlerModifiable items = createHandler();
        private LazyOptional<IItemHandlerModifiable> itemHandler = LazyOptional.of(() -> items);
        private String carrierName = "";
    
        public ServerTileEntity(TileEntityType<?> tileEntityTypeIn) {
            super(tileEntityTypeIn);
        }
    
        public ServerTileEntity(){
            super(TileEntityTypes.SERVER.get());
        }
    
        @Override
        public ITextComponent getDisplayName() {
            return new TranslationTextComponent("container.server");
        }
    
        @Override
        public Container createMenu(int p_createMenu_1_, PlayerInventory p_createMenu_2_, PlayerEntity p_createMenu_3_) {
            return new ServerContainer(p_createMenu_1_, p_createMenu_2_, this);
        }
    
        @Override
        public void tick() {
            
        }
    
        @Override
        public SUpdateTileEntityPacket getUpdatePacket() {
            CompoundNBT tagCompound = new CompoundNBT();
            tagCompound.putString("carrier", carrierName);
            this.write(tagCompound);
            SUpdateTileEntityPacket pack = new SUpdateTileEntityPacket(pos, 0, tagCompound);
            return pack;
        }
    
        @Override
        public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt) {
            this.read(pkt.getNbtCompound());
        }
    
        @Override
        public CompoundNBT getUpdateTag() {
            CompoundNBT tagCompound = new CompoundNBT();
            tagCompound.putString("carrier", carrierName);
            return tagCompound;
        }
    
        @Override
        public void handleUpdateTag(CompoundNBT tag) {
            this.read(tag);
        }
    
        public void setCarrierName(String carrierName) {
            this.carrierName = carrierName;
        }
    
        public String getCarrierName() {
            return this.carrierName;
        }
    
        @Override
        public int getSizeInventory() {
            return inventory.size();
        }
    
        @Override
        public boolean isEmpty() {
            for(ItemStack stack : this.inventory) {
                if(!stack.isEmpty()) return false;
            }
            return true;
        }
    
        @Override
        public ItemStack getStackInSlot(int index) {
            return inventory.get(index);
        }
    
        @Override
        public ItemStack decrStackSize(int index, int count) {
            return ItemStackHelper.getAndSplit(this.inventory, index, count);
        }
    
        @Override
        public void setInventorySlotContents(int index, ItemStack stack) {
            this.inventory.set(index, stack);
        }
    
        @Override
        public ItemStack removeStackFromSlot(int index) {
            return ItemStackHelper.getAndRemove(this.inventory, index);
        }
    
        @Override
        public boolean isUsableByPlayer(PlayerEntity player) {
            return true;
        }
    
        @Override
        public void clear() {
            this.inventory.clear();
        }
    
        @Override
        public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nonnull Direction side) {
            if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
                return itemHandler.cast();
            }
            return super.getCapability(cap, side);
        }
    
        @Override
        public void read(CompoundNBT compound)
        {
            super.read(compound);
            this.inventory = NonNullList.<ItemStack>withSize(this.getSizeInventory(), ItemStack.EMPTY);
            ItemStackHelper.loadAllItems(compound, this.inventory);
            setCarrierName(compound.getString("carrier"));
        }
    
        private IItemHandlerModifiable createHandler() {
            return new InvWrapper(this);
        }
    
        @Override
        public CompoundNBT write(CompoundNBT compound)
        {
            super.write(compound);
            ItemStackHelper.saveAllItems(compound, this.inventory);
            compound.putString("carrier", getCarrierName());
    
            return compound;
        }
    
    }
    public class Server extends Block {
    
        private static final VoxelShape SHAPE = Block.makeCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 32.0D, 16.0D);
    
        public static final DirectionProperty FACING = HorizontalBlock.HORIZONTAL_FACING;
    
        public Server(Properties properties) {
            super(properties);
    
            this.setDefaultState(this.getStateContainer().getBaseState().with(FACING, Direction.NORTH));
        }
    
        @Override
        public TileEntity createTileEntity(BlockState state, IBlockReader world) {
            return TileEntityTypes.SERVER.get().create();
        }
    
        @Override
        public boolean hasTileEntity(BlockState state) {
            return true;
        }
    
        @Override
        protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder) {
            builder.add(FACING);
        }
    
        @Override
        public BlockState getStateForPlacement(BlockItemUseContext context) {
            return this.getDefaultState().with(FACING, context.getPlacementHorizontalFacing().getOpposite());
        }
    
        @Override
        public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
            return SHAPE;
        }
    
        @Override
        public ActionResultType onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) {
            TileEntity te = worldIn.getTileEntity(pos);
            if (te != null && te instanceof ServerTileEntity && !worldIn.isRemote) {
                NetworkHooks.openGui((ServerPlayerEntity) player, (ServerTileEntity) te, pos);
            }
    
            return super.onBlockActivated(state, worldIn, pos, player, handIn, hit);
        }
    
    }

     

    My goal is to get the data from the TextFieldWidget, and save it in NBT tags, and be able to retreive it later, putting the text back in the field.

    Yes, I know; most of this code won't be the "recommended way" of doing any of this, I've been really trying though.

     

    Let me know if you need any more information.

    Thanks.

  16. 7 minutes ago, ChampionAsh5357 said:

    Ah yes, synchronization on block update. Something completely unnecessary when it comes to GUI. Those are synced through slots. This should only be used if you have a TER present.

    Then you fell into a trap of confirmation bias. Just because you get the same result doesn't mean it was synced correctly. It just means you probably executed the same code on both sides when it should only be on one and then synced.

    I forgot to mention I send Messages from the client to the server, so I am doing some syncing, I believe.

  17. 40 minutes ago, ChampionAsh5357 said:

    It's like there are two sides of the game that need to be synchronized, hmmmmmmmmmmmmm.

     

    The client and server will not be synchronized under normal conditions, you must specify which variable you would like to sync and when (most likely in your container).

    Does it help to say when I add...

    @Override
    public void tick() {
    	System.out.println(variable);
    }

    ...I always get the result, whether or not world.isRemote()?

     

    I use...

    @Override
    public CompoundNBT getUpdateTag() {
      CompoundNBT tagCompound = new CompoundNBT();
      tagCompound.putString("variable", variable);
      return tagCompound;
    }
    
    @Override
    public void handleUpdateTag(CompoundNBT tag) {
      this.read(tag);
    }
    
    @Override
    public void read(CompoundNBT compound)
    {
      super.read(compound);
      this.inventory = NonNullList.<ItemStack>withSize(this.getSizeInventory(), ItemStack.EMPTY);
      ItemStackHelper.loadAllItems(compound, this.inventory);
      setVariable(compound.getString("variable"));
    }
    
    @Override
    public CompoundNBT write(CompoundNBT compound)
    {
      super.write(compound);
      ItemStackHelper.saveAllItems(compound, this.inventory);
      compound.putString("variable", getVariable());
    
      return compound;
    }

    to synchronize the data.

     

    Thanks.

  18. Hi,

     

    I'm having trouble with opening my GUI, as the tile entity (extending ITickableTileEntity, among others) will erase all stored variables, retrieved from NBT. So this isn't a problem with NBT. Also, this is a 1.15 problem.

    I've tracked down the exact time that the variables reset, and it's when the GUI's screen is opened, createTileEntity() is triggered in the Block class, recreating the tile entity and overwriting the variables.

    Is there a way to stop this?

     

    Here's a snippet from my block's class.

    @Override
    public TileEntity createTileEntity(BlockState state, IBlockReader world) {
      return TileEntityTypes.TILE.get().create();
    }
    
    @Override
    public boolean hasTileEntity(BlockState state) {
      return true;
    }

     

    Thanks for your help in advance, I'd be willing to send more code snippets and answer any questions.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.