Jump to content

[1.11.2] Help syncing tileentity IItemHandler from server to client


Recommended Posts

Posted

Hello, all!

I'm currently trying to develop a server-compatible mod for the first time, and I'm having some massive issues with my IItemHandler capability for a tileentity not properly syncing from the server to the client.  It runs fine in singleplayer-- the inventory has expected behavior, as seen here:

normal-inventory.gif

Everything seems to be working fine.  I can drag stacks around, they register in the top, etc.  No issues. (placeholder gui and .lang isn't set up, I know XD)

But when I host from a server and connect to it...

broken-server-inventory.gif

Clicking the item just ends with it glitching immediately back into its slot.  Shift-clicking duplicates the item into the slot as a ghost item, which immediately disappears when clicked on.

So this is definitely a big issue.  One of the most requested features I had for the mod was server compatibility, so I'm not about to just give up, however this is my first experience with servers and there seem to be few good explanations/examples of how this even works.  As I understand, IItemHandler doesn't automatically sync with the client the way IInventory does, but IInventory is an older, outdated method that's not the most effective one to use from what I've read.  It sounds like I need to set up a packet system to sync the server to the client and back again, but I have very little idea of how to do that with an inventory.  I've used packets before, but only ever for simple variables (i.e. ints and stuff), and I don't necessarily know enough about the inventories to know where I'd need to call/send these packets.  So if anyone has experience/advice here, I would definitely appreciate it.

If at all possible, I'd like to make this setup reusable-- though if that's not easily possible I understand.  I want to keep the mod as clean as possible, without reusing code if I can help it, so if there's some way I can set this up automatically for future TileEntity inventories (i.e. a custom extension of the container class?  Some way to automatically sync through my custom slot base class?) that is definitely preferable.

 

Current code:

Block

TileEntity

Container

GUI

GUIHandler

 

I do use a custom slot class, but the only thing I added is a restriction for isItemValid (the slot is a food bowl, so I've restricted it to only accept my kibble items).  You can see that code here:

@Override
public boolean isItemValid(ItemStack stack) {
	if (stack.isEmpty() || !(stack.getItem() instanceof ItemKibble))
    	return false;

    IItemHandler handler = this.getItemHandler();
    ItemStack remainder;
    if (handler instanceof IItemHandlerModifiable)
    {
        IItemHandlerModifiable handlerModifiable = (IItemHandlerModifiable) handler;
        ItemStack currentStack = handlerModifiable.getStackInSlot(index);

        handlerModifiable.setStackInSlot(index, ItemStack.EMPTY);

        remainder = handlerModifiable.insertItem(index, stack, true);

        handlerModifiable.setStackInSlot(index, currentStack);
    }
    else
    {
        remainder = handler.insertItem(index, stack, true);
    }
    return remainder.isEmpty() || remainder.getCount() < stack.getCount();
}

Thank you so much for your time, and have a great day!

Posted

Why are you using 1.11? Update.

 

Quote

public class BlockFoodDish extends BlockWildCraft implements ITileEntityProvider

Don't use ITileEntityProvider, it is outdated and unnecesarry. Just override Block#hasTileEntity and Block#createTileEntity. 

 

Also blockbase is an anti-pattern.

 

Don't invoke EntityPlayer#openGui on the client at all. Forge will do the networking for you. This is likely the cause of your issue.

 

Your health property is lost upon (de)serialization. You should probably include this in your (de)serialization methods too.

 

public int quantityDropped(Random random)
    {
        return 1;
    }

The default implementation already returns 1. Why did you override it?

 

Quote

Integer.valueOf(MathHelper.clamp(level, 0, 3)))

MathHelper.clamp already returns an int. Why do you need to ask the Integer class to get the value from it?

 

Quote

return ((Integer)state.getValue(FULLNESS)).intValue();

Same here.

 

Quote

this.FULLNESS.equals(fullness);

...What? FULLNESS is static thus your IDE should be screaming at you for using this access keyword. Also why are you comparing it to the argument? You do know that Object#equals returns a boolean that indicates the result of comparing two objects.

 

Quote

this.HEALTH.equals(health);

Same here.

 

if (tileentity != null)
        {
            tileentity.validate();
            worldIn.setTileEntity(pos, tileentity);
        }

You don't need to do this. Just override TileEntity#shouldRefresh in your TE class. Actually you are already doing that so there is no need for this code at all.

 

Quote

public class TileEntityFoodDish extends TileEntity implements ICapabilityProvider

TileEntity already implements ICapabilityProvider. You don't need to add this interface again.

 

Quote

BlockFoodDish blockfooddish;

Blocks are singletons. You can use @ObjectHolder to get the reference if you need it.

 

int metadata = getBlockMetadata();
		return new SPacketUpdateTileEntity(this.pos, metadata, nbt);

This is not what that parameter wants from you. As you are using a modded TE you can pass anything to it.

 

public BlockFoodDish getFoodDish()
	{
		return this.blockfooddish;
	}

Again, blocks are singletons. You do not need to store a block reference in each instance of your TE.

 

Quote

this.blockType = this.getBlockType();

...Why? It is already set to that.

Posted

I announced that I'll be releasing the complete version of the mod's first update in 1.11, so I'll be continuing to work in 1.11 for now.

There are a couple things here that were added unnecessarily, I'll take a look at those-- some can probably be deleted, while others may be for things I intend to alter later.  I will definitely take a look at the EntityPlayer#openGUI part, as if that is the cause then this may be a simple fix.  I'll update this later when I've had time to take a look at these suggestions.

Thank you for your advice.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Im trying to build my mod using shade since i use the luaj library however i keep getting this error Reason: Task ':reobfJar' uses this output of task ':shadowJar' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed. So i try adding reobfJar.dependsOn shadowJar  Could not get unknown property 'reobfJar' for object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler. my gradle file plugins { id 'eclipse' id 'idea' id 'maven-publish' id 'net.minecraftforge.gradle' version '[6.0,6.2)' id 'com.github.johnrengelman.shadow' version '7.1.2' id 'org.spongepowered.mixin' version '0.7.+' } apply plugin: 'net.minecraftforge.gradle' apply plugin: 'org.spongepowered.mixin' apply plugin: 'com.github.johnrengelman.shadow' version = mod_version group = mod_group_id base { archivesName = mod_id } // Mojang ships Java 17 to end users in 1.18+, so your mod should target Java 17. java.toolchain.languageVersion = JavaLanguageVersion.of(17) //jarJar.enable() println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" minecraft { mappings channel: mapping_channel, version: mapping_version copyIdeResources = true runs { configureEach { workingDirectory project.file('run') property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.console.level', 'debug' arg "-mixin.config=derp.mixin.json" mods { "${mod_id}" { source sourceSets.main } } } client { // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. property 'forge.enabledGameTestNamespaces', mod_id } server { property 'forge.enabledGameTestNamespaces', mod_id args '--nogui' } gameTestServer { property 'forge.enabledGameTestNamespaces', mod_id } data { workingDirectory project.file('run-data') args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') } } } sourceSets.main.resources { srcDir 'src/generated/resources' } repositories { flatDir { dirs './libs' } maven { url = "https://jitpack.io" } } configurations { shade implementation.extendsFrom shade } dependencies { minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" implementation 'org.luaj:luaj-jse-3.0.2' implementation fg.deobf("com.github.Virtuoel:Pehkui:${pehkui_version}") annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' minecraftLibrary 'luaj:luaj-jse:3.0.2' shade 'luaj:luaj-jse:3.0.2' } // Example for how to get properties into the manifest for reading at runtime. tasks.named('jar', Jar).configure { manifest { attributes([ 'Specification-Title' : mod_id, 'Specification-Vendor' : mod_authors, 'Specification-Version' : '1', // We are version 1 of ourselves 'Implementation-Title' : project.name, 'Implementation-Version' : project.jar.archiveVersion, 'Implementation-Vendor' : mod_authors, 'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), "TweakClass" : "org.spongepowered.asm.launch.MixinTweaker", "TweakOrder" : 0, "MixinConfigs" : "derp.mixin.json" ]) } rename 'mixin.refmap.json', 'derp.mixin-refmap.json' } shadowJar { archiveClassifier = '' configurations = [project.configurations.shade] finalizedBy 'reobfShadowJar' } assemble.dependsOn shadowJar reobf { re shadowJar {} } publishing { publications { mavenJava(MavenPublication) { artifact jar } } repositories { maven { url "file://${project.projectDir}/mcmodsrepo" } } }  
    • All versions of Minecraft Forge suddenly black screen even without mods (tried reinstalling original Minecraft, Java, updating drivers doesn't work)
    • When i join minecraft all ok, when i join world all working fine, but when i open indentity menu, i get this The game crashed whilst unexpected error Error: java.lang.NullPointerException: Cannot invoke "top.ribs.scguns.common.Gun$Projectile.getDamage()" because "this.projectile" is null crash report here https://paste.ee/p/0vKaf
  • Topics

×
×
  • Create New...

Important Information

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