Jack Richard
-
Posts
30 -
Joined
-
Last visited
Posts posted by Jack Richard
-
-
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
QuoteMod (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
Quotejava.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!
-
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.
-
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!
-
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;
-
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...
-
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.
-
3 minutes ago, ChampionAsh5357 said:
In the development environment or the finalized jar?
It runs fine with runClient, but when it's built, it's not recognized at all.
-
All my libraries are inside the jar now, but Minecraft does not recognize it as a mod anymore...
-
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.
-
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.
-
I'm trying to use this guide now. Forge doesn't seem to have srgExtra or extraLines anymore, is there an alternative?
-
Is it just crossed out, or not allowing the game to run? If you're using IntelliJ or Eclipse, you'll see a line through a class or method name if it's deprecated. It shouldn't crash the game because of that.
-
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.
-
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?
-
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.
-
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!
-
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.
-
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.
-
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.
-
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.
-
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.
-
41 minutes ago, poopoodice said:
Have you save and read the information you've stored in the tileentity using write() and read()?
Yes, the data is stored and read through read() and write()
-
I've been able to make it work now, using the NBT tags in the Item class, I'm able to pass the ItemStack to the screen.
Thanks!
-
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.
[1.15.2] Minecraft Registry Problem When Loading from Jar
in Modder Support
Posted
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!