Jump to content

Refresh Content in Written Book(?)


jayxo

Recommended Posts

Hello! I have a book that writes down a players life information. I.e. how long they’ve been living, and when they die on that life, how long they lasted and what they died from.

My question is, is it possible to update content in a written book when it’s opened? Becuase the way it works now, you have to get the book with a command instead of it refreshing it’s content automatically.

Any help would be extremely helpful! Thank you.

Here’s a pastebin of the current class that writes in the book: https://pastebin.com/s6X05Nzz

Link to comment
Share on other sites

  • 2 weeks later...

I'm assuming that it is just a vanilla book with custom NBT, not your own custom item?

If that is the case you could listen to the use item event (sorry, I can't remember the name of it off the top of my head), check for the book being used (opened) and sync the data with the item.

Edited by Alpvax
Link to comment
Share on other sites

  • 2 weeks later...
On 9/27/2021 at 7:21 AM, Alpvax said:

No, I actually meant PlayerInteractEvent.RightClickItem, books don't count as being "used" I don't think

sorry for such a late response! i actually tried that before, but it would always show the player who opened it info. like i would open your book, and it would display my players capability information instead of yours.

https://pastebin.com/3qpwP8BF

Edited by jayxo
Link to comment
Share on other sites

On 10/11/2021 at 4:21 PM, jayxo said:

it would always show the player who opened it info.

https://pastebin.com/3qpwP8BF

I assumed that was what you wanted. Currently you get the capability of the player opening the book:

@SubscribeEvent
public void onUse(PlayerInteractEvent.RightClickItem event) {
    PlayerEntity player = event.getPlayer();
    ...

You need to use the player who "owns" the book instead. So store the "owner's" id in the book somehow (NBT/capablility), then when the book is opened, get the player from the id (they may not exist/be offline, in which case you can't reasonably update), then update the data.

It might be a better idea to change to a level (overworld) capability / saveddata if you need to access the data for offline players, then retrieve that data for displaying in your book.

As die7 says, it will probably be better to create a custom gui (based on the vanilla book screen, you can possibly subclass it, although I'm not sure), then retrieve the latest data on demand, rather than updating the item nbt each time.

Link to comment
Share on other sites

1 hour ago, Alpvax said:

I assumed that was what you wanted. Currently you get the capability of the player opening the book

this was actually what one of the issues i had was, i wanted to be able to look at any players book without it always showing my capability information.

1 hour ago, Alpvax said:

You need to use the player who "owns" the book instead. So store the "owner's" id in the book somehow (NBT/capablility), then when the book is opened, get the player from the id (they may not exist/be offline, in which case you can't reasonably update), then update the data.

i actually do have a bit that adds a “owner” nbt data in the book! it stores the players uuid if that would work? i just didn’t know how i would check if it’s connected to the players capability.

in response to the level/world capability, how would i actually do that? im not sure if it’s useful, also eventually wanted to be able to use a command to get a players book even if they’re offline.

Link to comment
Share on other sites

18 minutes ago, jayxo said:

it stores the players uuid if that would work?

Yes, I think that is linked to the player's GameProfile, so should never change.

13 minutes ago, jayxo said:

in response to the level/world capability, how would i actually do that? im not sure if it’s useful, also eventually wanted to be able to use a command to get a players book even if they’re offline.

The same way you attach the capability to the player, but just attach a capability with a Map<player id, your current player capability data> to the overworld Level instead of attaching the data to the player directly. Then when you want to modify the data, get the capability from the overworld (which is always loaded) and get the data for the player with the given id.

Alternatively, you could use Saved Data (which used to be WorldSavedData), again using the overworld to access the player data.

That way it doesn't matter if the player is offline, because the data is saved to the overworld, so you just need to look up the data for the player by player id.

  • Thanks 1
Link to comment
Share on other sites

this has actually helped out a lot! I definitely think the best option is using WorldSavedData.

On 10/13/2021 at 8:45 AM, Alpvax said:

Map<player id, your current player capability data>

I've now gotten Map<UUID, *>, but for the players capability data, what kind of information would I put there?

Link to comment
Share on other sites

Ohh alright! I've gotten a .dat file to load into a world, but I'm not sure where to go from here.

public class StatsManager extends WorldSavedData implements Supplier {
    public Map<UUID, DefaultStatsCapability> players = new HashMap<>();
    public PlayerEntity player = Minecraft.getInstance().player;

    public StatsManager() {
        super(XLife.MOD_ID);
    }

    public void load(CompoundNBT nbt) {
        players.put(player.getUUID(), StatsCapabilityProvider.stats);
    }

    public CompoundNBT save(CompoundNBT nbt) {
        ListNBT listNBT = new ListNBT();

        for (DefaultStatsCapability stats : players.values()) {
            stats.save(nbt);
            listNBT.add(nbt);
        }

        nbt.put("Players", listNBT);
        return nbt;
    }

    public static StatsManager onWorld(ServerWorld world) {
        DimensionSavedDataManager storage = world.getDataStorage();
        StatsManager sup = new StatsManager();
        StatsManager saver = (StatsManager) storage.computeIfAbsent(sup, XLife.MOD_ID);

        storage.set(saver);

        return saver;
    }

    public static void onSaved(WorldEvent.Save event) {
        if (!event.getWorld().isClientSide() && event.getWorld() instanceof ServerWorld) {
            StatsManager saver = StatsManager.onWorld((ServerWorld) event.getWorld());

            saver.setDirty();
        }
    }

    @Override
    public Object get() {
        return this;
    }

}

I've used RaidManager as somewhat of a template for this, and the forge forums you linked.

Link to comment
Share on other sites

On 10/15/2021 at 3:55 PM, jayxo said:
public class StatsManager extends WorldSavedData implements Supplier

Why are you implementing Supplier? (Also, you should include the generic type of Supplier).

You probably want to add a getter for a specific player. something like the following:

public DefaultStatsCapability getStats(UUID playerID) {
    // Bear in mind this can return null if the player stats have not been added yet.
    // You might want to use computeIfAbsent instead.
    return players.get(playerID);
}

Then wherever you need the DefaultStatsCapability (for example in your book update function), get your instance of StatsManager, then get the DSC from it using the new getter.

On 10/15/2021 at 3:55 PM, jayxo said:
public PlayerEntity player = Minecraft.getInstance().player;

A) This will crash on servers (which is where loading and saving of data occurs)

B) What is this for? All the players should be saved in the map.

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.