devnatan / inventory-framework Goto Github PK
View Code? Open in Web Editor NEWMinecraft Inventory API framework
License: MIT License
Minecraft Inventory API framework
License: MIT License
How to reproduce:
// onPaginationItemRender
item.withItem(x).onClick(slot -> slot.updateSlot());
Expected behavior:
Slot updated
Stacktrace:
Caused by: java.lang.ClassCastException: me.saiintbrisson.minecraft.DelegatedViewContext cannot be cast to me.saiintbrisson.minecraft.PaginatedViewContext
at me.saiintbrisson.minecraft.PaginatedView.update(PaginatedView.java:354) ~[?:?]
at me.saiintbrisson.minecraft.ViewSlotContext.updateSlot(ViewSlotContext.java:79) ~[?:?]
at me.saiintbrisson.minecraft.ViewListener.onViewClick(ViewListener.java:184) ~[?:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_292]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_292]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_292]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_292]
at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:300) ~[PaperSpigot.jar:git-PaperSpigot-"4347b01"]
This will allow for a "return" mechanic with preserved data.
Useful for paged views that, if returned, your page is preserved.
Possible API design
Creating two forward and backward functions
context.back();
context.advance();
It will be necessary to keep a history of context but with a low level of amount of transitions, how deep the context will hold a previous context
// will save only one context per transition
useHistory(1);
A public API will be needed for the developer to handle the history freely implemented on VirtualView.
There is currently no documentation on how to use some functions with onItemHold
and onItemRelease
and there is not much documentation in the code itself because the code was ported from another repository.
Paginated & non-paginated onRender
being called after onUpdate
, cancelling update handler setItem
slot change.
Currently IF paging only supports one-time set data, ie you have a large amount of data taken in one go and stored entirely in a data list that will later be rendered in the inventory.
List<...> hugeAmountOfData;
setSource(hugeAmountOfData);
This becomes a problem when there is an indeterminate amount of data, a large amount of data, or you don't necessarily have access to all that data at once, which is the case with calls to a backend that are paginated and only get results of specific pages. IF does not support this.
List<...> getHugeAmountOfData(int page);
setSource(/* how ??? */)
There are workarounds currently to get around these problems like the page switching handler that you can use to get the current page that is in the inventory, and thus update the items accordingly but this doesn't work properly besides breaking all the flow of rendering and updating a paginated inventory.
The idea here is that the developer can determine the data that will be rendered according to the page, providing a data factory instead of the data itself. Something like this.
List<...> getData(int page);
setSource(ctx -> getData(ctx.getPage()));
That way:
onRender
even if it is not dynamic;There is currently an option that when the player clicks outside the inventory while it is open, the inventory is closed to the player, this is the closeOnClickOutside
option.
The idea is to create a custom handler so that the developer can decide what to do when this happens. This custom handler can be used for example as a return function, which when clicked on the outside returns to the previous inventory instead of closing it.
Currently the layout only works in paginated views whose item position is defined according to a layout if it is defined.
The idea is that the layout also works for non-paged views and that adding items through an item definition function in the View that does not specify a slot for it to go to a position according to the layout.
These two functions will either add items that will adapt to the layout if any or one will be added to the first available inventory slot.
slot(ItemStack);
slot().withItem(ItemStack);
When transitioning to another view using ViewContext's open
fn, user must can choose if it will transfer the data from the current view to the next view
Example:
final class A extends View {}
final class B extends View {}
Opens A
view with some data
open(player, A.class, ImmutableMap.of("donnut", "chocolate"));
Inside A
handler
B
view opens with no data
...onClick(click -> click.open(B.class));
B
view opens with no data but user can transfer data from A
to B
...onClick(click -> click.open(B.class, true /* inherit context data */));
...onClick(click -> click.open(B.class, click.getData()));
The current title of the inventory is not being exposed for the user to use it as he wants (ViewContext#getTitle
), currently a workaround for this is to get the current title of the player's inventory that is open.
This issue is related to handlers call order issue (#7).
When we call the update function (ViewContext#update()
or ViewSlotContext#updateSlot
)
in any handler of an item that is not a page item for example:
final class Example extends PaginatedView<...> {
public Example() {
firstSlot(item).onRender($ -> {
// when updated, this will be called a thousand times for some reason
}).onClick(ViewContext::update);
}
@Override
public void onPaginationItemRender(PaginatedViewContext<...> ctx, ViewItem item, ... value) {
item.onRender($ -> {
// if we click here or on the `firstSlot` item, it will be called once
}).onClick(iewContext::updateSlot);
}
}
The check is only being applied to View items, which have been statically defined so it'll not work with items set in context.
Reproducible code:
slot(1, new ItemStack(Material.REDSTONE));
context.slot(2, new ItemStack(Material.DIAMOND));
...
@Override
protected void onItemRelease(ViewSlotContext from, ViewSlotContext to) {
from.getPlayer().sendMessage("Item released");
}
Hold and release the REDSTONE
, will work fine, prints "Item released".
Hold and release the DIAMOND
, nothing happens.
Also, it won't work with PaginatedViewContext as these contexts don't store item information.
Introduce a "contextless"-like inlined View type to create views that'll be used only for simple interactions like a confirmation menu. The difference between a menu with context and one without context is that many things will no longer be handled, reducing the overhead of the View, making it much faster and simpler.
private void confirm(Player player);
private void cancel(Player player);
// ...
View confirmationView = View.create("Confirmation", 3, view -> {
view.slot(1, item).onClick(ctx -> confirm(ctx.getPlayer()));
view.slot(2, item).onClick(ctx -> cancel(ctx.getPlayer()));
});
confirmationView.open(player);
Or
private void confirm(Player player);
private void cancel(Player player);
// ...
ViewItem confirmItem = item(...).onClick(ctx -> confirm(ctx.getPlayer());
ViewItem cancelItem = item(...).onClick(ctx -> cancel(ctx.getPlayer());
createView("Confirmation", 3)
.with(slot(1, confirmItem))
.with(slot(2, cancelItem))
.build()
.open(player);
This View must use a definitely smaller amount of memory, it must probably be limited in terms of functionality and must be discarded if the player closes it.
See #21 (comment)
Provide an easy way to use IF in Kotlin code by creating a DSL.
https://pastebin.com/NZvtcrqy error no console
For now it is possible to make animations in the inventories but not in a simple way, it is necessary to change a lot to make a minimally simple animation.
The implementation of a facility for the creation of animations in inventories as well as own and free implementations (from the developer and not from the IF developers) is in the plans.
We have support for onMoveOut
but we don't yet have support for onMoveIn
(inverse of move out) which is to detect when an item is moved from the player's inventory to the View's inventory.
Most of projects that are built in Gradle > 7.0 need to change their JDK version to Java 11
due to compatibility with inventory-framework.
I mean, all code from inventory-framework doesn't use anything from Java 11
, so why is this being built into Java 11
?
I think this is happening from that workflow.
Allow multiple players to share the same inventory and context.
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These problems occurred while renovating this repository.
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.
.github/workflows/build.yml
actions/checkout v3
actions/setup-java v3
gradle/gradle-build-action cd3cedc781988c804f626f4cd2dc51d0bdf02a12
actions/checkout v3
actions/setup-java v3
gradle/gradle-build-action 64a1064eca4dce12f511de38c4afb06707e4e7fc
.github/workflows/codeql-analysis.yml
actions/checkout v3
github/codeql-action v2
github/codeql-action v2
github/codeql-action v2
.github/workflows/generate-artifacts.yml
actions/checkout v2
gradle/wrapper-validation-action v1
actions/setup-java v2
ASzc/change-string-case-action v2
burrunan/gradle-cache-action v1
actions/upload-artifact v3
.github/workflows/publish.yml
actions/checkout v3
actions/setup-java v3
gradle/gradle-build-action cd3cedc781988c804f626f4cd2dc51d0bdf02a12
gradle/gradle-build-action cd3cedc781988c804f626f4cd2dc51d0bdf02a12
publish.gradle
settings.gradle
build.gradle
com.diffplug.spotless 6.9.1
bom/build.gradle
bukkit-api/build.gradle
bukkit-plugin/build.gradle
feature-move-io/build.gradle
gradle/libs.versions.toml
org.spigotmc:spigot-api 1.16.5-R0.1-SNAPSHOT
org.jetbrains:annotations 23.0.0
org.junit.jupiter:junit-jupiter-api 5.9.0
org.junit.jupiter:junit-jupiter-engine 5.9.0
org.projectlombok:lombok 1.18.24
org.jetbrains.kotlin:kotlin-stdlib-jdk8 1.7.10
org.mockito:mockito-core 4.7.0
org.mockito:mockito-junit-jupiter 4.7.0
com.github.johnrengelman.shadow 7.1.2
org.jetbrains.kotlin.jvm 1.7.10
org.jmailen.kotlinter 3.11.1
kotlin-dsl/build.gradle.kts
shared/build.gradle
gradle/wrapper/gradle-wrapper.properties
gradle 7.5.1
In the docs on the readme it says to use
render.withItem()
however that item doesn't exist. What am I supposed to use?
No response
No response
2.5
No response
Will fail silently if layout size is larger than view size.
public final class A extends PaginatedView<?> {
public A() {
super(4);
setLayout(
"XXXXXXXXX",
"XXOOOOOXX",
"XOOOOOOOX",
"XXXXXXXXX",
"XXXXXXXXX"
);
}
}
PaginatedViewContext#getSource
Os itens da próxima página e página anterior não aparece.
layout:
https://prnt.sc/gdIqA3KD8fEF
código:
https://prnt.sc/LvrnuW2538O6
in-game:
https://prnt.sc/ShGLyjKMIi2z
Estou usando a versão do último commit.
The inventory update happens without any conditions. This causes inventories that update constantly to have a "poor performance" (not noticeable for anyone who uses it, but notable for me who develops the library).
My goal is for there to be a way of detecting update and for it to happen intelligently, which, for example, ignores updating of static items – without a explicit rendering function, like constructor defined items via slot(n, ItemStack)
.
Interacting with PaginatedContext on PaginatedViews, onItemRender
, getPreviousPageItem
, getNextPageItem
, layout resolution, dynamic layout update and such other things related to PaginatedView is not being handled.
It is currently not possible to get the limit amount of items for a page without first solving the layout. The problem is that the rendering function is called before the layout is resolved, so it is not possible to get the limit amount of items inside it.
This should be possible:
public void onRender(final ViewContext context) {
final int maxItems = context.paginated().getPageSize();
}
The error that gets thrown when trying to do this:
Caused by: java.lang.IllegalArgumentException: No pagination source was provided.
at me.saiintbrisson.minecraft.PaginatedViewContext.getPaginator(PaginatedViewContext.java:132) ~[?:?]
at me.saiintbrisson.minecraft.PaginatedViewContext.getPageSize(PaginatedViewContext.java:62) ~[?:?]
at co.outplay.palaze.arcade.bedwars.map.island.store.inventory.IslandStoreInventory.updateCategory(IslandStoreInventory.java:168) ~[?:?]
at co.outplay.palaze.arcade.bedwars.map.island.store.inventory.IslandStoreInventory.onRender(IslandStoreInventory.java:226) ~[?:?]
at me.saiintbrisson.minecraft.View.open(View.java:106) ~[?:?]
at me.saiintbrisson.minecraft.ViewFrame.open(ViewFrame.java:103) ~[?:?]
at me.saiintbrisson.minecraft.ViewFrame.open(ViewFrame.java:95) ~[?:?]
at co.outplay.palaze.arcade.bedwars.state.play.listener.IslandStoreVillagerInteractListener.onVillagerInteract(IslandStoreVillagerInteractListener.java:38) ~[?:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_302]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_302]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_302]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_302]
at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:300) ~[PaperSpigot.jar:]
... 16 more
This is because the layout is only resolved after the page source is resolved, due to optimizations, this can be resolved by solving the layout before the rendering function using as a content basis the layout characters and not the pagination source themself.
Temporary workaround:
Force inventory resolution even if content is empty
public void onRender(final ViewContext context) {
// force layout resolve
context.paginated().setSource(Collections.emptyList());
final int maxItems = context.paginated().getPageSize();
}
Allow players to define items that will place as placeholders in the position of paginated items when the amount of paginated values does not match the total pagination display size.
All X
s in the layout will be replaced by a stained glass pane.
setLayout(
"XXXXXXXXX",
"XOOOOOOOX
"XXXXXXXXX
)
setPlaceholder("X", ctx -> ctx.withItem(item(Material.STAINED_GLASS_PANE)))
All X
s in the layout will be replaced by a stained glass pane.
setLayout(
"XXXXXXXXX",
"XOOOOOOOX
"XXXXXXXXX
)
@Override
public void onItemRender(
PaginatedViewContext<?> ctx,
ViewItem item,
? value
) {
item.withItem(ctx.isFilled() ? <item with value> : <placeholder>)
}
A nova versão (2.3.2) pelo jitpack não está baixando.
Allow user to render an item only for a duration.
Currently it is possible to use a workaround with context data to do this but it is very complex, it must be implemented in the IF itself.
setItem
combined with onUpdate
By default the rendered item will be the fallback item PAPER
,
when updated it will set to the item DIAMOND
for 3 seconds and return to PAPER
.
slot(10, new ItemStack(Material.PAPER))
.onUpdate(update -> update.setItem(new ItemStack(Material.DIAMOND, Duration.ofSeconds(3)))
.onClick(ViewSlotContext::updateSlot);
It will also be possible to do conditional rendering together with onRender
slot(10)
.onRender(render -> render.setItem(new ItemStack(Material.PAPER)))
.onUpdate(update -> update.setItem(new ItemStack(Material.DIAMOND, 10L /* ticks */))
.onClick(ViewSlotContext::updateSlot);
The item rendering chain will continue to work.
As soon as the render duration of the timeout item update expires,
the render function will be called and if null returns to fallback. As it is now.
slot(10, /* fallback */)
.onRender(render -> render.setItem(true ? null : new ItemStack(Material.PAPER)))
.onUpdate(update -> update.setItem(new ItemStack(Material.DIAMOND, 10L /* ticks */))
.onClick(ViewSlotContext::updateSlot);
Lately some IF users have been trying to do things that are impossible without using indeterministic magic codes when it comes to slot position, that is, the user tries to find an item in the inventory that he expects to be in a specific slot by looking in that slot, however, the IF has several features that allow a player to move the item within the inventory and the reference to that item remains intact, thus causing the user code to fail.
The idea here is to make an item reference system, this idea was taken from Vue Template Refs that ran into the same problem we have here.
As I said before, the user may want to make the player be able to move items within the inventory but keep track of these items regardless of where they are, this is already possible using handlers, however, this is internal to the item itself and only in its scope, so, for example, it's not possible to make an item that updates another specific item, like this:
boolean goldRush = true;
firstSlot().onRender(render -> new ItemStack(goldRush ? Material.GOLD_INGOT : Material.IRON_INGOT));
// we we want this item to upgrade gold bar to iron bar and vice versa
lastSlot(new ItemStack(Material.ARROW)).onClick(click -> { /* how??? */ });
A possible workaround for this is to update the entire inventory.
The problem is that we don't want to update the entire inventory, because we don't need to.
lastSlot(new ItemStack(Material.ARROW)).onClick(ViewContext::update);
Maybe we can take the item slot and update ourselves
But that doesn't work either, as we allow the player to move the item in the inventory, once they move, this code will no longer work.
lastSlot(new ItemStack(Material.ARROW)).onClick(click -> click.update(getFirstSlot()));
As inspired by Vue's template references, it will be possible to reference an item and take that item later and use it however we want.
We will add a reference to an item using a referencedBy
or ref
.
private static final String GOLD_REF_KEY = "gold";
firstSlot(new ItemStack(Material.GOLD_INGOT))
.referencedBy(GOLD_REF_KEY);
And take the reference and use it however you want later.
The method for getting the reference will return a ViewSlotContext
that can be manipulated freely.
private static final String GOLD_REF_KEY = "gold";
private boolean goldRush = true;
firstSlot()
.referencedBy(GOLD_REF_KEY);
.onUpdate($ -> goldRush = !goldRush)
.onRender(render ->
render.setItem(new ItemStack(goldRush ? Material.GOLD_INGOT : Material.IRON_INGOT))
);
// ... and then ...
lastSlot(new ItemStack(Material.ARROW)).onClick(click -> {
ViewSlotContext gold = click.ref(GOLD_REF_KEY);
// update the gold item
gold.updateSlot();
});
You will even be able to know where the item is positioned through ViewSlotContext#getSlot
.
Paginated contexts will also work, so you will be able to get the current paging index and value of that item even if it is in another slot.
Currently if there are 100 sub data units split over two pages having 50 for each, in IF page switching will render those two pages at once.
Smooth scrolling will make the next batch of items to be rendered not the current amount of items in the inventory for the next page, i.e. if there are 100 data units sub split over two pages having 50 for each, on the next attempt to switch to the next page, only X items from the next page, determined by the developer, will be rendered, not all.
Vertical scrolling causes items from the next inventory update for pagination to be redirected to the end of the inventory, the last slot, going left to right, bottom to top (LRBT), currently in horizontal scrolling, items go from the right to the left, top to bottom (RLTB).
Olá, estou com uma dúvida em relação ao setar o item de ir para a próxima página e voltar usando o inventário paginado, como faço para definir eles?
There is no error handling for the initial opening handler, it must be implemented.
How to reproduce:
public final class Test extends PaginatedView<T> {
public Test() {
super(6, ...);
setCancelOnClick(true);
setLayout(
"XOXXXXXOX",
"OXOXXXOXO",
"XOXXXXXOX",
"OXOXXXOXO",
"XOXXXXXOX",
"OXOXXXOXO"
);
}
Expected:
Ok
Current behavior:
Previous page item not yet resolved.
It is possible to change the size of the pre-render initial opening handler inventory, if the size is changed in this handler the View#getRows()
method returns the rows value defined in the constructor and not the actual inventory value.
How to reproduce:
public final class Ìnventory extends View {
public Inventory() {
super(0);
}
@Override
protected void onOpen(final OpenViewContext open) {
open.setInventorySize(36);
}
@Override
protected void onRender(final ViewContext render) {
render.getPlayer().sendMessage(render.getView().getRows() + " rows");
}
}
Expected output:
4 rows
Actual output:
0 rows
How to fix:
Modify this to adapt to menus with dynamic inventory sizes
There is no error handling for the initial global render handler, it must be implemented.
There are features in the inventory-framework that are very rare to use, for example: the detection of movement of items from the player's inventory to the View, paging, among others.
It is ideal that the default functionality of the project, the core, is a dependency required for use but that these features are moved to specific modules that will be published and that whoever wants to use them can add to the project whenever they want, this will make:
The render priority of a paginated and a non-paged item is not being applied correctly.
When a paginated item is not available and a non-paged item is in the position that a paginated item can be rendered, the non-paged item is being cleaned up by the IF.
It is expected that if there is a manually defined item in the layout at the position of a non-paged item, and if this paginated item is not present, the non-paged item should be rendered.
Reproducible code
When the inventory refreshes, the non-paged item (IRON_INGOT) should render as there is nothing to page, but in game, the non-paged item (IRON_INGOT) simply does not appear.
public final class A extends PaginatedView<Integer> {
public A() {
super(1, "Golden Shower");
setLayout("OOXXXXXXX");
slot(0, new ItemStack(Material.IRON_INGOT));
setSource(Collections.emptyList());
}
@Override
protected void onItemRender(PaginatedViewSlotContext<Integer> render, ViewItem item, Integer value) {
item.withItem(new ItemStack(Material.GOLD_INGOT));
}
}
Paged View with Layout is rendering the layout with one item less than the full layout capacity.
This code
It should render five gold bars.
// in constructor
setLayout("OOOOOXXXX");
setSource(IntStream.rangeClosed(1, 5).boxed().collect(Collectors.toList()));
@Override
protected void onItemRender(PaginatedViewSlotContext<Integer> render, ViewItem item, Integer value) {
item.withItem(new ItemStack(Material.GOLD_INGOT));
}
The central point of opening the View's inventory is from the onOpen
opening handler, there, the conditions that will determine whether the inventory will be opened or not must be handled.
However, it is a synchronous handler, in cases where asynchronous calls are necessary, which, from their result, the opening condition will be defined and the inventory will finally be opened to the player, it is not functional and the developer is obliged to wrap the function of opening the inventory to the completion function of this asynchronous call like this:
CompletableFuture<...> fetch();
// somewhere there is an attempt to open the inventory for the player
fetch().whenComplete((result, $) -> viewFrame.open(A.class, player));
And there's also a problem with that, if an error occurs while opening this inventory, the View's error will be propagated to the completion function of this asynchronous method in case this function propagates or does anything with errors inside it, which is bad because the Error handling is done from the View's own error handler and the developer himself determines if it will be propagated or not when it happens.
CompletableFuture<...> fetch();
final class A extends View {
@Override
public void onOpen(final OpenViewContext context) {
throw new RuntimeException("bad"):
}
}
// somewhere there is an attempt to open the inventory for the player
fetch().whenComplete(($, $$) -> viewFrame.open(A.class, player))
.exceptionally($ -> { /* bad */ });
The idea of this issue is to create a way to make opening the inventory blocked in case an asynchronous function needs to be terminated first for that.
CompletableFuture<...> fetch();
final class A extends View {
@Override
public void onOpen(final OpenViewContext context) {
CompletableFuture<...> call = fetch();
// the inventory will not open until `call` is complete somehow
}
}
// the developer can calmly open the inventory and expect correct encapsulation of errors and correct late opening
viewFrame.open(A.class, player);
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.