Jump to content

[1.10.2] [SOLVED] Saving additional information to chunk data


Bektor

Recommended Posts

22 hours ago, Choonster said:

 

Any mod that displays an energy value on the client needs to sync it somehow.

 

If it's an energy bar in a GUI, this is usually handled through the Container (which syncs the value when it changes). If it's rendered outside of a GUI, it could either be always synced when the value changes or synced on demand when the value needs to be rendered.

Ok, I got the capability system now implemented. 

 

Does the ChunkWatchEvent.Watch gets only called once, for example the player goes into this chunk and the event gets called and then never again until the player goes into this chunk again? So it does not get called like every 20 ticks when a player is in this chunk.

 

I'm also wondering how I should access my capability from a block to let this block update the value stored in the chunk, as I've only worked with capabilities where the data is directly saved to the block and thus every block had it own instance of in that case the EnergyStorage class.

And how do I access the value stored in the chunk in events like CropGrowEvent or SaplingGrowTreeEvent to do something within those events when the value reaches a critical point.

Should I just do something like this:

final IChunkEnergy chunkEnergy = getChunkEnergy(player.getEntityWorld(), event.getChunk());

 

Edited by Bektor

Developer of Primeval Forest.

Link to comment
Share on other sites

20 minutes ago, Bektor said:

Does the ChunkWatchEvent.Watch gets only called once, for example the player goes into this chunk and the event gets called and then never again until the player goes into this chunk again? So it does not get called like every 20 ticks when a player is in this chunk.

 

It gets fired once when the player starts watching the chunk and won't be fired for that player and chunk again until they stop watching it and then start watching it again. It's not fired constantly while a player is in the chunk.

 

23 minutes ago, Bektor said:

I'm also wondering how I should access my capability from a block to let this block update the value stored in the chunk, as I've only worked with capabilities where the data is directly saved to the block and thus every block had it own instance of in that case the EnergyStorage class.

And how do I access the value stored in the chunk in events like CropGrowEvent or SaplingGrowTreeEvent to do something within those events when the value reaches a critical point.

 

Access the holder capability through the World and then use it to get the energy storage for the chunk. I created helper methods in CapabilityChunkEnergy to get the IChunkEnergy for a Chunk or World and ChunkPos.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

2 hours ago, Choonster said:

 

It gets fired once when the player starts watching the chunk and won't be fired for that player and chunk again until they stop watching it and then start watching it again. It's not fired constantly while a player is in the chunk.

 

 

Access the holder capability through the World and then use it to get the energy storage for the chunk. I created helper methods in CapabilityChunkEnergy to get the IChunkEnergy for a Chunk or World and ChunkPos.

Ok, thx. I've got just a little problem:

 

I'm sending a message to the player via ChunkWatchEvent.Watch to test if the code, but now I'm getting the following error inside of the message handler:

 

[22:59:21] [Client thread/FATAL]: Error executing task
java.util.concurrent.ExecutionException: java.lang.NullPointerException
	at java.util.concurrent.FutureTask.report(Unknown Source) ~[?:1.8.0_131]
	at java.util.concurrent.FutureTask.get(Unknown Source) ~[?:1.8.0_131]
	at net.minecraft.util.Util.runTask(Util.java:29) [Util.class:?]
	at net.minecraft.client.Minecraft.runGameLoop(Minecraft.java:1108) [Minecraft.class:?]
	at net.minecraft.client.Minecraft.run(Minecraft.java:406) [Minecraft.class:?]
	at net.minecraft.client.main.Main.main(Main.java:118) [Main.class:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_131]
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_131]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_131]
	at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_131]
	at net.minecraft.launchwrapper.Launch.launch(Launch.java:135) [launchwrapper-1.12.jar:?]
	at net.minecraft.launchwrapper.Launch.main(Launch.java:28) [launchwrapper-1.12.jar:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_131]
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_131]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_131]
	at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_131]
	at net.minecraftforge.gradle.GradleStartCommon.launch(GradleStartCommon.java:97) [start/:?]
	at GradleStart.main(GradleStart.java:26) [start/:?]
Caused by: java.lang.NullPointerException
	at minecraftplaye.justanotherenergy.common.network.msg.MessageChunkPollution$MessageChunkPollutionHandler.lambda$0(MessageChunkPollution.java:80) ~[MessageChunkPollution$MessageChunkPollutionHandler.class:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) ~[?:1.8.0_131]
	at java.util.concurrent.FutureTask.run(Unknown Source) ~[?:1.8.0_131]
	at net.minecraft.util.Util.runTask(Util.java:28) ~[Util.class:?]
	... 15 more

 

Here is the code:

    public static class MessageChunkPollutionHandler implements IMessageHandler<MessageChunkPollution, IMessage> {
        
        @Override
        public IMessage onMessage(MessageChunkPollution message, MessageContext ctx) {
            IThreadListener mainThread = Minecraft.getMinecraft();
            mainThread.addScheduledTask(() -> {
                final World world = Minecraft.getMinecraft().world;
                
                final IChunkPollutionHolder chunkPollutionHolder = CapabilityPollution.getChunkPollutionHolder(world);
                if(chunkPollutionHolder == null) return;
                
                final IChunkPollution chunkPollution = chunkPollutionHolder.getChunkPollution(new ChunkPos(message.chunkPosX, message.chunkPosZ));
                System.err.println("t: " + chunkPollution + " tt: " + chunkPollution == null); // output: false
                chunkPollution.setPollution(message.pollution); // Error occurs here
            });
            
            // No respond packet
            return null;
        }
    }

 

Developer of Primeval Forest.

Link to comment
Share on other sites

10 hours ago, Bektor said:

I'm sending a message to the player via ChunkWatchEvent.Watch to test if the code, but now I'm getting the following error inside of the message handler:

 

The IChunkPollution for that chunk was null.

 

Are you creating a default IChunkPollution in ChunkEvent.Load when the Chunk doesn't already have one? This is required for client-side chunks, since ChunkDataEvent.Load only fires on the server.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

9 hours ago, Choonster said:

 

The IChunkPollution for that chunk was null.

 

Are you creating a default IChunkPollution in ChunkEvent.Load when the Chunk doesn't already have one? This is required for client-side chunks, since ChunkDataEvent.Load only fires on the server.

Yes.

 

    @SubscribeEvent
    public void chunkLoad(ChunkEvent.Load event) {
        final World world = event.getWorld();
        final ChunkPos pos = event.getChunk().getChunkCoordIntPair();
        
        if(world == null || !world.hasCapability(CHUNK_POLLUTION_CAPABILITY, DEFAULT_FACING))
            return;
        final IChunkPollutionHolder chunkPollutionHolder = world.getCapability(CHUNK_POLLUTION_CAPABILITY, DEFAULT_FACING);
        if(chunkPollutionHolder == null) return;
        
        // don't create a IChunkPollution twice for a chunk
        if(chunkPollutionHolder.getChunkPollution(pos) != null) return;
        
        final IChunkPollution chunkPollution = new ChunkPollution(world, pos);
        chunkPollutionHolder.setChunkPollution(pos, chunkPollution);
    }

 

Developer of Primeval Forest.

Link to comment
Share on other sites

Now that I look at your code closer, the IChunkPollution couldn't have been null on line 80 if it wasn't null on the previous line.

 

Set a breakpoint on that line and look at the values of the local variables when it's hit, which of them is null?

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

15 minutes ago, Choonster said:

Now that I look at your code closer, the IChunkPollution couldn't have been null on line 80 if it wasn't null on the previous line.

 

Set a breakpoint on that line and look at the values of the local variables when it's hit, which of them is null?

Hm... It doesn't really bring me anywhere.. Setting the breakpoint at line 80 will just result into it that eclipse shows me that neither the world, nor the chunkPollutionHolder or the chunkPollution values are null.

Putting in this line of code results into this:

System.err.println(message.pollution); //output :0.0
System.err.println(message); // output: MessageChunkPollution@3fbdd7c8

Opening the chunkPollutionHolder shows me that the keySet and the values from the HashMap are null while the entrySet contains values.

Developer of Primeval Forest.

Link to comment
Share on other sites

9 minutes ago, Bektor said:

Hm... It doesn't really bring me anywhere.. Setting the breakpoint at line 80 will just result into it that eclipse shows me that neither the world, nor the chunkPollutionHolder or the chunkPollution values are null.

Putting in this line of code results into this:


System.err.println(message.pollution); //output :0.0
System.err.println(message); // output: MessageChunkPollution@3fbdd7c8

 

That's strange. Can you reliably reproduce the NullPointerException, or has it only happened once?

 

Try removing the breakpoint on the line that throws the exception and replacing it with an exception breakpoint for NullPointerException. If the breakpoint is hit and the exception is being thrown on the same line as before, look at what's null.

 

Quote

Opening the chunkPollutionHolder shows me that the keySet and the values from the HashMap are null while the entrySet contains values.

 

That's normal, keySet and values are only created when they're first requested.

Edited by Choonster

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

9 minutes ago, Choonster said:

 

That's strange. Can you reliably reproduce the NullPointerException, or has it only happened once?

 

Try removing the breakpoint on the line that throws the exception and replacing it with an exception breakpoint for NullPointerException. If the breakpoint is hit and the exception is being thrown on the same line as before, look at what's null.

 

 

That's normal, keySet and values are only created when they're first requested.

How can I create an exception breakpoint fpr NullPointerExceptions in eclipse?

Also the NPE still happens. I just removed the breakpoint, pressed resume and got it directly while I could click on resume before like a thousand times without anything happening.

I'm also not entirely sure under which situations it occurs, I just now it happens always when the world loads.

Developer of Primeval Forest.

Link to comment
Share on other sites

52 minutes ago, Bektor said:

How can I create an exception breakpoint fpr NullPointerExceptions in eclipse?

 

Look at the documentation or use your search engine of choice.

 

If it's anything like IDEA, the Debug window should have a button that shows all breakpoints. Clicking this will bring up a window that also allows you to create new breakpoints.

Edited by Choonster

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

10 minutes ago, Choonster said:

 

Look at the documentation or use your search engine of choice.

 

If it's anything like IDEA, the Debug window should have a button that shows all breakpoints. Clicking this will bring up a window that also allows you to create new breakpoints.

Hm, seems like eclipse has something like that, too. Thought I can't set the line of an exception breakpoint nor the class and for normal conditional breakpoints I have to write normal null checks like I would inside of the code, just inside of the breakpoint.

Developer of Primeval Forest.

Link to comment
Share on other sites

Just now, Bektor said:

Hm, seems like eclipse has something like that, too. Thought I can't set the line of an exception breakpoint nor the class and for normal conditional breakpoints I have to write normal null checks like I would inside of the code, just inside of the breakpoint.

 

You shouldn't need to set the class/line or add any null checks, the breakpoint will be hit as soon as something throws a NullPointerException. Once your code throws the exception and hits the breakpoint, look at the debugger to see what's null.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

15 minutes ago, Choonster said:

 

You shouldn't need to set the class/line or add any null checks, the breakpoint will be hit as soon as something throws a NullPointerException. Once your code throws the exception and hits the breakpoint, look at the debugger to see what's null.

Ok. Thougt now eclipse tells me always this: Source not found. Edit Source Lookup Path.

There it just gives me the option to select default and then it works. I click on resume and the same thing happens again.

 

EDIT: Ok, after literally pressing the Resume button like a 100 times I got to the point where my code starts... There it stopped on this line:

chunkPollution.setPollution(message.pollution);

The debug window shows me that chunkPollution is null while the console window showed me false just a few ms before for this statement: chunkPollution == null.

 

Console output:

Quote

false
[20:56:25] [Client thread/INFO] [STDERR]: [minecraftplaye.justanotherenergy.common.network.msg.MessageChunkPollution$MessageChunkPollutionHandler:lambda$0:80]: minecraftplaye.justanotherenergy.common.network.msg.MessageChunkPollution@334a373a
[20:56:25] [Server thread/WARN]: Can't keep up! Did the system time change, or is the server overloaded? Running 5453ms behind, skipping 109 tick(s)

.Code:

                final IChunkPollution chunkPollution = chunkPollutionHolder.getChunkPollution(new ChunkPos(message.chunkPosX, message.chunkPosZ));
                System.err.println("t: " + chunkPollution + " tt: " + chunkPollution == null);
                System.err.println(message);
                chunkPollution.setPollution(message.pollution);

Debug Window:

Quote

world = WorldClient (id=670)

chunkPollutionHolder = chunkPollutionHolder (id=674)

chunkPollution = null

 

Edited by Bektor

Developer of Primeval Forest.

Link to comment
Share on other sites

1 minute ago, Bektor said:

Ok. Thougt now eclipse tells me always this: Source not found. Edit Source Lookup Path.

There it just gives me the option to select default and then it works. I click on resume and the same thing happens again.

 

It sounds like Eclipse is showing you NullPointerExceptions being thrown in external code that it doesn't have source code for.

 

Restrict the breakpoint to your message handler class by doing the following:

  • Show the Breakpoints view (Window > Show View > Other... > Debug > Breakpoints)
  • In the Breakpoints view, right click on the exception breakpoint and select Breakpoint Properties...
  • In the Properties window, select Filtering in the left column and then click Add Class...
  • Type in the name of your message handler class, select it in the search results and click OK.
  • Click OK in the Properties window.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

10 minutes ago, Choonster said:

 

It sounds like Eclipse is showing you NullPointerExceptions being thrown in external code that it doesn't have source code for.

 

Restrict the breakpoint to your message handler class by doing the following:

  • Show the Breakpoints view (Window > Show View > Other... > Debug > Breakpoints)
  • In the Breakpoints view, right click on the exception breakpoint and select Breakpoint Properties...
  • In the Properties window, select Filtering in the left column and then click Add Class...
  • Type in the name of your message handler class, select it in the search results and click OK.
  • Click OK in the Properties window.

Oh, ok. Thx.

 

Console output:

Quote

[21:19:46] [Client thread/INFO] [STDERR]: [minecraftplaye.justanotherenergy.common.network.msg.MessageChunkPollution$MessageChunkPollutionHandler:lambda$0:80]: minecraftplaye.justanotherenergy.common.network.msg.MessageChunkPollution@59843821
false

Code:

 

                final IChunkPollution chunkPollution = chunkPollutionHolder.getChunkPollution(new ChunkPos(message.chunkPosX, message.chunkPosZ));
                System.err.println("t: " + chunkPollution + " tt: " + chunkPollution == null);
                System.err.println(message);
                chunkPollution.setPollution(message.pollution);

Debug Window:

Quote

world = WorldClient (id=670)

chunkPollutionHolder = chunkPollutionHolder (id=674)

chunkPollution = null

Developer of Primeval Forest.

Link to comment
Share on other sites

That output doesn't appear to match your code. Where did the "false" message come from? What did the first System.err.println call output?

 

It appears that chunkPollution is indeed null. Is the ChunkEvent.Load handler definitely being called? Was it called for the chunk that produces this error?

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Just now, Choonster said:

That output doesn't appear to match your code. Where did the "false" message come from? What did the first System.err.println call output?

 

It appears that chunkPollution is indeed null. Is the ChunkEvent.Load handler definitely being called? Was it called for the chunk that produces this error?

It should have been called. I registered the entire class as a event handler using MinecraftForge.EVENT_BUS.register(new CapabilityPollution()); in FMLInitializationEvent within the ServerProxy.

And all events have the @SubscribeEvent annotation on them, so they should be recognized and called.

 

Just change a bit of the code to get more information out of it:

As I am no longer using System.err.println but instead System.out.println the order of the output matches now also the order of the code. ;)

 

Quote

chunkPollution: null
 Position: -1 | -1
Player Position: 10 | 12

 

                final IChunkPollution chunkPollution = chunkPollutionHolder.getChunkPollution(new ChunkPos(message.chunkPosX, message.chunkPosZ));
                System.out.println("chunkPollution: " + chunkPollution);
                System.out.println("Position: " + message.chunkPosX + " | " + message.chunkPosZ);
                System.out.println("Player Position: " + ((int)(Minecraft.getMinecraft().player.posX) >> 4) + " | " + ((int)(Minecraft.getMinecraft().player.posZ) >> 4));
                chunkPollution.setPollution(message.pollution);

 

So it seems like the error occurs inside of a chunk in which the player currently is not.

Also this is the data from the map from my chunkPollutionHolder.

Quote

{[-1, 1]=ChunkPollution@2f319ca3, 
[-1, 6]=ChunkPollution@8a2e3b6, 
[-1, 3]=ChunkPollution@2942e7cb, 
[-1, 2]=ChunkPollution@2fa015bc, 
[-1, 5]=ChunkPollution@1e400e08, 
[-1, 7]=ChunkPollution@1177e2c4, 
[-1, 10]=ChunkPollution@36a8ef12, 
[-1, 8]=ChunkPollution@29881522, 
[-1, 9]=ChunkPollution@37a66e55, 
[-1, 4]=ChunkPollution@3ab59822}

As of the chunk which is causing the problem isn't in the list I guess it wasn't called at the point where the client player added it to it's watch list.

 

 

Developer of Primeval Forest.

Link to comment
Share on other sites

If I am correct and the problem is caused by it that data was sent to the client for which the chunk events haven't run yet, how can I prevent this from occuring?

 

EDIT: fixed. Just implemented an extra null check for IChunkPollution. I hope nothing else get's messed up because of this.

Seems also that other code parts didn't had an npe because of instanceof checks which also check for null.

Edited by Bektor
solved

Developer of Primeval Forest.

Link to comment
Share on other sites

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



×
×
  • Create New...

Important Information

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