Jump to content

Recommended Posts

Posted

Hello,

So I have a capability that stores a value within chunks that can be accessed across items/blocks within my mod. This value, however, I want to increase back to a default value if it has decreased at all. I want this value to increase very slowly, but I don't exactly know how I should do this as efficiently as possible to prevent lag. I'm already subscribed to some events: ChunkDataEvent.Save, ChunkDataEvent.Load, ChunkEvent.Load, ChunkEvent.Unload and ChunkWatchEvent. Here is the capability class that I'm using:

  Reveal hidden contents
 

All other class references can be found on my github in the folder labeled 'voidenergy'. 

 

Thank you.

Posted

Use the WorldTickEvent and do whatever it is you need to do there. If you are concerned about performance - don't be, there aren't that many chunks loaded in the world at any given time to be concerned. You can optimize this further by putting the data that needs updating in a Stack or something(when the value changes below default, since this is when you want to do the restoration), then iterate over that stack and process the value in the data and either add it back(after you are done iterating of course) if it still needs updating or doing nothing.

Also I might be mistaken here but isn't a Chunk itself a ICapabilityProvider? As in couldn't you attach your capability directly to the chunk, rather than to the world?

Posted (edited)
  On 11/24/2018 at 5:49 AM, V0idWa1k3r said:

Use the WorldTickEvent and do whatever it is you need to do there. If you are concerned about performance - don't be, there aren't that many chunks loaded in the world at any given time to be concerned. You can optimize this further by putting the data that needs updating in a Stack or something(when the value changes below default, since this is when you want to do the restoration), then iterate over that stack and process the value in the data and either add it back(after you are done iterating of course) if it still needs updating or doing nothing.

Expand  
 

So I'd get the persistent chunks from the event.world (which I'm presuming gives all currently loaded chunks), get their capability that I've created and then check if its below said default value?

  On 11/24/2018 at 5:49 AM, V0idWa1k3r said:

 Also I might be mistaken here but isn't a Chunk itself a ICapabilityProvider? As in couldn't you attach your capability directly to the chunk, rather than to the world?

Expand  

 Would this require a drastic change in how I'm saving/loading the chunks' 'energy'? As stated, this is derived from an example that I'm trying to learn from. (Choonster). I am aware by me using ChunkDataEvents (which are soon to be deprecated) makes this code obsolete when transitioning to 1.13. So a small list of things that would have to be done in order to keep some kind of compatibility would be nice. As storing things using capabilities like this is still somewhat new to me.

 

Thanks.

Edited by unassigned
Posted
  On 11/24/2018 at 6:10 AM, unassigned said:

So I'd get the persistent chunks from the event.world (which I'm presuming gives all currently loaded chunks), get their void capability and then check if its below said default value?

Expand  

Don't you already have a set of all chunks currently in posession of your data? Your VoidEnergyHolder stores the data somehow, presumably in something like a Map<ChunkPos, IVoidStorage>? You can iterate all values of a map just fine. With my suggestion you don't even need to do that though.

 

  On 11/24/2018 at 6:10 AM, unassigned said:

Would this require a drastic change in how I'm saving/loading the chunks' 'energy'?

Expand  

Why yes it would. Instead of manually listening to the save/load events you would have to do... absolutely nothing, as the capability, as long as it implements INBTSerializable/ICapabilitySerializable would do everything for you.

All other code you have would remain unaffected(mostly, you would retreive the capability a bit differently but that's it).

Posted
  On 11/24/2018 at 6:15 AM, V0idWa1k3r said:

Why yes it would. Instead of manually listening to the save/load events you would have to do... absolutely nothing, as the capability, as long as it implements INBTSerializable/ICapabilitySerializable would do everything for you.

All other code you have would remain unaffected(mostly, you would retreive the capability a bit differently but that's it).

Expand  

Okay, I'll do this after I get this framework done. 

 

  On 11/24/2018 at 6:15 AM, V0idWa1k3r said:

Don't you already have a set of all chunks currently in posession of your data? Your VoidEnergyHolder stores the data somehow, presumably in something like a Map<ChunkPos, IVoidStorage>? You can iterate all values of a map just fine. With my suggestion you don't even need to do that though.

Expand  

Yeah, I can use this map and iterate through the values, however, how would I slow this down to a rate that I would like. In a TE I would normally use the ticks % some-val == 0 to slow, however, I don't see this applicable within the world as a whole.

Posted (edited)
  On 11/24/2018 at 6:49 AM, V0idWa1k3r said:

Why? What stops you from having a ticksHappend variable per world, incrementing it and doing the same % operator on it as you would in a TE?

Expand  

Where would I be keeping this variable stored? Would it be with the capability, or could I do some kind of easier implementation? (ex. would I localize it within the TickEvent?)

 

As well, I've gone through the capability code and tried my best to port this to a serialized capability. All methods that are currently listed as deprecated are going to be removed, however, I am not sure if this is actually correct. Here is the code I have now:

  Reveal hidden contents
 

And I pushed another version to github if you are interested in other classes. Thanks for your help.

Edited by unassigned
elaboration
Posted
  On 11/24/2018 at 7:06 AM, unassigned said:

Where would I be keeping this variable stored? Would it be with the capability, or could I do some kind of easier implementation? (ex. would I localize it within the TickEvent?)

Expand  

Define "localize". You can store it either in your capability or in a map, that doesn't matter.

 

Since your capability is now stored per chunk you need to iterate over chunks in the world and get the capability instead of iterating over data in your world capability.

 

  On 11/24/2018 at 7:06 AM, unassigned said:

however, I am not sure if this is actually correct.

Expand  

Finish your code and provide any problems you might or might not have.

Posted
  On 11/24/2018 at 7:16 AM, V0idWa1k3r said:

Finish your code and provide any problems you might or might not have.

Expand  

Okay, so this may or may not be the correct way of doing this, however, I attached an integer onto the capability for keeping track of 'ticks' it has been below the default value. This value is saved within its NBT and is process across the client and server. However, I ran into an issue with the for loop, as it never becomes active, presumably because I'm not correctly trying to access the chunks loaded. Maybe I do not understand the method for getting the currently loaded chunks. I'd like to note I cannot use that HashMap I was using before, as its basically removed from the capability due to moving to serialization. 

 

  Reveal hidden contents
 

And by 'it never becomes active': I mean that "outside for" is printed at the proper rate, while "within for" is never printed.

Again, I have pushed all code to the github if you'd like to see more. 

Posted

World#getPersistentChunks returns all chunks that are kept loaded by forge's chunk loading system, not all currently loaded chunks.

You could still keep a list of all loaded chunks by subscribing to the ChunkEvent.Load/Unload and keeping the chunk in question in a collection of some kind.

Posted
  On 11/24/2018 at 8:25 AM, V0idWa1k3r said:

World#getPersistentChunks returns all chunks that are kept loaded by forge's chunk loading system, not all currently loaded chunks.

 You could still keep a list of all loaded chunks by subscribing to the ChunkEvent.Load/Unload and keeping the chunk in question in a collection of some kind.

Expand  

Okay, this worked well I believe, here is the code for the chunk processing:

        @SubscribeEvent
        public static void chunkUnload(final ChunkEvent.Unload event) {
            ChunkPos chunkPos = event.getChunk().getPos();

            IVoidStorage voidStorage = getVoidEnergy(event.getChunk());
            if(voidStorage == null) return;

            VOID_CHUNKS_LOADED.remove(chunkPos);
        }

        @SubscribeEvent
        public static void chunkLoad(final ChunkEvent.Load event) {
            ChunkPos chunkPos = event.getChunk().getPos();

            IVoidStorage voidStorage = getVoidEnergy(event.getChunk());
            if(voidStorage == null) return;

            VOID_CHUNKS_LOADED.put(chunkPos, voidStorage);
        }

 

And here is my new TickEvent:

  Reveal hidden contents
 

 

 

Everything seems to be working fine, other than my values that are checked with the client do no match the values that get output by console here. So obviously, this leads me to think that I'm not sending a packet somewhere, however, I do not know where. I send one during ChunkWatchEvent and every time void related things (ticks/energy) is changed.

 

Here is the WatchEvent:

  Reveal hidden contents
 

 

and here is the VoidEnergy class which is the framework behind the whole void system.

  Reveal hidden contents
 

Thanks for your help.

Posted
  On 11/24/2018 at 9:01 AM, unassigned said:

if(voidStorage == null) return;

Expand  

This should never be the case since you are adding the capability to each and every chunk. And if this is the case - something is seriously messed up and you should just crash the game.

 

  On 11/24/2018 at 9:01 AM, unassigned said:

my values that are checked with the client do no match the values that get output by console here. So obviously, this leads me to think that I'm not sending a packet somewhere, however, I do not know where. I send one during ChunkWatchEvent and every time void related things (ticks/energy) is changed.

Expand  

Use the debugger to see 

  • When the update packet is sent to the client, if it is sent at all
  • What are the contents of said packet
  • What data arrives at the client
  • What the client does with that data
Posted (edited)
  On 11/24/2018 at 9:06 AM, V0idWa1k3r said:

Use the debugger to see 

  • When the update packet is sent to the client, if it is sent at all
  •  What are the contents of said packet
  • What data arrives at the client
  • What the client does with that data
Expand  
2

I've been testing for about an hour now, and cannot seem to put a finger on what is happening. I've added a network sync line in the TickEvent when the amount of energy stored is updated.

                        ((VoidEnergy) voidStorage).receiveVoid((world.rand.nextInt(10)+ 1), false);
                        PlentifulUtilities.network.sendToAll(new MessageUpdateVoidValue(voidStorage));

And within my network class, I've added debugs to tell me what messages are being sent. Here is what the debugger shows when the threshold of energy drops below the default value:

[11:47:57] [Server thread/INFO] [STDOUT]: [unassigned.plentifulutilities.voidenergy.capability.VoidEnergy:onVoidChanged:114]: sending packet!
[11:47:58] [main/INFO] [STDOUT]: [unassigned.plentifulutilities.network.MessageUpdateVoidValue$Handler:lambda$onMessage$0:82]: Pack received and updating! SV: 905 | ticks Sent: 0
[11:47:58] [main/INFO] [STDOUT]: [unassigned.plentifulutilities.network.MessageUpdateVoidValue$Handler:lambda$onMessage$0:82]: Pack received and updating! SV: 980 | ticks Sent: 0
[11:47:58] [main/INFO] [STDOUT]: [unassigned.plentifulutilities.network.MessageUpdateVoidValue$Handler:lambda$onMessage$0:82]: Pack received and updating! SV: 988 | ticks Sent: 0
[11:47:58] [main/INFO] [STDOUT]: [unassigned.plentifulutilities.network.MessageUpdateVoidValue$Handler:lambda$onMessage$0:82]: Pack received and updating! SV: 992 | ticks Sent: 0
[11:47:58] [main/INFO] [STDOUT]: [unassigned.plentifulutilities.network.MessageUpdateVoidValue$Handler:lambda$onMessage$0:82]: Pack received and updating! SV: 1002 | ticks Sent: 0

(do not worry about the ticks sent, I disabled that functionality for now as I try to fix this)

As you can see, it properly gets itself back to above 1000, however, the Item that checks this will still display the first value of 905.

33271eda5db312f1b75e01899d0d0a83.png

What is even more interesting is that the Item I have to decrease this value WILL sync up with the client value that is displayed.

Here are the two items in question:

the 'setter' item:

  Reveal hidden contents
 

The 'getter' item:

  Reveal hidden contents
 

What it seems is that the items seem to sync up fine, however, when I try to change the value within the TickEvent, it never syncs, even though it clearly says packets are being sent to the client with the correct data. I pushed another version, if you'd like to see where networking, view the 'network' folder, and for all the void energy related things, view the 'voidenergy' folder.

 

Thank you for your help.

Edited by unassigned
bugged formatting
Posted

Your issue is the fact that you were operating with different data all this time. You were iterating over the entries in the map, but needed to iterate over actual data attached to the chunks. Because the data was different(as in the VoidEnergy instances were different) there were all kinds of issues. 

Don't store the data in the map, in fact ditch the map alltogether. Have a list, or an array, or something containing all ChunkPositions of loaded chunks. Also store this in the world capability since there are multiple world instances(dimensions). Your packet will also need a dimension ID. Iterate over those positions and get the actual data attached to the chunk. Then do whatever it is you need to do with it.

Also probably don't send it each tick.

Posted
  On 11/25/2018 at 5:26 AM, V0idWa1k3r said:

Don't store the data in the map, in fact ditch the map alltogether. Have a list, or an array, or something containing all ChunkPositions of loaded chunks. Also store this in the world capability since there are multiple world instances(dimensions).

Expand  

So I'd create another capability with a storage class similar to what I was doing with IVoidHolder? One that just holds that list of ChunkPos and stores to the world? Would I still populate this list using the onChunkLoad / onChunkUnload events?

 

Posted

Okay, I have fixed up my code and it is now working fine. I ended up reusing my IVoidHolder and IVoidHolderModifiable so that the list can still be stored and the chunks be accessed under one instance. As well, I used sendToAllTracking to include the dimension it is in when sending the packet. All of these combined allowed me to access the chunks and modify them as I wish.

 

Thank you for your help.

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.