#help-development
1 messages ¡ Page 1754 of 1
creating a global manager is likely the better option, like suggested
like this?
public PlayerManager playerManager;
public PlayerManager getManager() {
return playerManager;
}
yes
yes
then just init it in onEnable
and since you already have playermanager with plugin arg, all old calls can be quickly fixed
init it?
oh
also when I do this
this.playerManager.loadHashMap();
it says Static member 'net.reikeb.maxicity.datas.PlayerManager.loadHashMap()' accessed via instance reference
I did it, thank you guys đ
and when it offers to replace what I placed, and I click on it, it replaces
this.playerManager.loadHashMap();
by
PlayerManager.loadHashMap();
did you make it static?
no
sounds like you did
are you sure
Hey umm... The plugin works just no folder is made
package me.Eman.Ecore;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
public class Main extends JavaPlugin{
public boolean onCommand(CommandSender commandSender, Command command, String label, String[] commandArgs) {
if (command.getName().equalsIgnoreCase("help")) {
try {
Object localVariableScope = new Object();
commandSender.sendMessage(Main.color("&eGo to &7&owwww.youtube.com/eman49&e,"));
commandSender.sendMessage(Main.color("&eor do &9&l/discord &efor help!"));
} catch (Exception e) {
e.printStackTrace();
}
}
return true;
}
public static String color(String string) {
return string != null ? ChatColor.translateAlternateColorCodes('&', string) : null;
}
}
uh
it doesnt create folder automatically
You already have it? effectId
yea
it was id 1013^^
forgot about that... new to plugin development sorry
np
There ya go
so like this?
public static PlayerManager playerManager;
public PlayerManager getPlayerManager() {
return playerManager;
}
@Override
public void onDisable() {
playerManager.saveHashMap();
}
@Override
public void onEnable() {
playerManager = new PlayerManager(instance);
playerManager.loadHashMap();
}
also, saveHashMap and loadHashMap aren't static methods
instance is this you can use this
ok
any error or fixed?
Hello to you !
I would like to discuss some pure Java with you if you don't mind.
I know this is not necessarily the place, but I would like to have your opinion on a subject please.
I often see MC plugins that use a class with a lot of static variables for config files. (Example: Screenshot below the message)
In my opinion, we are clearly in a case of abuse of the static keyword! (Besides the use of the name Main for the main class which is also an error but that is not the subject).
After that, it is true that it is very easy to use this kind of classes ... But I do not find this way of doing correct.
Do you have any thoughts on this subject?
Any suggestions to overcome this problem?
Thank you !
well for now no error is shown by my IDE so I'm gonna replace everytime I called a new instance of PlayerManager by plugin.getPlayerManager() and test in-game if it fixes my issue
I generally just read from the YamConfiguration each time
That's what i'm doing too
I keep in a file handler my FileConfiguration, and use it to get things
You could also set values to instance variables
No I can't !
I love having a reload command for my plugins, so I can't do that
You can still update those variables
Yeah but it's complicated for little I think ?
Currently I just have to change the instance of my FileConfiguration when reloading to get the new file and voila
Okay ty đ
I like the principle, indeed it's very clean!
well done
Hello, would you be how to recover the rgb from a block?
Rgb?
What block has an rgb color
All blocks
The color of the texture?
Yeah
The textures donât exist on the server, so youâll have to hardcode the colors
Or generate a yml file of them using python or something
I had however found something which allow to recover the rgb of a block thanks to nms
Thatâs... not possible
The textures donât exist on the server, the server has no idea what colour a block is
What?
Also this sounds like #help-server
Ok, thanks
do sockets come with set in listening properties?
it tells you
what do u mean
it tells you what to do
read the wiki
i did pretty much everything
The home of Spigot a high performance, no lag customized CraftBukkit Minecraft server API, and BungeeCord, the cloud server proxy.
Hmm
What is the event to detect when a player does a command?
Hey guys, so im trying to add soft dependencies, and I made a hook for luck perms, however I get a NoClassDefFoundError for LuckPerms ContextCalculator when the plugin isn't present on the server. Now obviously it wouldnt be found if the plugin isn't present, but before I load the hook I check if Bukkit.getPlugin("LuckPerms") != null
I'm not sure how to avoid this exception because the hook class shouldn't be instantiated if the plugin isn't present
to detect when a player simply chats it's AsyncPlayerChatEvent but what is it for a command?
I have a broadcast for when I add a hook, but none of the messages get printed before the error:
public void registerHooks() {
Chat.broadcast("&aAdding hook");
addHook(HookType.LUCKPERMS);
Chat.broadcast("&cHook added");
}
I am so lost...
PlayerCommandPreProcessEvent
Bruh java IO is a bit of a pain
Whatâs up?
hey
can anyone help? i made a tutorial with this:
https://www.youtube.com/watch?v=s1xg9eJeP3E&t=7s
but i do not know how to make build it, am i supposed to use the install thing on the maven tab or the package thing
https://pastebin.com/xQUESCRt
What I did is good right? It should work fine?
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
Whatâs the issue
How would i have an entity have health above its normal max health
i see setMaxHealth is deprecated so how would i do this?
Thanks it worked, I was wondering how i could have an hp bar for my mob that updates as it gets damaged
I can't figure out why I'm getting a mapping values are not allowed here error in my plugin for the config file.
The config file contains
mentionsmessage: '&c%player_name% has mentioned you in chat!'
would public void onCreatureSpawn(Event e, Creature c) { work as detecting spawns like armor stands from /summon and spawn eggs and all that?
What exactly is the error?
Yes
thatâs not an event handler callback right?
You would need to use the BossBar API and listen for damage events
no?
Alright
Uh.
No
Idk?
Comments in yml files should start with a # I think
#All placeholders activated by message sender!
mentionmessage: 'false'
quick question: how do I return a list of all the keys in a YAML file?
testVar:
value: HelloWorld!
block2Use:
value: minecraft:stone
selector2use:
value: @s
I want to store ["testVar","block2use","selector2use"] in a variable - what method do I use to do this?
Ty.
ConfigurationSection::getKeys
You can get the configuration section [file.getConfigrationSection("section")] and then get all the keys. You can do [file.getConfigrationSection("section").getKeys(false);
You can stream it to a list if you need the keys but try to handle it in case there is an exception.
An instance of ConfigurationSection
and hell, what is .getKeys(false)
And section is just the string content
getKeys is an instance method of ConfigurationSection
false means it wonât look for nested keys
so I literally say section?
No that was a dummy example
No, you say the name of the section
If itâs the root then no need to even get the section.
ah so "keys" are the nested stuff
the value in this case
Yuh
refering back to the YAML, I want to get the top levels
And the Boolean controls if you want to get keys within subsections
there is no root
There is always
just getKeys(false) would do it to get all the parent keys
file.getConfigrationSection()?
Though with the assumption you do have an instance of a subsection ConfigurationSection call getRoot() to get the root section instance (which seems not to be your case)
file.getKeys(false)
YamlConfiguration#getKeys
so String[] exampleVar = file.getKeys(false)?
that will work?
No
It returns a Set<String> instance
So itâd have to be
Set<String> exampleVar = ...;
Somewhat
you have to stream it to an array
Sets donât have a get method
Itâs a data structure which has a single type parameter that determines the type of elements the set can contain, a set also should ensure no duplicates are contained within the set as opposed to a list
public void onCreatureSpawn(Event e, Creature c) {
System.out.println(c.getLocation());
System.out.println(c.getType());
}``` why isnt this detecting any spawns? ive tried spawning using a spawn egg and /summon and nothing gets sent to the console, yes its registered
Not necessarily but if it is a HashSet ye
Not an event handler method
so how do I turn Set<String> into a String[]
onSpawn(CreatureSpawnEvent event)
ah thanks
iirc toArray(new String[])
new String[0]
Ah yeah
so String[] newExampleVar = exampleVar.toArray(new String[]);
With a 0 between the latter []
why
An arrayâs size must be known at creation
Working with a list would be simpler
If you pass an array thatâs too small I think it just makes a new one? Idk
The initial array will have the length of 0 however the toArray method does some magic and stores it contents into the array (sort of) thus returning an array with the contents of the set
ok but this will work???
.toArray(new String[0]);
With a list would be simpler.
List<String> keys = fileInstance.getKeys(false).stream().toList();```
why is a list simpler?
Yes my bad I;ve been using streams a lot for sorting maps today xd
It might be for some
As youâre probably already familiar with a list
Depends what you are doing I guess
ok just to confirm
List<String> keys = fileInstance.getKeys(false).stream().toList(); will give me this:
["testVar","block2Use","selector2use"]
Use the other method
You can avoid the stream method.
This one
Yeah probably is negligible in this case
ok so THIS:
ArrayList<>(fileInstance.getKeys(bool))
will return this:
["testVar","block2Use","selector2use"]
List<String> keys = new ArrayList<>(file.getKeys(false));
ok so THIS:
List<String> keys = new ArrayList<>(file.getKeys(false));
will return this:
["testVar","block2Use","selector2use"]
It will return a list containing those.
and file will be config
Works similar to an array but instead of doing keys[0] you will do keys.get(0);
Placeholder API stopped working with my plugin...
if (plugin.getConfig().getString("mentionsmessage") != null) {
person.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(ChatColor.translateAlternateColorCodes('&', PlaceholderAPI.setPlaceholders(player, plugin.getConfig().getString("mentionsmessage")))));
}```
ok, and keys.get(0) will return "testVar"
If it is in the index 0, then yes.
and this is correct?
The config msg is &c%player_name% has mentioned you in chat!.
correct. the file you're using as the configuration would be file.
đ
đ
oh dear
nice taco
List<String> keys = new ArrayList<>(config.getKeys(false));
yikes
Do you have a variable named config
could I use plugin.getConfig()
just hold on a second
Its being entirely weird.
public class ChatEvent implements Listener {
public DataManager data;
static FastGensChatMentions plugin = null;
public ChatEvent() {
}
public static void initialize(FastGensChatMentions instance) {
plugin = instance;
}
@EventHandler
public void onChat(AsyncPlayerChatEvent event) {
Player player = event.getPlayer();
for (Player person : Bukkit.getOnlinePlayers()) {
if (event.getMessage().toLowerCase().contains(person.getName().toLowerCase())) {
if (data.getMutedConfig().getString(person.getUniqueId() + "muted") == null || data.getMutedConfig().getString(person.getUniqueId() + "muted") != null && !Objects.equals(data.getMutedConfig().getString(person.getUniqueId() + "muted"), "true")) {
person.playSound(person.getLocation(), Sound.BLOCK_ANVIL_LAND, 3.0F, 1.25F);
if (plugin.getConfig().getString("mentionsmessage") == null) {
person.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(ChatColor.RED + player.getName() + ChatColor.RED + " has mentioned you in chat!"));
}
if (plugin.getConfig().getString("mentionsmessage") != null) {
person.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(ChatColor.translateAlternateColorCodes('&', PlaceholderAPI.setPlaceholders(player, plugin.getConfig().getString("mentionsmessage")))));
}
return;
}
}
}
}
}``` When the config line is deleted, it still does ``&c%player_name% mentioned you in chat!``
I have a custom mob what event would i use to listen for it being damaged??
EntityDamageEvent
how would i do the specific one tho
How do you identify your custom mob?
Just a mob with potions and custom name
wdym?
Add a pdc tag to the mob when you spawn it so you can identify it
Yes
did you install player expansion?
[23:04:37 ERROR]: Error occurred (in the plugin loader) while enabling LDDuty v1.0 (Is it up to date?)
java.lang.NullPointerException: null
at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:357) ~[patched_1.16.5.jar:git-Paper-774]
at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:500) ~[patched_1.16.5.jar:git-Paper-774]
at org.bukkit.craftbukkit.v1_16_R3.CraftServer.enablePlugin(CraftServer.java:518) ~[patched_1.16.5.jar:git-Paper-774]
at org.bukkit.craftbukkit.v1_16_R3.CraftServer.enablePlugins(CraftServer.java:432) ~[patched_1.16.5.jar:git-Paper-774]
at org.bukkit.craftbukkit.v1_16_R3.CraftServer.reload(CraftServer.java:965) ~[patched_1.16.5.jar:git-Paper-774]
at org.bukkit.Bukkit.reload(Bukkit.java:726) ~[patched_1.16.5.jar:git-Paper-774]
at org.bukkit.command.defaults.ReloadCommand.execute(ReloadCommand.java:54) ~[patched_1.16.5.jar:git-Paper-774]
at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:159) ~[patched_1.16.5.jar:git-Paper-774]
at org.bukkit.craftbukkit.v1_16_R3.CraftServer.dispatchCommand(CraftServer.java:826) ~[patched_1.16.5.jar:git-Paper-774]
at org.bukkit.craftbukkit.v1_16_R3.CraftServer.dispatchServerCommand(CraftServer.java:788) ~[patched_1.16.5.jar:git-Paper-774]
at net.minecraft.server.v1_16_R3.DedicatedServer.handleCommandQueue(DedicatedServer.java:470) ~[patched_1.16.5.jar:git-Paper-774]
at net.minecraft.server.v1_16_R3.DedicatedServer.b(DedicatedServer.java:437) ~[patched_1.16.5.jar:git-Paper-774]
at net.minecraft.server.v1_16_R3.MinecraftServer.a(MinecraftServer.java:1342) ~[patched_1.16.5.jar:git-Paper-774]
at net.minecraft.server.v1_16_R3.MinecraftServer.w(MinecraftServer.java:1130) ~[patched_1.16.5.jar:git-Paper-774]
at net.minecraft.server.v1_16_R3.MinecraftServer.lambda$a$0(MinecraftServer.java:291) ~[patched_1.16.5.jar:git-Paper-774]
at java.lang.Thread.run(Unknown Source) [?:1.8.0_301]
Anyone seen this error before
java.lang.NullPointerException: null
well yes, but what's null lol
Is that the entire error
yes
- its not the full error
[23:11:03 ERROR]: Error occurred (in the plugin loader) while enabling LDDuty v1.0 (Is it up to date?)
java.lang.NullPointerException: null
at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:357) ~[patched_1.16.5.jar:git-Paper-774]
at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:500) ~[patched_1.16.5.jar:git-Paper-774]
at org.bukkit.craftbukkit.v1_16_R3.CraftServer.enablePlugin(CraftServer.java:518) ~[patched_1.16.5.jar:git-Paper-774]
at org.bukkit.craftbukkit.v1_16_R3.CraftServer.enablePlugins(CraftServer.java:432) ~[patched_1.16.5.jar:git-Paper-774]
at net.minecraft.server.v1_16_R3.MinecraftServer.loadWorld(MinecraftServer.java:594) ~[patched_1.16.5.jar:git-Paper-774]
at net.minecraft.server.v1_16_R3.DedicatedServer.init(DedicatedServer.java:298) ~[patched_1.16.5.jar:git-Paper-774]
at net.minecraft.server.v1_16_R3.MinecraftServer.w(MinecraftServer.java:1069) ~[patched_1.16.5.jar:git-Paper-774]
at net.minecraft.server.v1_16_R3.MinecraftServer.lambda$a$0(MinecraftServer.java:291) ~[patched_1.16.5.jar:git-Paper-774]
at java.lang.Thread.run(Unknown Source) [?:1.8.0_301]
[23:11:03 INFO]: Running delayed init tasks
[23:11:03 INFO]: Done (10.893s)! For help, type "help"
[23:10:57 ERROR]: [org.bukkit.craftbukkit.v1_16_R3.CraftServer] null initializing LDDuty v1.0 (Is it up to date?)
java.lang.NullPointerException: null
at org.bukkit.craftbukkit.v1_16_R3.CraftServer.loadPlugins(CraftServer.java:398) ~[patched_1.16.5.jar:git-Paper-774]
at net.minecraft.server.v1_16_R3.DedicatedServer.init(DedicatedServer.java:269) ~[patched_1.16.5.jar:git-Paper-774]
at net.minecraft.server.v1_16_R3.MinecraftServer.w(MinecraftServer.java:1069) ~[patched_1.16.5.jar:git-Paper-774]
at net.minecraft.server.v1_16_R3.MinecraftServer.lambda$a$0(MinecraftServer.java:291) ~[patched_1.16.5.jar:git-Paper-774]
at java.lang.Thread.run(Unknown Source) [?:1.8.0_301]
?paste the full startup log
alright
odd. I'd guess LDDuty is corrupt
Wonder if modern java would give a better error
tbh I was using java 16 but I had to move down to 1.8 for a quick project
you're not running spigot
how i can make my plugin reload itself?
reload config?
no no, eg: my plugin download the dependencies, and for apply this i need restart the server or the plugin
and i want reload the plugin
oh ok
(this is for java 16)
try PlugMan .__.
no... I want to make my plugin reload itself
without needing external help
did you understand?
yes
There are definitely ways to download external dependencies without needing to reload the plugin
Something like slimjar
the only supported way to reload is to reload the whole server
Or the system built into spigot in 1.17
reloading just one plugin could be really bad, eg what happens if another plugin depends on yuour plugin
export -> /reload -> profit
got a question but don't want to override lol
This is why we have threads
yess
true
or just the ability to read multiple things at once
To be fair I already saw the code
well I just don't want to like, belittle someone else's issue
don't wanna walk on someone lol
You have the path needed, but you just have it sitting on a line doing nothing
public class onPlayerMove implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
Player player = (Player) sender;
return false;
}
@EventHandler
public void playerMove(PlayerMoveEvent e) {
Player player = e.getPlayer();
if (player.hasPermission("shark.move")) {
e.setCancelled(false);
} else {
e.setCancelled(true);
player.sendMessage(ChatColor.RED + "You cannot move in this lobby!");
}
}
}
Main class:
getCommand("hMove").setExecutor(new onPlayerMove());
Trying to have it so when the command is executed it'd check if the player has permission to move, and if not the PlayerMoveEvent will be disabled
Im quite new to spigot and would appreciate some help
Yeah thatâs not how you do that
you didnt register the event listener
alright, thanks you
you just registered the command
You have an event listener inside a command method
implements listener not there
implement Listener and call registerEvents
Ah wait no you donât, but the command just declares a player variable and then returns
Implemented listener but not quite sure how to call registerEvents?
Sorry for all the questions!
Bukkit.getPluginManager().registerEvents(Listener listener, Plugin plugin);
what would be the best way to make a thing. lemme show an example
https://www.youtube.com/watch?v=9btkUg1ea_U like this:
so yeah, what would be the best way to make this? ^
Would I do it in my main class or in the class with my event?
Class extends JavaPlugin
onEnable() method
Thanks!
no prob
TileTool plugin
hmm?
I'm using this when i'm on development, it reload plugins when it detect file changes
Did you register events in the main class? and You forgot add implements Listener
solved đź
Ok
.___.đ
someon please help me
Im trying to make a shop plugin
I made a class with the shop menu Inventory and sell inventory as its members
So far it is working pretty good, I onlly setup the selling thing
but
will the inventory change for everyplayer when one player changes it
no.
hey, quick question, what method to use to get item in player's hand if i want plugin to work 1.8-1.17.1?
are you using a listener/event handler?
public ItemStack getItemInHand(Player player) {
if(Bukkit.getVersion().contains("1.8")) {
return player.getItemInHand();
} else {
return player.getInventory().getItemInMainHand();
}
}
it work for me .___.
player.getItemInUse();
any easy way for adding multiversion to plugin?
I wanted to try https://github.com/WesJD/AnvilGUI
...
donno but i'm using this in my event ItemStack killerWeapon = e.getEntity().getKiller().getItemInUse();
My dothetext: (deathlogger.logDeaths)
public class logDeaths { //line7
public static void dotheText() throws IOException{ //Line 8
//1 Create a File
File file1 = new File(DeathLogger.getPlugin().getDataFolder() + "\\logs\\out1.txt");
file1.mkdir();
//2 Create a File Writer Class
FileWriter fw = new FileWriter(file1);
//3 Create a Print Writer Class
PrintWriter pw = new PrintWriter(fw);
}
}
Main Method: (deathlogger.DeathLogger)
try { //line 23
logDeaths.dotheText();
} catch (IOException e) {
e.printStackTrace();
}
How to I make the directory? A bit lost on this one :))
Know VERY little about this
and what about changing that item?
how can i create a cosmetic explosion?
wdym?
just create a file
change the item that is in player's main hand, 1.8-1.17.1
ok
new File(JavaPlugin#getDataFolder(), "yourtxtfile.txt");
wait a sec
make the checks for it so you can create it if its missing
public void setItemInHand(Player player, ItemStack item) {
if(Bukkit.getVersion().contains("1.8")) {
player.setItemInHand(item);
} else {
player.getInventory().setItemInMainHand(item);
}
}
i'd guess
thanks
no prob
should i use PlayerInteractEntity or PlayerInteractAtEntity?
for?
For right clicking on mobs
Ok
Do I need to make sure that e.getCurrentItem() is not null before this statement?
if(!(e.getCurrentItem().getItemMeta() instanceof Repairable repairableItem)) {
return;
}```
(I know `instanceof` doesn't throw an error when used on `null` but here I am using a method on something that may be `null` before checking if it's an instance of `Repairable`)
Is it marked nullable
Yes, getCurrentItem() is Nullable, it may be null
So then you need to check itâs not null
Okay, thank you. Was just wondering because usually IntelliJ complains if there is a null check missing, but here it doesn't
Maybe a bug, probably due to the new style instanceof youâre using
java.lang.NullPointerException: Cannot invoke "org.bukkit.configuration.ConfigurationSection.getValues(boolean)" because the return value of "org.bukkit.configuration.file.FileConfiguration.getConfigurationSection(String)" is null
at me.favn.PluginName.ItemCreator.<init>(ItemCreator.java:22) ~[PluginName-1.0-SNAPSHOT.jar:?]
at me.favn.PluginName.ItemGenerator.fetchItems(ItemGenerator.java:19) ~[PluginName-1.0-SNAPSHOT.jar:?]
at me.favn.PluginName.ItemGenerator.<init>(ItemGenerator.java:11) ~[PluginName-1.0-SNAPSHOT.jar:?]
at me.favn.PluginName.PluginName.onEnable(PluginName.java:18) ~[PluginName-1.0-SNAPSHOT.jar:?]
at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:264) ~[patched_1.17.1.jar:git-Paper-336]
at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:370) ~[patched_1.17.1.jar:git-Paper-336]
at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:500) ~[patched_1.17.1.jar:git-Paper-336]
at org.bukkit.craftbukkit.v1_17_R1.CraftServer.enablePlugin(CraftServer.java:561) ~[patched_1.17.1.jar:git-Paper-336]
at org.bukkit.craftbukkit.v1_17_R1.CraftServer.enablePlugins(CraftServer.java:475) ~[patched_1.17.1.jar:git-Paper-336]
at net.minecraft.server.MinecraftServer.loadWorld(MinecraftServer.java:730) ~[patched_1.17.1.jar:git-Paper-336]
at net.minecraft.server.dedicated.DedicatedServer.initServer(DedicatedServer.java:317) ~[patched_1.17.1.jar:git-Paper-336]
at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1217) ~[patched_1.17.1.jar:git-Paper-336] at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:319) ~[patched_1.17.1.jar:git-Paper-336]
at java.lang.Thread.run(Thread.java:831) ~[?:?]```
ItemCreator:22
```alltheshit = cconfig.getConfig().getConfigurationSection(checkthis).getValues(false);```
(cconfig is passed through from ItemGenerator calling a method on line 11, that code being at line 19...
Idk what I am trying to say is I cannot understand this, so can someone please help me understand it?
That means that config section ur trying to get don't exist
Thank you
Thanks, I was passing value instead of key, which is why the section didn't exist đ
what does the build error ```invalid target release: 1.8.0_312
Means uh its the first time im getting this error
you probably need to change your language level
will it affects on my project ?
shouldnt
will language level 9 would be enough or higher...?
i changed it to 9 from 8 but it didnt changed wt
it is not working
you specified an higher java version in your pom.xml than you have on your system
so going higher will not fix the issue
1.8 is java 8
im checking that in pom.xml but
<target>${java.version}</target>```
this is the java version in pom.xml
also
open cmd and type in java -version, whats the output?
its 16
btw i also have 8 installed
1.8*
it also used to work fine before changing my project version to 1.6-Beta but this probably does not affect on java version so...
even changing project java version to 16 didnt worked!
error: invalid target release: 16.0.2
target and source only want a basic level, like 1.8 or 16. It does not work using 16.0.2
Is HikariCP worth it ? I would like to add database (sqlite & mysql) for my plugin, should i use that instead of simply jdbc ? (I'm new at java development)
im gonna download another java 1.8 version which one should i choose then
just remove your $java.version and put in an actual number to see if it works
in target or source or both?
both
How can i get the tps of my server?
not really. read the thread, thats how spigot does it. otherwise you have to do something on your own
how can i update the GUI on InventoryGUI?
https://pastebin.com/MR1JLBPm
Hey I have a problem. So this corpse does not dissapear when the inventory is empty for some reason so I switched the code up A lot to try to make it work but no luck.
reopen
wouldnt that cause stuttering tho?
not if you dont close it
inv.setItem()?
and not doing it frequently
oh open it repeadetly?
doesnt that updates it automatically?
or call Player#updateInventory()
doesnt that just update the inventory of the player? or does the inventory count atm as a part of the inventory?
I thought it updated teh view
only the players inventory
ah
does anyone know an opensource discord bot that announces every time an author updates their plugin?
uhh watch console?
you are literally adding items to the inventory and checking directly after if the inventory is empty
⨠you could do your own one â¨
i tried to and gave up midway lol
Oh...
right
is there any method i can use to run a task for a specific amount of times with the tick delay also?
something like runTaskTimerAsynchrously but do that task 10 times and no more
repeating task has a param for delay doesntt it
no, delay is fine, but i want to do it for certain amount of times
you can always have a counter inside of it
i dont think theres any task with an inbuilt iteration limit though
i had an idea of doing a for loop
but i think the for loop will also repeat cause uh
every time the task repeats, the loop also repeats
just have an int starting at 0
iterate at the end of each iteration of the task then if i >= 10 finish the task
is it possible to make maven build plugin's jar into multiple directors?
Wait for a second I thought I knew the solution but now Im unsure
what are you trying to do, what did you thought of and what were you trying?
I think youre returning when the inventory is empty before you can remove it in line 49
the return in line 30 might be the problem
https://pastebin.com/8iiidgPQ So like this?
not sure if it works. you tell me đ
Got it
if i do like
new ClassThatExtendsRunnable().runTaskTimer(plugin, 1L, 6L);```
will that create a new object on every run?
every 6 ticks in my case
so its the same as
var obj = new ClassThatExtendsRunnable();
obj.runTaskTimer(pluhin, 1L, 6L);
```?
ok
yeah
oki thanks
i was scared
and uhh i guess these things are te same
ah wait
It will try to remove 'as much as possible' from the types and amounts you give as arguments
i was hoping there is something like inv.remove(ItemStack...) which returns a boolean
either you else it or it doesnt make sense
but yeah, seems like there isnt
sad sad
can someone please help sending actionbar packet via tinyprotocol?
why not just sending an actionbar?
cuz i want it 1.8-1.17.1
don't you mean maow?
I think ActionBarAPI is only like 1-2 classes and accomplishes that exact task
want me to link ya it?
yep
NO đ
:(
(:
at which version is ActionBarAPI useless?
test it for 1.17, it worked fine on 1.16
my framework is 1.14+, I might incorporate that API into it
yea, i would send ya my framework but its not done, Factions oriented, and based in 1.8.8
whats Adventure?
ahh
A component-based text lib for Minecraft platforms, has platform support for Spigot but is native for Paper.
ah uh looking for a more efficient way
Bungeecord's text API is close to it.
honestly, lately I have been doing a lot of code related to obfuscating and practicing a lot of reverse engineering
...separate it into a method?? lol
^
then just return that new File from the method and assign your fields to the returned File
e.g.
if it takes two parameters i cant access the field it only modifies the parameter
uhh
configFile = loadConfig("config.yml");
you might have to make a new class for that or smthn
one minute
Here's my framework btw: https://github.com/Spigot-MSPL
It is also not done
But it's primarily focused on medium-large sized plugins, and is for 1.14.4+ as I said before.
primary projects are iron and mspl-core
iron = Gradle plugin that helps with creating a development server.
mspl-core = Core library that contains common or necessary functionality for other parts of the library.
Just use adventure for action bars
I don't think it supports it tho :p
It does
goddamn their docs really are unfinished then
javadocs is a thing
?paste
oh
Like, sending an action bar is a single method nothing to explain in docs
but yeah mspl-core basically provides abstractions over stuff like Adventure and Commodore, as well as some utils.
well if the docs don't show it as existing, it's hard to motivate me to look at the javadocs to see if it actually does :p
what does this do?
fileConfiguration.setDefaults(defConfig);
basically if the config doesnt exist in the folder
it saves the config with the one in your plugin jar
isnt that just plugin.saveResource("config.yml", false)?
exactly
wew thanks
np lol
1.16
at least in my case, but i didn't updated it for a long time
Bungee Chat API OP
adventure better
Yes
heh
java.lang.IllegalArgumentException: Length of Base64 encoded input string is not a multiple of 4.
Base 64 strings must be a multiple of 4
the number of characters ^
from what mc version does spigot have built-in actionbar api?
smh java.lang.IllegalArgumentException: Illegal character in Base64 encoded data.
send the string
1.12 i think
how to know it 100%?
by testing it XD
search up the docs
grr i'm trying to decode something from yml file
send the string
like
safe-chests:
uuid1: base64string
send the actual base64 sting
i havent
and wait
it wont save
why do ya wanna use Base64 for it if i may ask
not going to save a whole itemstack array to a file
but anyways i was trying to get configSection.getKeys(false) but then i saw it was .values
but that returns an Object so grr
.toString may just return a debug msg
probably this now
i think itemstack has a real toString
but getValues(false).values looks cursed
this wont work as the key isnt an uuid
use "datafile.getString(key + ".uuid");
Darn it, It doesnt work
he does it already better
and yes the key isnt an UUID
his way there wouldnt work, he needs to actually grab the content of the key
maybe thats the error
not the key itself
he does?
#getValues
out for the configuration section
that returns a map with the values of the keys & keys under that CS
but are you sure that it returns the values of each subkey as well?
one second, ima just test this
i think the subkey is the value for the key if there is a subkey
i think i found it
dataFile.getConfigurationSection("safe-chests").getKeys(false).forEach(key -> {
ItemStack[] content = InventorySerialisation.itemStackArrayFromBase64(dataFile.getString("safe-chests." + key));
SafechestGui.getMenus().put(UUID.fromString(key), content);
});
but he would be trying to handle every subkey at once
there arent any subkeys so fuck it
where dataFile.getString("safe-chests." + key) grabs the content
wouldnt ya also need the subkey on the end if you are not getting deep?
for getKeys
there arent any subkeys
he now just gets uuid1, uuid2, uuid3 and fetchs the value for each
uhu
yea, in this one example there are not, but realistically it should be written to be adapted for anything not just a single situation
if there would be subkeys my brain would really explode
not sure how you would go for that. probably looping over the keys or getting the CS for each
private or public its important to get in the habit of always assuming your work will be seen and worked on by others
heh?
makes a plugin for my localhost "ready to let players on my server!"
grr java.io.StreamCorruptedException: invalid type code: 2D
for those who don't want to use DataWatchers for packet entities, here's a detail explanation how to send metadata packets, without having LivingEntity object or doing reflection inside packet object which costs performance. (1.17.1)
PacketDataSerializer metaData = new PacketDataSerializer(Unpooled.buffer()); // Unpooled.buffer is netty's implementation of ByteBuf interface. Its used to store packet data, before it gets sent through netty's connection pipeline.
metaData.d(987); // entity id. d method is for writing varInts, mojang has a special implementation of them.
// Entity Metadata info
metaData.writeByte(0); // byte index https://wiki.vg/Entity_metadata
metaData.d(0); // type registry id (varInt) https://wiki.vg/Entity_metadata
metaData.d(0x20); // byte bit mask (invisible) https://wiki.vg/Entity_metadata
metaData.writeByte(255); // mark as end of the packet buffer data. Its required.
connection.sendPacket(new PacketPlayOutEntityMetadata(metaData));
error on this line
ItemStack[] items = new ItemStack[dataInput.readInt()];
public static ItemStack[] itemStackArrayFromBase64(String data) {
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64Coder.decodeLines(data)); // this line
BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream)) {
ItemStack[] items = new ItemStack[dataInput.readInt()];
// Read the serialized inventory
for (int i = 0; i < items.length; i++) {
items[i] = (ItemStack) dataInput.readObject();
}
return items;
} catch (Exception e) {
e.printStackTrace();
}
return new ItemStack[0];
}
have to be an int
i've researched this for god long how, due to obfuscation of datawatcher classes. And google suggests using datawatchers or reflections, which are wrong if the entities are not in the server but are clientside
?paste
this creates the string
https://paste.md-5.net/edexeyisev.java
and it writes the length of the itemstack[] first
seems like it added a "D"
as seen here
uhh
when i try again its this
java.io.StreamCorruptedException: invalid type code: 00
every time 00
đ
WOW
bat's hitbox is really fucked up
pro tip: wanna kill a bat, swing at the air.
easier to hit xd
that would explain it if the hitbox was around its body
its only the half
sitting yeah, and in air?
In the air it's 1 pixel
Why is that bat's hitbox so tall
i have no idea
Yeah
that's vanilla
hmm
output.write(items.length) vs dataoutput.writeInt(items.length) was probably my mistake
hanging bats have enormous hitboxes
[Thats how I got people to say im the best archer in minecraft, I just show hitboxes and since its so tall you dont have to hit the bat itself]
Okay so I've been working on a plugin that adds some custom items to the game... these items are automatically generated by the plugin by drawing parameters from a config... What I don't know is how do I then obtain those items in-game? đ
I made the plugin print the final ItemStack to console: The itemstack is: ItemStack{DIAMOND x 1, UNSPECIFIC_META:{meta-type=UNSPECIFIC, display-name={"extra":[{"text":"Pure Diamond"}], "text":""}, lore=[{"extra":[{"text":"A rare form of Diamond!"}], "text":""}], enchants={LUCK=1}, ItemFlags=[HIDE_ENCHANTS]}}
Write a command that looks something like this:
/customitem get <name>
If you have mapped those items to names that is.
You see that I am not completely certain of lol
I was hoping something in there would help me figure that out đ
Well it looks like you've already built the ItemStack, all you have to do is add it to the player's inventory.
When you want to add it depends on your plugin
Of course, of course. But that is the question: How
player.getInventory().addItem()
The ItemStack
declaration: package: org.bukkit.inventory, interface: Inventory
So I gotta add these itemstacks I'm creating to a map is what you're saying, then?
Depends on your plugin. You could just use a
Map<String, ItemStack>
and get loaded items by their mapped String
Hmm yeah that seems pretty nice
I was gonna post the code I used but I think I'm just gonna try this first then see if it works đ
I feel good about this
Hmm
So I tried this:
The "name = item" is at the end of the method that makes my itemstack, setting that itemstack to be equal to "item". I then attempted to just put that into the hashmap I created at the top of my class, named "items"
name = item;
items.put(itemname, name);
That gave me an error saying "this.items" is null
More code pls
One sec
https://pastebin.com/ABwEdXgY
Hey I have a problem. So this corpse does not dissapear when the inventory is empty for some reason so I switched the code up A lot to try to make it work but no luck.
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
Original:https://pastebin.com/UnQdv3Uq
for some reason nothing gets written to the file while the map isn't empty
SafechestGui.getMenus().forEach((key, value) -> dataFile.set("safe-chests." + key, InventorySerialisation.itemStackArrayToBase64(value)));
saved it
it's a Map<UUID, ItemStack[]> which gets transformed to a Map<UUID, String>
to players?
Im canceling a sound Id with the ProtocolLib API. Does any1 know if this plugin works for any version with viaversion? Because every version has like a other sound Id
Hey, if I create multiple Connections asynchronously via the scheduler, are they all going to be on different threads?
yep
Good.
True.
The Bukkit scheduler? Not necessarily
iirc it uses a cached thread pool for its asynchronous tasks
Eh that's fine anyways.
I just needed to know so I could keep track of multiple connections at once.
Yeah but it may reuse the threads, yeah what you doing anyways?
SQL module for my framework.
do i need to save my yml directly after setting one thing maybe?
Uh well
Currently just trying to figure out how to abstract its data classes though.
Ideally youâd cache it FourteenBrush
I want to be able to provide an interface so that I can have 2 ways of storing/retrieving info, one with and one without SQL.
well i dont understand why my message gets logged and nothing has been saved
And then save with a sync buffer every x duration and save at certain justified events like join and leave
Oo, lmk how it all comes along
it's a Map<UUID, ItemStack[]> which i'm trying to save this way
SafechestGui.getMenus().forEach((key, value) -> {
dataFile.set("safe-chests." + key, InventorySerialisation.itemStackArrayToBase64(value));
Utils.logDebug("saved safechest " + key + ":" + Arrays.toString(value));
});
Can someone help me. Im making a plugin has a command. Im trying to turn an arg(the arg is the player's ign) to a player so i can give that player stuff but i cant figure it out.
after that the config.save bla bla bla but the message gets logged and it isnt saved
?paste the code
i do
I canât spot it in thecode you sent
pasted
its saved because the code below it gets saved
you have to give the link :kekw:
you want an else
or an early return
and store the player somewhere
Player hunter = Bukkit.getPlayerExact(args[idk]);
if (hunter == null) // the message stuff
else // do something with the player
casting won't work
Thank you!
just a general java question: how do I get every element in a list after a certain index
example:
["thingZero","thingOne","thingTwo","thingThree","thingFour","thingFive"]
I want to store ["thingTwo","thingThree","thingFour","thingFive"]
how would I do this? Thanks!
lookup #subList
and if I don't provide a second argument, it will default to the last?
you need a second argument.
subList(fromIndex, toIndex). if you want it to go to the last element, use #size() as toIndex
ok thank you!
i don't get it
nothing is set to the file and its saved
also hmmm
RFC 2045, which defined Base64, REQUIRES a newline after 76 characters (max).
EntityDamageByEntityEvent
cant a string with \n be saved into config or something?
you need to make a List<String>
Can you disable TabComplete in a PlayerCommandPreprocessEvent?
because Java doesn't understand it as a line break i guess, is it just getting "deleted" and just the n is in the config?
because \anything just means "deal with it as a normal character"
pretty sure you can escape the \ with another \ -> \\n. but that would mean "hey \n wow, linebreak" would be in the config
i'm now trying it with the java.util.Base64 class
Hi it is possible to set HEX or RGB color to sheep?
No
đŽ
that looks like vsc
so "Jeb" name tag works only on the Client side?
i guess
Yeah
Yes
Technically you could have a timer switching the color every so often though it wonât be smooth transitions
whats that background image
some random galactic
can you send it in here? đĽş
@GodCipher it would't be cheap transaction đ
now the string is without \n and stuff but for some reason it wont get saved
god
js user
terrible thing
var is super useful huh ?
My employer force me to use var in C#. So i'm used to it ÂŻ_(ă)_/ÂŻ
anyway var makes programming faster a bit
Anyway, afaik sheep in java don't use hex under the hood
hmm yes intellij has some genius ideas
Pretty sure you can disable the super call when gening
anyways to prevent me from using JavaPlugin.getPlugin(MyPlugin.class) cant i just do this in my mainclass so i can use MyPlugin.getInstance() afterwards?
private MyPlugin instance = JavaPlugin.getPlugin(this)?
and a getter
sounds stupid
Well
You could in every other class use something like:
private final MyPlugin plugin = JavaPlugin.getPlugin(MyPlugin.class);
DI is sobbing
Though Idk why youâd have to depend on MyPlugin with every other class
Wonder if that would be marked as a bad code practice
Thatâs some sort of abstraction breach
Probably lol
The question always comes down to âWould it make it past premium inspectionâ
đĽ˛
i do đŚ
May I ask how come most of your classes depend on MyPlugin, the main plugin class instance?
All the runnables
Ah
i need the plugin
for uhh
configs, namespacedkeys etc
for some reason i lost the jetbrains annotation package :/
Ah, sometimes you can delegate a certain functionality to another class then go on and pass that other class instance instead of your main class instance, for instance this would be a middle ordered class https://github.com/Conclure/cityrp-core/blob/master/paper/src/main/java/me/conclure/cityrp/paper/utility/concurrent/BukkitTaskCoordinator.java I guess, though the code isnât great
i like the doggo đ
i heard my name?
meow
private static final DiscordBridgePlugin PLUGIN = DiscordBridgePlugin.getPlugin(DiscordBridgePlugin.class);
Yeah di would make it a bit more loosely coupled
is this the same as instance = this in main class?
instance = getPlugin(getClass());
The only problem is that they need a plugin instance for construction.
Well... not anymore. But when they did it was a pain.
not anymore?
There is a static parse method
I currently default on something like this:
public class NamespaceProvider {
private static final String NAMESPACE = "MyPlugin".toLowerCase(Locale.ROOT);
public static NamespacedKey create(final String key) {
return NamespacedKey.fromString(NAMESPACE + ":" + key);
}
}
oh
I use the static getplugin method
This looks viable:
public class Namespaces {
public static final NamespacedKey DAMAGE = NamespaceProvider.create("damage");
}
?paste
if you convert that to an interface, it removes the need for the public static final part
I dont see it... example pls
Ah i see
public interface Namespaces {
NamespacedKey DAMAGE = NamespaceProvider.create("damage");
}
What you mean
No. I want verbosity. Implicit scopes and access modifiers are doodoo đŠ
is there a way to replace something in getStringList like getString?
Do you want to replace an element from a List of Strings?
exactly
replaceall wasnt working or i was using it wrong
- Get the index of an element
- Write a new Object to that index
replaceall is a bulk operation and should also work
wasnt working i think
Something like this:
final String oldElement = "foo";
final String newElement = "baz";
list.replaceAll((element) -> element.equals(oldElement) ? newElement : oldElement);
But thats a bit of overhead
i think that was the output of replaceall
k i'll try it thanks
uh guess i found an easier way
*not working
Another way would be this:
public <T> void replaceFirst(final T oldElement, final T newElement, final List<T> list) {
int replaceIndex = -1;
for (int index = 0; index < list.size(); index++) {
if (list.get(index).equals(oldElement)) {
replaceIndex = index;
break;
}
}
if (replaceIndex > -1) {
list.set(replaceIndex, newElement);
}
}
Hm this looks ugly
Kind of useless to store the index there
Just set when found, won't run into a CME as you are accessing by index
cant create a void for this as i have to use replaceall in only one line code
because the code only accepts that way... :
KnockbackFFA.getInstance().getConfig().getStringList("scoreboard.lines")//replaceneeded
Ah you are right. First thing i thought was concurrent modification XD
public <T> void replaceFirst(final T oldElement, final T newElement, final List<T> list) {
final int index = list.indexOf(oldElement);
if (index > 0) {
list.set(index, newElement);
}
}
...
Anyone know how I would be able to use custom textures with spigot?
Like custom model data ?
You need a resource pack
^^ on the plugin side of things you can use https://hub.spigotmc.org/javadocs/spigot/org/bukkit/inventory/meta/ItemMeta.html#setCustomModelData(java.lang.Integer)
declaration: package: org.bukkit.inventory.meta, interface: ItemMeta
Which your resources pack then can map to a custom texture
hello, i would like to create multiple structures and they would work like a beacon. how could i do that
Very carefully
Work like a beacon in terms of giving potion effects to players ?
it is a cell tower but would be something like that yes
yes, i need specifically that
not working like what i expected
i will use like an activator so the player just right click and it detects the structure
but i dont know how to do it
Bounding box around the structure, check if block inside the box is clicked. Etc...
create a cuboid when the structure is spawned
it is like a beacon so the player need to build them
like store x1, y1, y1, x2, y2, z2
based on radius
and center of structure
and then if player walks in
You can add structures. Like portals or the wither boss etc...
when it is finished then do the structure
was not aware of this maybe look into it
how
I have to relook for the methods. One sec
also, these structures are got from a schematic
but there is no problem, i can load them first
Well you said the player has to make them... so either check if all blocks match the schematic or create a shape based on the schematic and check the shape when the player places a block.
I'm still looking for the shape code
PlayerConnection connection = ((CraftPlayer)holder).getHandle().b;
Location loc = player.getLocation();
PacketPlayInFlying.PacketPlayInPositionLook positionPacket = new PacketPlayInFlying.PacketPlayInPositionLook(
loc.getX(),
loc.getY(),
loc.getZ(),
loc.getYaw(),
loc.getPitch(),
player.isOnGround()
);
connection.sendPacket(positionPacket);
am i sending the wrong packet
or
what
Probably
Entity Position and Rotation This packet is sent by the server when an entity rotates and moves.
this packet is sent by the server
i hate wiki.vg sometimes
maybe i should look inside packetwrapper git page
the same packet
i dont get it
Hey, I wanna change a lot of blocks really fast but without lagging out a whole server what's the best way to do it?
im cancelling the inventory click in 1.16 but when i do that i can see the hand doing the left click aanimation
also i can other players doing the same too
probs fixed, i found another packet inside. Out class tag is for server sent packets while In for server received packets
thus netty doesn't know how to sent received type packet back
and it should've been obvious for me since it doesnt have entityId inside its own constructor args
for ^
@golden turret Unfortunately I am not finding any exact code for the structures but you might have better luck. Look through portal generation and such. Code that would need to check for structures like lighting a nether portal or placing an ender eye in an end portal frame. Etc..
np, thanks for the help :3
Server#getStructureManager()
đ I was looking for the full code though.
Actually.... I'm not seeing that in 1.17.1
declaration: package: org.bukkit, interface: Server
Why does discord mobile remove the last bracket from my hyperlinks
discord bad
I didn't say it didn't exist.... but in spigot 1.17.1 that I am using... its not there lol
Probably horribly outdated local maven repo ?
Nope I don't use dependency managers
Then a horribly outdated local spigot jar
Yeah probs. When was it added?
That would do it yea
Is latest actually latest or is it still the base 1.17.1?
Should be latest
When was it ever base 1.17.1
The structure API was added on the 5th of Oktober btw đ
đ
how are you still alive
Cause I don't "build" my plugins. Its a waste of time
lol
Real heros just look at the source code of a plugin to enjoy it
Didn't say I don't compile xD
you'll change your mind eventually đ
wrong reply
I meant yapperyapps
I know lol. But no I won't. Only reason I use managers is for shading. Which I rarely do.
I use managers for dependencies
I mean if you ever plan on working with multiple people you'll have to
I still remember when someone wanted to introduce me to maven and I hated it đ now I couldn't live without it anymore
But I use the project manager IJ has for exporting
I don't. Not a people person lol
Rip
I still hate github but started using it for new projects
Still rarely use it though cause i don't update those plugins xD
github is awesome. when you're a student, you get tons of free stuff there đ
havent scrolled thru but do Bukkit.getServer
I was using an old version
o
Building the new version now.
Nope latest doesn't contain Bukkit.getStructureManager(). Trying 1.17.1
Can someone help creating NPC with skin (1.8-1.17.1 support) or link to ready 1-2 class realization (not ready plugin)?
A single class (or event two) that supports that many versions will probably be nearly impossible to find and if it exists is horribly ugly
1.17.1 doesn't have it either? Are you guys getting your jars from buildtools or just looking at the source code?
Build tools.
Maybe your eclipse didn't index correctly
Latest should work perfectly fine
Odd. Both 1.17.1 and latest don't contain it.
Recaf doesn't show it either
also i don't need many functionality, just standing npc with custom name, skin and running command on click
Ok just did latest again and recaf shows it in this one...
Yeap it shows in eclipse too. 𤡠IDK why the first 2 didn't work
can someone please help, is there a way to make maven copy plugin jar into multiple directories at once????
Hi there, I'm having some issues with getting the human entity of a player
I'm new to programming plugins in java
I have the player object from the commandSender
now I need the human entity of the player
Why
entity.openInventory