#development
1 messages ยท Page 58 of 1
does it still use hashmap in the end? or completely different implementation
a "JumboEnumSet" uses a long[] array internally
no clue what a regular enum set uses
yeah anyway I'm not an md_5 simp, just to clarify that, lol
yeah anyway I got an actual dev question related to gson, one sec I'll find the github link
I'm using this shitty hack to avoid integers (and longs) being parsed as doubles in gson, is there a better way? Because this feels very dirty https://github.com/JEFF-Media-GbR/JsonConfigurationSerialization/blob/master/src/main/java/com/jeff_media/jsonconfigurationserialization/ConfigurationSerializableTypeHierarchyAdapter.java#L66
Hello, I need some help with Permission. I have a command called /ghost . And I want to hide that from player if they don't ahve a permission. But I want to freely access it via console. How can I do that?
commands:
ghost:
description: test
permission: ghost.command.help
With this, I was able to hide the command to player but this command isn't working in console as it says that I don't have permission.
that should work just fine from console
unless you delcared that permission to be "default: false"
by default, permissions have "default: op" and console is OP
Thank you! I made an error by creating another same permission node from permissions: which overrides the default value. Thank you so much!
np
Assuming the map is being used in the spigot ConfigurationSerializable with spigot's own classes, I don't think there is a better way (in your own custom classes you could cast to Number and go from there ig
I don't think gson would have an option to store it as an int because that goes against the json specs
You could also store it as a String though, and maybe put a unique identifier so that you don't get "false positives" with real strings such as like "this is a real integer: 123" ๐ฅฒ (This would be the most reliable method, because if there's a double 10.0, that would break because it's a whole number)
yeah it's meant to be used for ANY given ConfigurationSerializable
e.g. CraftItemMeta uses "instanceof Integer" when parsing the map so I need stuff to be an int
tbh I would do the string method - you don't have to add a prefix thing since that might look weird to the user, but if you do, that would be 100% reliable
and even if you don't, idk how often users name their item like "123"
ยฏ_(ใ)_/ยฏ
since I feel like doubles would be a whole number pretty often
I cannot add arbitrary strings to anything as I rely solely on gson's output - I simply throw the output of ConfigurationSerializable#serialize() (which is a Map<String,Object>) into gson's toJson(...) method
no I mean like add a "middleman" like how you're currently doing and replace all the strings of "int: 123" with an actual integer
I know that I could use a custom ToNumberStrategy for a certain gson instance, but my serializer class only implements JsonSerializer and that one doesn't have access to the gson instance
uuugh I don't really understand what you mean
like for ex ```json
{
"cool-int": "int: 123",
"cool-double": 123.45,
"cool-whole-number-double": 123.0
}
also hopefully theres no floats, shorts (are enchantments still in shorts?), and longs.......
if there are, you can just continue with float: 123.45, etc
orrrrrrrrrr
make a json parser ๐
dkin, the man with the ideas
I am dkin ๐
๐ฅฒ
Tbh it's easier than you think
I made one relatively quickly with half the performance of gson
I need to provide a TypeAdapter or what's it called to be used with gson
and unfortunately Gson's JsonDeserializer method does not allow me to specify a custom ToNumberStrategy
it only gives me a JsonElement
by current code is also working fine, but I still think it's nasty
Oh wait this is a library
How come you're not just making your own gson instance?
(also add .idea to your gitignore)
I want other people be able to add my thing to their gson instance using GsonBuilder#addTypeHierarchyAdapter or however it's called
ig you could add a Gson parameter then
unless it goes on the builder
then ig you could add a GsonBuilder parameter then ๐ฅฒ
that sounds like a horrible solution lol
https://helpch.at/docs/1.19.3/org/bukkit/inventory/InventoryView.html#convertSlot(int) wtf since when does this exist o0
this woul dhave saved me so much trouble
why?
Assuming ToNumberStrategy works (i have no idea what that is), it wouldn't affect the user (configuration is the same) and it wouldn't really affect the developer (it is reliable - 10.0 or any whole number won't break everything)
a ToNumberStrategy takes in a JsonElement and returns a Number. IMHO it should return double for 10.0 and integer for 10 and long for 91571515781571515615
but the default used ToNumberStrategy always returns a double
IMHO it should return double for 10.0 and integer for 10
but your method would return integer for 10, no?
so if you used ToNumberStrategy
it would work like how you'd want
wait
no
this leads to issues
MyItemStack:
# ...
enchants:
UNBREAKING: 1
this would return a Map<String,Double> for enchants. Unfortunately CraftItemMeta does an instanceof Integer in the buildEnchants() method, so it will not apply the enchantments if the value of the enchant is not an integer
I cannot add a custom ToNumberStrategy because I only get passed a JsonElement
yes
so there really isn't a good solution to this
especially since it's a library, and not a private plugin
yeah probably my current solution is the best that exists
im the idea man
or I just get drunk and call it a day?
now I suspect that you are already drunk lol
anyway I can't decide which Map gets used as json returns the map in fromJson(..., MAP_DATA_TYPE)
yeah its an Object value nevermind
๐
does anybody know if it's possible to use "variables" in javadocs, i.e. so that I don't have to write the same docs twice and be able to say "pls reuse the same javadocs as from the following method: ..."?
e.g. I got a public static final field of an instance of class XY, and I want the field to have the same javadocs as the XY class itself
is that possible without custom doclets ๐ฅฒ
proabably not, but you can have a @see Class
yeah unfortunately that's not what I want
I want it to copy the exact same content instead
I know at least one "InventoryMoveItemEvent" is pretty messed up (not accurate what the Javadoc saying) and it is like 1 or 2 lines to fix that mess and the option to update the inventory title according to paper is messy/bad (I don't think it is implemented yet). https://hub.spigotmc.org/stash/projects/SPIGOT/repos/bukkit/commits/ecfa559ae8821e3e2677fe168b536333f71149aa#src/main/java/org/bukkit/inventory/InventoryView.java (what I get sent to me, I'm not good at search on that site).
the setTitle method was merged in may and works fine from what I remember
it was merged within a few days IIRC, just by accident I saw it in the spigot changelogs like an hour ago lol
the InventoryMoveItemEvent is indeed messed up
I fully agree with that
somehow neither the original nor the new inventory contain that item at the time when that event is called
but what's wrong with the setTitle method? Works fine from what I know
although the javadocs are shit, idk why y2k didn't mention which exception it throws

https://github.com/PaperMC/Paper/issues/9189 I mean paper is still paper, they often complain. I have not check how they implement it. You should see how I implement that function (at least it works from 1.8.8 to 1.20.1) ๐
Yeah they perhaps should add @throws , don't know if that will compile. I know it could be little sensitive you can't add like & ๐
I mean paper is still paper
true lol. I also haven't checked how it's implemented, all I know is that it seems to work fine
So long it works, it doesn't need to look pretty XD
mojang's motto, I guess
I'm still angry that they obfuscate their .jar - what's the point if the distribute the mappings file >.<
Yeah how they implement the barrel in the code compere to other containers for example ๐คข
what are they doing?
Yeah anyway I have a very weird maven issue, maybe someone can help me with that.
I have one .jar that's using whatever-SNAPSHOT as version name. maven then appends a "build number" and "timestamp" to the actual name, and somehow maven always says the build number is 2 instead of 1 whe nI deploy this to my repo. I have already opened an issue on reposilite about that but it seems like the problem is actually my own project, but I cannot figure out why this happens, it's strange. Here's the reposilite issue I opened https://github.com/dzikoysk/reposilite/issues/1905
This seams to be the way to get the barrel from this fieldDataWatcherObject<NBTTagCompound> bR. So you get it from nbt tag and that can also contain other data? what is wrong with mojang staff, why not add it in containers class?
protected boolean a(EntityHuman entityhuman) {
if (entityhuman.bR instanceof ContainerChest) {
IInventory iinventory = ((ContainerChest)entityhuman.bR).l();
return iinventory == TileEntityBarrel.this;
} else {
return false;
}
}
I think it is inside net.minecraft.world.level.block.entity.TileEntityBarrel but not sure
ah yeah then it's BarrelBlockEntity in moj maps
ah that seems to be RandomizableCOntainerBlockEntity#stillValid(Player)
either way confusing as hell :/ I mean composter is in containers class?????
lol that makes little sense
composters don't even have any inventory or am I stupid
what the hell is a NonNullList ๐
it has "inventory" but only to store composted materials, no gui. So way not add barrels here?
huuh why does it even store the composted materials
Have you never use it?
I wrote a whole plugin about composters
from what I know, you can add items to composters and depending on the item, there's a certain chance that the level is raised
but I don't remember that a composter actually stores "what items" it got
sometimes I think that macgyver works at mojang, otherwise it's hard to explain why their code looks like they wrote it using a chewing gum and a paperclip
yes and in the end you get 1 bone meal, moss and leaves is best I think.
wtf?!
it can produce something that's not bone meal?
when was this added lol
from what I know, it always yields exactly 1 bone meal once the level reaches 7
No more the best materials to put in is moss and leaves.
is it not 8?
might also be 8, i don'
t remember
I'm pretty sure it's 7 though because it goes from 0 to 7 so 8 possible states
it is the redstone signal then
why do I get Invalid session even though I started the game 30 seconds ago ๐ฅฒ
I always get null I think on the id on first time I log in to a server (at least with a 1.16.5 client) and that happens every time I restart the game.
I just checked the composter - 7 is full and after a second or so, it automatically goes from 7 to 8
where 8 is the harvestable state that also shows the "bone meal" texture
so yeah it's full when it's either 7 or 8
yeah ๐ I pull this from the wiki "comparator outputs a signal strength between 0 and 8"
So your observation match this statment from the wiki "7 is for completely full but the bone meal is not ready to collect, and 8 for completely full and the bone meal is ready to collect"
Don't worry, it is rely useless flower sadly :/
but it's fancy ๐ฅฒ
yeah, but it could even be cooler if it did what the name suggested ๐
probably 105
i'm new to making plugins, ive got a kit system working but realized no modded items are persisting
this is my current implementation (this is day 1 of development so don't judge)
private void handleCreateLoadout(Player player, String[] args) {
if (args.length < 3) {
player.sendMessage("Specify a name for the loadout.");
return;
}
String name = args[2];
if (plugin.getLoadouts().containsKey(name.toLowerCase())) {
player.sendMessage("A loadout with that name already exists.");
return;
}
// Create the loadout from the player's inventory and add to plugin's map
List<ItemStack> itemsList = Arrays.stream(player.getInventory().getContents()).filter(Objects::nonNull).collect(Collectors.toList());
Loadout loadout = new Loadout(name, itemsList);
// Add the new loadout to the plugin's loadouts map
plugin.getLoadouts().put(name.toLowerCase(), loadout);
player.sendMessage("Loadout " + name + " created successfully!");
}
private void handleSelectLoadout(Player player, String[] args) {
if (args.length < 3) {
player.sendMessage("Specify the name of the loadout to select.");
return;
}
String name = args[2].toLowerCase();
Loadout loadout = plugin.getLoadouts().get(name);
if (loadout == null) {
player.sendMessage("No loadout with that name exists.");
return;
}
player.getInventory().clear();
for (ItemStack item : loadout.getItems()) {
player.getInventory().addItem(item);
}
player.sendMessage("Loadout " + name + " equipped!");
}```
vanilla items work fine when I retrieve them, but modded are empty slots
using mohist for spigot/forge integration
is this even possible or not with forge items? do I need to do a different method of handling the inventory items?
looks like i'll be looking into spongeforge instead... thanks for that notice lol
mohist bad
also mohist users are weird and tend to leave 1 star reviews for your plugins because they think it's the dev's fault if sth doesn't work on this weird fork
I remember that I once looped over Material.values() and mohist threw a NPE or sth (while doing Iterator#next()) for non-bukkit materials or sth
Material.values() returns an array?
yes
yea so howd the non existant iterator throw an exception and how was it an npe
Real
What would be the best way to store a placer of a Shulker? iirc there is no way to do it with PDC right?
How can an enum constant be null?
Shulkers are tile entities, It doesnt have PDC?
@uneven lantern ping
Yes, the Box
I believe I have to cast block state to https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/block/ShulkerBox.html this then
Yes
Thanks
At the top you can see it implements PersistentDataHolder
Yes saw that thanks
Material m = null; 
but yeah, .values() shouldn't can't contain nulls
Not what I meant smh M0dii
yes
"mohist" that's your answer, god knows how many hacky things they do
I have seen the wackiest problems with it
Enum values having null on it doesn't surprise me
Hey
I was just thinking
How does mohist handle materials different than those defined in the Material enum?
Like, for example the BlockPlaceEvent, what's the Material if the player placed a non-vanilla block?
often the answer is "not very well"
theres been lots of attempts to do things like this and afaik theyre usually shit
but i guess they patch the material class, not sure
I have a plugin which is developed for both 1.8 and 1.16 (customer wanted it) I'm using Material.getMaterial("NETHERITE_SWORD") with null check for checking does the version have NETHERITE_SWORD or not and then I tried Material.values().toList().filter { it.name.contains("SWORD") } (it is a kotlin code but it gets values() as list and filters them) then I got a list of [LEGACY_IRON_SWORD, LEGACY_WOOD_SWORD, LEGACY_STONE_SWORD, LEGACY_DIAMOND_SWORD, LEGACY_GOLD_SWORD], what causes this? How can I make it give me a proper list with NETHERITE_SWORD on 1.16?
set api-version: 1.13 in plugin.yml
and perhaps add another condition in there, !it.name.startsWith("LEGACY_")
does that have any side-effects? I solved it using another way :d (get declared fields of Material and filtering them using their name)
no afaik
if all plugins have api-version defined, spigot won't do its legacy bullshit
I mean that kills 1.8 compatibility doesn't it?
A
but yeah, if you set it to like 1.16, it won't run on 1.13-1.15
Idk check mohists implementation
oh I just checked it, and I remembered it wrong - it was actually CatServer ,notmohist, and it threw a NoSuchElementException when looping over the recipeIterator() https://github.com/Luohuayu/CatServer/issues/540
their "fix" for this is also kinda funny https://github.com/Luohuayu/CatServer/pull/549/commits/17035303e0e05a5490af87ee101308091433754e
mfw Collections.emptyIterator exists 
oh i see what that is doing ๐ that is hideous
instead of calculating if there is a value available in hasNext it does it inside next
dear god
What if someone made a forge and fabric thing ๐ค
i'm still confused why catserver is rethrowing that exception instead of just skipping the non-bukkit materials
makes little sense to me lol
true
i think they used to have a cute mascot too, but i can't seem to find it anywhere
not a mineraft question but does anyone have a comprehensive guide to use sourcemod? I haven't used it in 10+ years and now wanted to get back at it - somehow I can only find specific tutorials on their website but nothing about "how to get the project started" in the first place
I little confused about this error https://paste.helpch.at/cabolohuqe.md and the method https://paste.helpch.at/ayadikabuc.kotlin the error start with line 25 but no value is null, as you can see top of the stack trace.
So the bug seams to be in the nms/spigot/bukkit api. I know it is old server version, but little confusing error.
you can use a debugger to see where it goes wrong
I did already debug it, no values is null. Don't know if the effect SPELL could be the issue.
System.out.println("this.world " + this.world);
System.out.println("location " + location);
System.out.println("this.effect " + this.effect);
System.out.println("this.data " + this.data);
use a proper debugger and step into the internal bukkit code
what type of debugger do you suggest?
the IntelliJ debugger
I don't see that help so much. Not give me any extra info.
Yeah, I searched about it. But it seems like it's already setup in my idea. But yeah how to use it is a different question.
The only thing I can think of, is that I use the wrong class for data.
Are there any fake inventory packages people use? I could dump files into DeluxeMenus but seems a bit "hacky" to do that
if you dont care about having to deal with extra data you can use World#spigot()#playEffect(Location,Effect)
tho from what i can tell its not using the right method which is strange
tho thats probs the data is using a type other then int
since there are two methods, one that uses int for data and one that use T (Generic Type)
tho id suggest casting it to int
I accidentally used a double instead of int I think I could create some issues
@Override
public <T> void playEffect(Location loc, Effect effect, T data, int radius) {
if (data != null) {
Validate.isTrue(data.getClass().isAssignableFrom(effect.getData()), "Wrong kind of data for this effect!");
} else {
Validate.isTrue(effect.getData() == null, "Wrong kind of data for this effect!");
}
if (data != null && data.getClass().equals(MaterialData.class)) {
MaterialData materialData = (MaterialData)data;
Validate.isTrue(materialData.getItemType().isBlock(), "Material must be block");
this.spigot().playEffect(loc, effect, materialData.getItemType().getId(), materialData.getData(), 0.0f, 0.0f, 0.0f, 1.0f, 1, radius);
} else {
int dataValue = data == null ? 0 : CraftEffect.getDataValue(effect, data);
this.playEffect(loc, effect, dataValue, radius);
}
}
@Override
public void playEffect(Location location, Effect effect, int data, int radius) {
this.spigot().playEffect(location, effect, data, 0, 0.0f, 0.0f, 0.0f, 1.0f, 1, radius);
}
this makes sense why you are getting a npe
since you are using something other then int, the first method is called, and when it attempts to do data.getClass() it would npe since double isnt an object its a primitive type
if you had used Double it wouldve probably worked
or should i say wouldve spit out the wrong kind of data error seen there
Yeah I miss the obvious some time.
I did not have the time to really test the mistake with the double. And your inputs help me on the way. Will check this later this evening.
And I did not find just " location and effect" argument
thats because its under the .spigot() method
Oo that explains it.
currently diving through packets, im trying to figure out when Use Item (Serverbound 0x32) is called, because its not firing when im expecting it to according to its description on wiki.vg
its supposed to fire when you right click with an item in hand, im doing that and its firing as Use Item On (Serverbound 0x31) or atleast it is according to protocollib
this is on 1.19.4 with protocollib 5.1.0
actually might be when you attempt to eat idk
yeah I think it counts as Use Item On since you're using it on the air
Use Item is consumable items like food, potions, milk, etc
Use Item On is like placing blocks, or, well, anything that won't trigger a Use Item really
turns out im a bit dense and forgot to add BLOCK_PLACE to the list of packets to listen for kekw
in protocollib the packets have their name switched around, USE_ITEM does the use item on packet, and BLOCK_PLACE does use item packets, so basically use item == blockplace and blockplace == use item
so helpful craftbukkit, so helpful
using protocollib is pretty meh tbh unless you for whatever reason must support multiple versions out of the box
even then not all plib packet types are really transferable between versions, as some packets are replaced or deleted, good luck figuring those out
im not using protocollib for multi version
im using it only to listen to packets incoming or outgoing cus i wanna get something to work untill i get around to going the normal route of netty stuff
it's pretty painless on paper
not api
oh
it's internals but you can easily register a listener that will get called on channel initialize
wdym? (link?)
ChannelInitializeListenerHolder.addListener(Key.key("cool-plugin:whatever"), channel -> {
// ... add ChannelHandler etc
});
yes
but protocollib lets u convert it to mc stuff
whereas i assume netty just gives you the bytes?
depends on where you put the channel handler
if you put it at the very beginning, yes
if you put it before the Connection handler, no, it's deserialized to the Packet pojo by the packet_decoder or w/e
oh its like a fresh new feature
still stuck on 1.19.4 for the time being, ill look into it later
packet pojo
like the vanilla mc ones?
because if so, combined with paperweight, would be pretty nice
it was also there in 1.19.4
I mean, how else are you gonna register the listener if it isn't API lol
true ๐ฅฒ
wait then how would you access it in the API
like if you don't have paperweight
wouldn't it show as like an error?
it is not API ....
oh its a server patch
yes
Cf on top
Hi, Someone know how can I get the Armor Toughness attribute from an ItemMeta and then adding 1 to it ?
I've done that to test but I got an error
if(command.getName().equalsIgnoreCase("test")){
Player player = (Player)sender;
ItemStack item = player.getItemInHand();
ItemMeta meta = item.getItemMeta();
meta.getAttributeModifiers(Attribute.GENERIC_ARMOR_TOUGHNESS).add(new AttributeModifier("test-toughness", 10, AttributeModifier.Operation.ADD_NUMBER));
item.setItemMeta(meta);
}
Caused by: java.lang.NullPointerException: Cannot invoke "java.util.Collection.add(Object)" because the return value of "org.bukkit.inventory.meta.ItemMeta.getAttributeModifiers(org.bukkit.attribute.Attribute)" is null
at fr.skylined.evolution.Main.onCommand(Main.java:82) ~[?:?]
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:45) ~[spigot-api-1.20.1-R0.1-SNAPSHOT.jar:?]
... 23 more
get description
Return an immutable copy of all AttributeModifiers for a given Attribute
I have done this, it work but there is a little problem...
AttributeModifier modifier = new AttributeModifier(UUID.randomUUID(), Attribute.GENERIC_ARMOR.name(), 1, AttributeModifier.Operation.ADD_NUMBER, EquipmentSlot.CHEST);
meta.addAttributeModifier(Attribute.GENERIC_ARMOR, modifier);
But if I repeat my command to test multiple times it shows up like this on the item :
When on Body:
+1 Armor
+1 Armor
+1 Armor
...
do you know how can I make it so it shows up like this :
When on Body:
+3 Armor
yeah probably because you add 3 different modifiers
Then I can do that maybe ?
meta.getAttributeModifiers(Attribute.GENERIC_ARMOR).add(new attribute here)
```?
no
Check if there is any modifier for that attribute, if not add a new one, otherwise increase the value of the existing one
Hello! I have a problem with placeholders of the PlaceholderAPI plugin in my plugin. I found a solution on GitHub, but I don't understand how to modify my code by adding the code from GitHub.
i dont see any mention of placeholderapi in this class at all, also having everything in one class is pretty eww
I know that I didn't add PlaceholderAPI to the class, but I'm writing in this chat because I don't know how to add it in a way that the placeholders would work.
Read the wiki?
yes
package at.helpch.placeholderapi;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;
import me.clip.placeholderapi.PlaceholderAPI;
public class JoinExample extends JavaPlugin implements Listener {
@Override
public void onEnable() {
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
/*
* We register the EventListener here, when PlaceholderAPI is installed.
* Since all events are in the main class (this class), we simply use "this"
*/
Bukkit.getPluginManager().registerEvents(this, this);
} else {
/*
* We inform about the fact that PlaceholderAPI isn't installed and then
* disable this plugin to prevent issues.
*/
getLogger().warn("Could not find PlaceholderAPI! This plugin is required.");
Bukkit.getPluginManager().disablePlugin(this);
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onJoin(PlayerJoinEvent event) {
String joinText = "%player_name% &ajoined the server! They are rank &f%vault_rank%";
/*
* We parse the placeholders using "setPlaceholders"
* This would turn %vault_rank% into the name of the Group, that the
* joining player has.
*/
joinText = PlaceholderAPI.setPlaceholders(event.getPlayer(), joinText);
event.setJoinMessage(joinText);
}
}
.
I have an unusual message output system
Hi I have created a custom recipe in the anvil using the PrepareAnvilEvent (be cause my recipe need to handle nbt and attribute) but when I click on my result item I can get it. I use event.setResult(ItemStack) in my code
I mean in game it shows up in the GUI but I can't get it
so are you trying to allow placeholders to be used in your messages or are you trying to add your own placeholders or what?
me need placeholder %vault_rankprefix%
in messages: onMessages and offMessages
then just do PlaceholderAPI.setPlaceholders(player,yourmessage)
hm
like ig for example on line 127 you can do getServer().dispatchCommand(getServer().getConsoleSender(), PlaceholderAPI.setPlaceholders(player,group.getCommands()));
since if you have the player expansion you dont have to replace the %player_name% placeholder yourself anymore
String messages = enabledGroups.getString(groupName + ".off_messages");
I don't understand...
PlaceholderAPI.setPlaceholders(player,message)
oh

Ee
String messages = enabledGroups.getString(groupName + ".getMessages");
like i dont really get what your plugin is even trying to do
staff work mode
thats not really that descriptive
so your trying to make a weird permissions plugin?
yes)
why not just use luckperms? its like one of the standard permissions plugins
everything works for me except the placeholder
nonono)
why reinvent the wheel?
in what sense
there is very little sense it trying to make another permissions plugin
tho it doesnt even look like your doing that
this is not a permissions plugin, it is a plugin for granting permissions to players through certain commands, granting privileges to players to work on the server
are you doing this convoluted way instead of doing it through a permission plugin?
ohhh its a wrapper
helper:
off_commands: "lp user %player_name% parent add helper"
off_messages: "&6StaffWork &8ยป %vault_rankprefix%&7%player_name% &aะฝะฐัะฐะป ัะฐะฑะพัั."
group_permission: "blackdigo.sw.offhelper"
permission_priority: 1
offhelper:
on_commands: "lp user %player_name% parent remove helper"
on_messages: "&6StaffWork &8ยป %vault_rankprefix%&7%player_name% &cะทะฐะบะพะฝัะธะป ัะฐะฑะพัั."
group_permission: "blackdigo.sw.helper"
permission_priority: 1
it would make more sense to compact them into just one entry cus its unlikely that you would have access to give them permissions but not to take them away
prefix_message: "&6StaffWork &8ยป"
enabled_groups:
helper:
on_messages:
- "%prefix% %vault_prefix%&7%player_name% &cะทะฐะบะพะฝัะธะป ัะฐะฑะพัั."
on_commands:
- "lp user %player_name% parent add helper"
off_messages:
- "%prefix% %vault_prefix%&7%player_name% &aะฝะฐัะฐะป ัะฐะฑะพัั."
off_commands:
- "lp user %player_name% parent remove helper"
group_permission: "blackdigo.sw.helper"
permission_priority: 1
also you should probably use StringList rather then String
also its %vault_prefix%, not %vault_rankprefix%
I always forget, if I make a plugin that should work from 1.8.8-1.17 I should make the jar in 1.8.8 right?
Yes
Where can I see the list of dependency versions?
I think it's this but can't find it compileOnly("io.papermc.paper:paper-api:1.17.1-R0.1-SNAPSHOT")
It depends what you do. For example, if you have a GUI and want to allow users to use shields with custom banners, you would need to use spigot-api 1.9+
But what would happen for 1.8.8 servers then?
Or wait 1.8.9 it might be not sure
As long you add a check that works in 1.8, it will be alright
E.g. material.name().equals("SHIELD")
How about methods that have a different name in the API in 1.17 than 1.8, what will then happen?
It would still work right?
There isn't any, spigot maintained backwards compatibility
Paper didnt though? Or did they?
They did.
So what happens if I use text components etc?
Adventure works on 1.8 just fine, but you need to shade it alongside with bukkit platform
Spigot compatibility while using paper-api is a different thing. And even if you want to support paper only, you can't depend on its version of adventure, because it is available only on 1.16.5+
I just said fuck you and only support paper with java 17
And I've never been happier
Had to code in java 8 today and holy moly
Yeah I miss var and Records xD
I use the latest jar and make sure to check the version when using specific methods/materials etc...
The issue is that it has to work with WineSpigot 1.8.9 and Purpur 1.17.1 though lol
And Purpur 1.19 actually
Yeah all you have to do is add api: 1.13 to the plugin.yml
1.13?
Yeap.
Why exactly that version?
Alright, and also that jar version in the jar ig? Or just 1.19?
The api-version thingy was added in 1.13 so that's the lowest you'd go if you want to support the most amount of versions
Ahhh gotcha, thanks! :))
But which dependency version should I use? Which would you guys recommend?
no you don't include it at all
if it's not included, then spigot assumes <1.12 (pre-material change)
Depends which methods you want to use.
but if you include it, it assumes 1.13
he wants to make it 1.8
so you shouldn't include it at all
It won't load the plug in on versions above 1.13
yes it will
it shows a "legacy plugin" (since it's for 1.12 and below, it adds legacy compatibility) warning
Really when did that change?
it should've always been like that
maybe the warning made it confusing (and some other issue made the plugin not load, resulting in thinking that the warning was the reason?)
since it's not just a normal INFO message
or maybe its somewhere in 1.13 to like 1.15 since i didn't code from that long ago
It's been awhile now so maybe I'm wrong... but when 1.13 released plugins were disabled if they didn't contain the api version.
when 1.13 released
oh then maybe since I didn't even play minecraft when 1.13 released ๐ฅฒ
Well anyone here can test it lol. I'm not on PC right now.
Which dependency should be used? Latest version I'll be using or?
It's your preference. Are you gonna make use of the latest methods on higher version servers?
Not really I think, but I might lol
use 1.8.8
any code that exists in 1.9 api for ex will end up erroring if you run it on 1.8
Alright, thanks :))
ah for this ig you could use reflection?
iirc 1.9 is the end update and so there might be a lot of new additions that they might accidentally use
As long as you check the version before using the method you won't have issues.
Alright, thanks
For whatever reason you want to support a version older than some Minecraft players lol
earliest you'll be using
spigot guarantees forward compatibility but not backwards compatibility
it's easy to fuck up doing things like this
oh shoot
have I been calling forwards compatibility "backwards compatibility" this whole time
๐ฅฒ
well it depends on your perspective
but i think saying backwards compatibility is misleading people into thinking new plugins work on older versions
Backward compatibility is a design that is compatible with previous versions of itself. Forward compatibility is a design that is compatible with future versions of itself
so it is a matter of perspective really
It should be in relation to whatever the API version is, no?
"it"?
Like if the plugin is running API version 1.8, and it works on the latest version, its forward compatibility
yes
i feel like 95% of people say backwards compatibility though
and they would be wrong
Java is backwards compatible, not Spigot

i mean
Just like Skript
a java 16 program isn't compatible with previous versions
again it depends on your perspective but yeah id say theyre the same
unless you mean the side from the java -jar
older programs can run on newer jvms
not vice versa
so... it's either the programs being forward compatible, or the jvm being backwards compatible
I mean I'd assume it would work as long as all the classes/methods still exist in the latest version of spigot
yes, and spigot basically never removes stuff for this reason
almost every deprecated method still works
I'd assume its almost always NMS that breaks plugins on version updates
There are some cases of other things breaking it like Tag.REPLACEABLE replacing other tag types in 1.20
if a 1.8 plugin doesn't use any internals then theres a very high chance (afaik) that it would still work on latest
๐
I should look at how multi-versioned anticheats do it
Maybe it would be able to run but it would probably have issues
true
Hello! How to disable PvP mode for a specific player so that they cannot deal damage?
player.
Check entity damage event
listen to EntityDamageByEntityEvent. Get the damager. if the damager is a projectile, use Projectile#getShooter() instead.
Now if the damager is a player, you can cancel it
Is spigot 1.8.8 actually completely outdated and not possible to use anymore?
1.8.9
There's no such dependency
Dunno
I really hope it is
you need the bungee repo too
if you google "spigot gradle" or that error it should come up
(i think theres 2 repos you need - the snapshots repo and the bungee)
I would've said yes and hope he will use 1.17 api instead D:
I made this code to create a "trench" enchant, but the issue is that it keeps getting called again and again as player.breakBlock triggers the event again ofc. any way I can avoid this while other plugin still being able to access the event to check for regions etc on the other blocks?
simulate the blockbreak
its like uhh, Block#breakNaturally(ItemStack)
instead of getting the player to do it
and ofcourse do your checks for each block before calling that method
you can also add like a "lock"
Haven't looked at the code, but block break events are ran synchronously, so you can just keep the uuid in like a map until the event is over
if the uuid is in the map, ignore the event
Yup, that's what I'm doing rn
Kinda
Here's the update https://paste.helpch.at/aculiririt.java
but theres no reason to do that when Block#breakNaturally exists
means you are only doing a player break once and the rest dont trigger the event
uhhhhhh
interesting way of writing a boolean variable...
oh
uh
now that I think about it, you don't even need to store the location or the uuid
since it all runs sync, no?
orrrrrrrrrrrrr you can do Block#breakNaturally
as Lunaiskey suggested
only problem with Block#breakNaturally(ItemStack) is that you cant modify the items dropped, which means you will have to go through the craftbukkit classes, figure out exactly what they do and then copy that ofcourse with the blocks dropped missing and just calculate the block drops yourself manually or something
Well no, I can't. breakNaturally doesn't run the BlockBreakEvent which I need for other plugins to handle worldguard regions, drops etc.
I could manually call the event, but there would be no reason to do that when player.breakBlock exists.
It is better to handle the breaking on your own afaik, because breakBlock doesnt apply enchantments and stuff as you would expect
oh interesting
even tho it inputs an ItemStack instead of like a Material
so it doesnt count stuff like fortune or whatever?
according to the javadocs
This method will respect enchantments, handle item durability (if applicable) and drop experience and the correct items according to the tool/item in the player's hand.
Hmm, then it might be the case for a method on Block, is been a while ๐คฃ I think Block#breakNaturally(ItemStack) or Block#getDrops(Entity, ItemStack)
can anyone join a vc and help me with my plugins
Has anyone used the api of github for creating cards in projects? I want to migrate a system that uses trello to github projects and I can't seem to find a way to specify what custom fields I want to add to the card (default field: Status; custom fields: Priority, Type)
The rest api only has a few parameters https://docs.github.com/en/rest/projects/cards?apiVersion=2022-11-28#create-a-project-card
I think I've found a way, with graphql https://docs.github.com/en/graphql/reference/mutations#updateprojectv2itemfieldvalue
yeah Block#getDrops() returns some bullshit, e.g. it's always WHEAT for wheat crops and e.g. ignores that you'd also get seeds, and stuff like that
Hey there, if I set the amount of an itemstack to something like 300 and remove it from the inventory, will it remove 300 items of that itemstack or does it not work like that?
TLDR
bruh
Current issue: /dupe off
How it's supposed to work: Operators run /dupe off - plugin takes the item in the operators hand - adds it to a set which is saved into the config.yml file - running /dupe off again will take it out of the set (all of that works fine)
When a player now trys to run /dupe to duplicate the item, if the item is in the set, the player can't dupe the item.
The Issue: The player is STILL able to run /dupe on the item which the operator ran /dupe off on. What is causing the issue?
You should check using ItemStack#isSimilar, or what you can do is try cloning the item and setting the amount to 1 both when you add it to the set and when trying to dupe it
Also you can change
if (undupableItems.contains(itemType)) {
undupableItems.remove(itemType);
```to
```java
if (undupableItems.remove(itemType))
I did do that but the thing is that it also takes the quantity into account. Therefore when you retry to dupe it, it will only not work for that quantity and not the material.
Do you want it to require the same amount?
The quantity shouldnโt matter it should only take the material into account
Thatโs why I changed it to material before it was itemstack
Oh
You're checking if the set contains an ItemStack, not a Material
getItemInMainhand returns an ItemStack
You're IDE should warn you about that
Right and then I have a .getType()
if (undupableItems.contains(itemInHand)) {
player.sendMessage("This item cannot be duplicated.");
player.playSound(player.getLocation(), Sound.BLOCK_ANVIL_LAND, 1f, 1f);
return true;
}
yo if anyone wants to have a multitool message me
i have all the tools
???
'Set<Material>' may not contain objects of type 'ItemStack'
if you want me to change my Set<> to an ItemStack, I'll just have the same issue I had before where it's quantity specific
Thatโs the warning itโs telling you, use itemInHand.getType()
yes, thats what itemType is
ItemStack itemInHand = player.getInventory().getItemInMainHand();
if (!itemInHand.getType().isAir()) {
Material itemType = itemInHand.getType();
if (undupableItems.contains(itemType)) {
undupableItems.remove(itemType);
saveUndupableItemsConfig(); // Save the updated set
player.sendMessage("Item is now dupable.");
player.playSound(player.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1f, 1f);
} else {
undupableItems.add(itemType);
saveUndupableItemsConfig(); // Save the updated set
player.sendMessage("Item is now undupable.");
player.playSound(player.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1f, 1f);
}
saveUndupableItemsConfig();
return true;
}
} else {
sender.sendMessage(ChatColor.RED + "You don't have permission to use this command.");
player.playSound(player.getLocation(), Sound.BLOCK_ANVIL_LAND, 1f, 1f);
return true;
}
Yes, but you have undupableItems.contains(itemInHand)
ItemStack itemInHand = player.getInventory().getItemInMainHand();
if (itemInHand.getType().isAir()) {
player.sendMessage("You need to hold an item to use this command.");
player.playSound(player.getLocation(), Sound.BLOCK_ANVIL_LAND, 1f, 1f);
return true;
}
if (undupableItems.contains(itemInHand)) {
player.sendMessage("This item cannot be duplicated.");
player.playSound(player.getLocation(), Sound.BLOCK_ANVIL_LAND, 1f, 1f);
return true;
}
that doesnt change the fact that the set undupableItems is still a Material and not an ItemStack, and reverting it to an ItemStack will be quantity senesitive
I'm not telling you to change it to an ItemStack
I'm telling you you're checking if the set contains an ItemStack instead of a Material
Read this code carefully @small arrow
if (undupableItems.contains(itemInHand))
You're welcome
I am so sorry ๐
Lol it's okay
Issue Resolved ๐ tysm for the help!
No problem
Hi,
do les anyone know if there is a better way to do this https://pastebin.com/WaF6NuVz ?
I just want to check wether the player has to turn left or right to look at the target
Any good tutorials online for how I can make placeholders for my plugin through PAPI?
assuming you mean inside an external plugin's internal class
which is what I'd recommend for making PAPI placeholders for your plugin
placeholder format: %identifier_params%
No. I mean I want to add placeholders to my existing plugin. I currently have an events system with โtime until eventโ and want to display that through a placeholder using PAPI.
isn't the link what you mean?
or can you give a more specific example?
since by that example you can have like a %events_time_remaining% placeholder
and based on this format, events = identifier, and time_remaining would be the params
identifier and params can be found on the link
(it should also automatically scroll you to the relevant part of the page)
unless you mean that you're trying to use already-existing PAPI placeholders from another expansion or plugin: https://github.com/PlaceholderAPI/PlaceholderAPI/wiki/Hook-into-PlaceholderAPI#setting-placeholders-in-your-plugin
Yes. I am mistaken I shouldโve read carefully. Thank you so much!
I got an issue with gradle not being able to find my script from inside buildSrc - can I somehow send a screenshot here? Or am I allowed to link to some screenshot website?
it complains about my bukkit module's build.gradle:
Build file 'C:\Users\mfnal\IdeaProjects\lightpermsx\bukkit\build.gradle' line: 2
Plugin [id: 'lightpermsx.java-conventions'] was not found in any of the following sources:
Here's the whole github repo: https://github.com/mfnalex/lightpermsx
I got it working myself. Additionally to declaring the actual script in buildSrc/src/main/groovy/lightpermsx.java-conventions I also had to declare a build.gradle in buildSrc/ with the following content:
plugins {
id 'groovy-gradle-plugin'
}
I could then apply my "lightpermsx.java-conventions" script file using plugins { id 'lightpermsx.java-conventions' } in my subproject. However gradle was also angry that i declared the lombok plugin like this in my buildSrc/src/main/groovy/lightpermsx.java-conventions.gradle file:
plugins {
id "io.freefair.lombok" version "8.2.2"
}
I had to replace this with just id "io.freefair.lombok" (so without the version). Obviously it then complained about this plugin not being specified anywhere, which I fixed by creating a build.gradle file in the root project that consists of nothing but this:
plugins {
id "io.freefair.lombok" version "8.2.2" apply false
}
Is it possible to side load worlds in from a different directory?
Like, I wanna have โplayer-worlds/<uuid>/โ where the uuid is the name of the world
I donโt really want it to clog the main directory, thatโs why
another question about gradle. I now have my core module and bukkit module working, both share a script in buildSrc/. Obviously I want the bukkit module's .jar to include the core module's classes. Ofc I could use the shadow plugin but people once told me it's also possible to do with directly with gradle, without third party plugins - does anybody know how?
at least with spigot's api, this isn't directly possible
pretty sure you can do new WorldCreator("a/b/c")... and that'll be the dir structure as well 
oh you're right, that does indeed work
i would have thought it'd complain about "illegal char" in the world name or sth
uh I don't remember the exact details but in the jar task something about adding zipTree("uh stuff") to the inputs, you can do that for the whole runtimeClasspath
thanks but I figured I'll just shadow to save myself the trouble lol
does anyone know how I can achieve sth like this https://blog.jeff-media.com/how-to-make-maven-automatically-put-your-plugins-jar-into-your-test-servers-plugins-folder/ using gradle, but only for one submodule's shadow artifact?
basically, I wanna be able to do gradle export-to-test-server instead of gradle build . it should do exactly the same as build, except that it changes the output directory of one module's shadowJar to another folder
I have tried adding this to the one module's build.gradle but when I ran gradle export-to-test-server it still created the .jar at the default location (myModule/build/libs)
tasks.register("export-to-test-server") {
jar {
destinationDirectory = file(...)
}
}
uh idk groovy dsl but in kotlin dsl is something like this
tasks {
register<Copy>("exportToTestServer") {
dependsOn(shadowJar)
from(shadowJar.flatMap { it.archiveFile })
into("/...")
}
}
also unrelated but if you name your tasks camelCase you can run them by their initials like so ./gradlew eTTS ๐
oh right, I didnt worry much about the name, wanted to get it working at first lol. So you're suggesting to just copy it, yeah actually why not.
I already declared build to dependOn shadowJar, so I guess I can make my task depend on build instead of shadowJar, right? Let me quickly try to translate this to groovy, then I'll see if it works. thanks
i believe on groovy you'd just do from shadowJar.archiveFile instead of the flatmap
yeah it complained about the flatMap, so I tried this:
tasks.register("exportToTestServer", Copy) {
dependsOn build
from shadowJar.archiveFile
into '/c/mctest/plugins/'
}
that runs without errors and I also see that it ran the task, but nothing happened (except that it built everything normally)
oh wow, I'm stupid. I'm running it from IntelliJ and not git bash, so I needed to use C:\ path names. using /c/path/ it just silently failed lol Thanks!
hello, having an issue with this
block.blockData = Bukkit.createBlockData(unstrippedBlockMaterial) {
it as Orientable
it.axis = (block.blockData as Orientable).axis
}
Works as intended, unless im in creative?? anyone care to advise?
weirdly enough, if I print the block.type right after, its correctly set??
but the update never actually happens
this is being executed in PlayerInteractEvent btw
Works as intended, unless im in creative?? anyone care to advise?
that code itself has no player in it, can you show more of the code?
for sure, https://pastebin.com/1GcLXdCp
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.
thats the entire event
everything gets executed from start to finish as expected
works fine in survival
but in creative seems to not wanna do anything
btw tip: you can do private fun PlayerInteractEvent.onEvent() { ... }
also are you making sure that it's actually being called? Since it seems ok...
wait what is in UNSTRIP_MATERIALS
UNSTRIP_MATERIALS is just a list of items than can unstrip the logs, for now just all the axe items
kind of badly named actually
and ye its being called
like i said, it works fine in survival mode but when i go creative, the block type doesn't update but the sound is played and the item in hand is swung and print statements show it working from start to finish
version is 1.20.1, should also mention that
hmmm odd
try
- removing
UNSTRIP_MATERIALScheck and just trying with a regular hand (nothing in the hand) - cancelling the event afterwards
ยฏ_(ใ)_/ยฏ
kinda random ideas but worth it if you still have the issue
@dusky harness the cancelling event at end works, likely because my code works fine and updates the block but during the same tick, the log is stripped again after all the events are processed
so it gives the affect that it isn't unstripped but infact does the unstrip and strip in the same tick
:/
also note that you can also do if (material !in UNSTRIP_MATERIALS) {}
uhhhh
ยฏ_(ใ)_/ยฏ
i've been doing too much C# at work :/
this is really nice tho, thanks for the tip
kotlin ftw
lol does pastebin require you to put in a category or smth?
just noticed that randomly
the Gaming
i was playing around with it, first time using pastebin
you should host pastes.dev instead ๐ ๐ (haven't checked but i assume you're using hastebin)
im not
oh?
pastes.dev my beloved
99% of people host pastes.dev hastebin
been coding for years but this is the 2nd time ive used a paste thing before
hastebin
i agree
wdym?
i wanted to host that once: https://github.com/szabodanika/microbin
seems like it ahhahaa
very cool
thank you
Oh shit, you're alive
REMENCE ๐ฎ
good song!
Hey simple question
private static final List<String> CMDS = "minecraft", "testje", "blasalala";```
How do I do this correctly?
List.of("minecraft", "testje", "blasalala")
Then I'll have to do this
Is this smart to do?
Depends on what version you want to be developing for
Java version 17
then you can change it to language level 17
It is already like that
no it isnt. its 8
thats the sdk
set it on the jdk too
thank u
np
I've got this in my .gitignore
.idea/compiler.xml
.idea/jarRepositories.xml
.idea/modules.xml
.idea/misc.xml
.idea/*.iml
.idea/modules
Then I unstage the changes, but then when I use git add . it adds them back, even though they should be ignored, anyone got an idea why?
Were they committed already? Also, simply adding .idea/ to .gitignore is enough btw
Yeah they're on github already from a previous commit. Tried changing it from ./idea because I thought that was the issue but yeah
Didnt work
you need to remove them first, I think it is, uh, git rm --cache -r .idea or smth like that
Np
Yeah, does the same it seems
ah
Hey guys, kinda need assistance here, I have been changing and trying to get this to work for the past hours but it seems like I am either stupid, blind or this actually doesn't work.
I have a compact coin (64 normal coins) and a normal coin, I am making a remove method so that it removes X amount of coins, it works like intended besides in one specific case, when I don't have normal coins, only compact coins, it's supposed to convert the respective amount of compact coins needed to normal coins, to then remove the normal coins that it needs.
If someone is able to see something or just an idea on what could be going wrong.
(for context, it doesn't convert nor remove anything)
compare lines 30 and 51
as a very general piece of advice, i find it very helpful to break large functions with lots of control flow into smaller ones
doesn't matter if the end result is functions that seem too simple to justify being their own thing, the point is to better organize and not be tricked by nested if's that might otherwise hide stuff from you in plain sight
since 90+% of the time the issue for me in cases like this is with something happening when it shouldnt or vice versa, eg. control flow
yeah ty
If you're too lazy you can actually ask ChatGPT, and since it doesn't write code by itself, it usually works
xD, think I already figured it out
Hi, I have a question, I'm making a java program that needs to create a schematic file, but I can't write a single schematic and I don't understand how to create one, so I don't know if anyone here knows how to do it?
Like many other mc files a schematic is an NBT file. You can look at the structure here: https://minecraft.fandom.com/wiki/Schematic_file_format
You could probably use a java NBT api and create one with those fields
Note this is a legacy format that doesnโt properly support 1.13+. You should probably look into the Sponge schematic format
How do you name your event listeners?
I have been doing EventNameFeatureName but this results in incredibly long and confusing file names.
AnvilInventoryClickEventDisableTooExpensive.java
well, since I usually group them in a feature class and usually name them according to what Im trying to achieve with the method, you already have the event name as a parameter, so you already know that part and no need to include it in the method name imo
I just do BlaListener for example
Don't call your listeners events, as they aren't events
And they don't need to be too long, it's nice having a quick overview of the name of a class and what it could be doing, but people can always look into the class
i group them based on their type, such as WorldEvents, EntityEvents, InventoryEvents, PlayerEvents, etc
i probs should rename them from Events to Listeners
tho i just use a single event listener method for each type and then will transfer to another method somewhere else if it fits a certain criteria
That's fine too imo, just don't call them events
I have an issue, I have a for loop that gets nearby entities by 12 blocks from the damager, checks if they are instanceof player then checks if those entities health is below 12D
I then add those players to a list, when I check the size it only returns 1, anyone got any idea why its not returning the amount of players it should have in the list?
provide code
post to like paste.helpch.at
I'm trying out kotlin in my build scripts. What's the difference between these two? Only the former one seems to work
plugins {
`kotlin-dsl`
}
plugins {
id("kotlin-dsl")
}
it needs to be escaped with ` because it contains an illegal character (dash).
id() should also work I think, hmm
first one is shorter - I don't think theres any difference (also kotlin-dsl is only if you're making a gradle plugin iirc)
yeah I need it so that gradle recognizes my custom scripts in buildSrc/src/main/kotlin as plugins - however using the id("...") format, it throws some very unspecific error that I don't recall anymore - I have just used the `syntax` now
oh, I've never used the custom scripts before so idk
the gradle docs say that using subprojects {} or allprojects{} should be avoided so that's why I moved my stuff into buildSrc lol
yeah
ah ok so with id(...) I have to provide the full id but without, I can use the "abbreviated name"?
it's only for some core plugins, obviously it isn't going to know about every single plugin in the plugin repo lol
that's funny because in groovy I was able to just do id('groovy-gradle-plugin')
and I assumed the kotlin-dsl would be a core plugin ๐
mm well it kind of is but, yeah
I find groovy to be so much easier ๐ฅฒ
k๐คกtlin
i still don't really get the technical difference between pluginname and id("f.q.d.n.pluginname") version("version") - apparently using id requires to give the fully qualified name including the version for all non-core plugins while `pluginname` does not require fully qualified name neither version, even for not-core plugins - interesting 
pluginname is a variable
or more specifically, a property
yeah I just checked and it seems to be a "field" or however it's called in kotlin
interesting
ex here it returns id(...) anyways
the get() is why getters and setters don't have to be explicitely defined by default ๐คฉ
(in kotlin)
It's just a type safe shortcut so you don't have to type ids all the time
btw is it normal that when I create a new project in IJ -> Gradle -> Kotlin/Kotlin -> JDK 17, that it uses jvmToolchain(8) even though I specifically set it to 17?
shouldn't that be set to 17 ๐
but thats ass to set up for kotlin
?
it asks you what language you want the project to be in
I made my own project generator ๐
its a nice project idea
if you need a project idea
oh fr cool?
never saw that tbh
why did it not ask you whether to use subprojects?
oh I didnt see it because it didn't show the 1: 2: as separate lines
for me it looks different
Split functionality across multiple subprojects?:
1: no - only one application project
2: yes - application and library projects
Enter selection (default: no - only one application project) [1..2] 2
huh what gradle version?
7.5.1
mm yeah i guess they changed it for gradle 8
fair enough, it's a yes/no question
no need to split that up into 1 and 2 lol
I'm still surprised that gradle init doesn't specify any jdk version in the generated project
oh! now I also understand why the kotlin-dsl plugin requires `this-notation` - it's because the "field" has a hyphen in the name, that's why "java" works without backticks but kotlin-dsl doesn't
I did choose application -> with subprojects and jdk is defined nowhere
and it doesn't really do anything for a basic project, it's a very basic layout
well it definitely was defined when i ran it

well it was without subprojects, just ./app/build.gradle.kts
hm mine only has this
plugins {
id("kttestgradleinit.kotlin-application-conventions")
}
dependencies {
implementation("org.apache.commons:commons-text")
implementation(project(":utilities"))
}
application {
// Define the main class for the application.
mainClass.set("kttestgradleinit.app.AppKt")
}
yeah well anyway ๐ I learnt a lot again today, thanks
things slowly start to make sense to me

I'm currently writing a tiny PAPI extension to properly replace %formatter_text_replace% with a properly working replacer lol.
I currently got the following format which works 100% fine:
%replacer_"<search>"_"<replacement>"_text in which to search and replace%
As you see, both <search> and <replacement> must be put into quotes, so that the search and replace string can both contain underscores just fine. It also works with "quotes" being included in the search and replacement string by simply escaping them like usual:
%replace_"\"jeff\""_"\"alex\""_my name is "jeff"%
I'm using this relatively easy regex:
private static final Pattern PATTERN_BOTH_QUOTED =
Pattern.compile("^\"(?<search>([^\"]|\\\\\")+)\"_\"(?<replace>([^\"]|\\\\\")+)\"_(?<text>.*)$");
Outside of java it looks like this: ^"(?<search>([^"]|\\")+)"_"(?<replace>([^"]|\\")+)"_(?<text>.*)$
Now I'm thinking of making the " quotes optional if search or replace doesn't contain any underscores, however I'm unsure how I'd do that using just one regex - ofc I could just use 4 different patterns (current one for both search and replace quoted, one for only search quoted, one for only replacement quoted, and none quoted) but that seems a bit unperformant I guess. Anyone got any idea? Maybe I could add another named group (?<searchWithoutQuotes>(...)) and same for replace, and then combine them with the existing quoted named groups using (|) ?
Ha! I got the discord formatting working
I have a library called MDLib that shade CommandAPI, and I have a plugin that shading the MDLib library, for some reason the CommandAPI got doubled and it cause some issues, as you can see on the image it has dev.jorel.commandapi package and I have com.muhammaddaffa.rpgclass.mdlib.commandapi package, that shouldn't happen right?
Can someone help me solve this issue?
This is my pom.xml for RPGClass https://paste.helpch.at/qotivogapi.xml
seems like your MDLib contains a package called "dev.jorel.commandapi" but you only relocate "com.muhammaddaffa.mdlib" ?
there's different options
- commandapi should only be a transitive dependency in MDLib
or - MDLib should relocate commandAPI into its own package
I have relocated the "dev.jorel.commandapi" inside the MDLib, does that do anything?
This is pom.xml for MDLib https://paste.helpch.at/boneweresu.xml
hm that looks correct. Run mvn clean install on your mdlib, and then mvn clean package on your RPG thing
Still the same.
Maybe I need to invalidate cache or something.
Something is messed up. I also dont see the configupdater package in your plugin
I think the issue is that you set createDependencyReduced to false in MDLib
That way maven doesnโt know MDLib got it shaded already
Dont forget to โmvn cleanโ on both projects again
Iโm pretty sure thats it :p this is exactly tjhe purpose of the reduced pom
In short, this is quite useful if you intend to use that shaded JAR (instead of the normal JAR) as a dependency for another module. That dependency-reduced-pom.xml will not contain the JARs already present in the shaded one, avoiding useless duplication.
I never understood why people always disable the dependency-reduced-pom ยฏ_(ใ)_/ยฏ
I use the Minecraft IntelliJ Plugin to create project and that's the default.
But thank you for the help!
Disabling it has no advantage, only downsides
Np!
Will keep that in mind.
I am implementing a player tracking feature. It's 1:1 so every player is at most tracking exactly one player at any given time.
So I need to look up players in a map every couple ticks.
Should I use Map<Player, Player> for this purpose or is it more efficient to use e.g. Map<UUID, UUID>?
use UUIDs
uuids always*
i think saying always is harsh but yeah if you're ever even slightly unsure then just use uuids
thats why you put a vague asterisk and then refuse to elaborate
๐ฑ
Is there a situation where you would use Player as a key?
i cant really think of one where it's better
maybe for the sake of performance
i dont think theres any noticeable difference
but only at the point where're you're concerned about converting players to uuids or vice versa
so probably never
First few tutorials I clicked on all put the entire player in the map ๐
That would mean that I need to do player.getUniqueId() and Bukkit.getPlayer(uuid) whenever I look up a player pair in the map tho.
But that's still faster than using a <Player, Player> map?
unless you specifically wanted it to be tied to the player object, so WeakHashMap. but there arent many situations where that's useful
it's not all about performance
also spigot tutorials are almost always awful
not faster but safer
Safer in what way? Less prone to errors or are we actually talking about security?
I wonder, do Player objects become null when the players leave? Or does anything happen at all
memory leaks
you don't have to worry about the Player lifecycle for when they disconnect from the server, etc
UUIDs are forever ๐ซก
no, thats the point. theres no way of turning a reference into null everywhere, so any hard reference to a player will prevent GC
this isnt c++
Ah true
But you could always just clear it yourself during PlayerLeave or later, no?
you could, but you might forget. it's more maintenance
using Player as a key also relies on equals/hashCode behaviour that is effectively undefined. in practice it'll probably be fine, but you never know.
It's like how trying to serialise a Location with gson stack overflows because it contains a reference to World, whose implementation contains a reference to more locations
so UUID also makes serialisation easier
no need for a custom type adapter
yeah so instead of leaking the player you only leak the entry in the map ๐
hell yeah
yeah no, you should still be manually cleaning up when it makes sense. but leaking player objects might lead to some weird states where you have 2 distinct player objects representing the same player
i dont actually know
im pretty sure thats not possible
even if it is i dont see the issue
why wouldnt it be possible?
spigot is too robust and battle tested to be subject to silly bugs
it's basically the perfect software
linus torvalds could learn a thing or two
ha
players get removed from the internal cache when they disconnect. as far as i can tell theres nothing preventing a new ServerPlayer getting created, which in turn creates a new CraftPlayer
so theres an internal cache?
meaning they get reused?
or?
im not talking about when they leave btw
i have to imagine that the same Player object is returned after multiple calls to getPlayerById(id)
so yeah they are reused in that sense
yes
PlayerList
something.nms.something.PlayerList to be precise
so. let's say you keep a hard reference to a Player after they dc. internally it makes a new CraftPlayer so suddenly you have 2 CraftPlayers
it might not be an issue but i reckon it'll subtly break something
i thought u were talking abt even when they dont leave cuz that was right after u "you should still be cleaning up when it makes sense"
in theory nothing should go wrong as long as the player doesnt leave
bm saying that you should still clean up is just a more general advice
i think
Yes
Can someone help me rewrite this to work in kotlin? Lol
processResources {
def props = [version: version]
inputs.properties props
filteringCharset 'UTF-8'
filesMatching('plugin.yml') {
expand props
}
}
It was generated by the minecraft plugin in IDEA
I recommend using the minecrell plugin to just generate the plugin.yml
Havn't heard of that before, is in a plugin in IntelliJ?
nope, gradle plugin
Wow it needs a lot of configuration lol
no, not really
thats everything you can do
id("net.minecrell.plugin-yml.bukkit") version "0.6.0"
bukkit (or paper) {
main = "com.example.testplugin.TestPlugin"
apiVersion = "1.13"
author = "Skyslycer"
}
thats all you need
ye
Was about to write it lol
shouldn't this do? ```kt
tasks.processResources {
filteringCharset = "UTF-8"
filesMatching("plugin.yml") {
expand(mapOf("version" to project.version))
}
}
Thank you, can I ask why you recommend using this instead of plain old plugin.yml?
yeah that should work too
well, its easier to have everything in one file, its strongly typed which isnt prone to plugin yml errors and i find it cleaner
Difference between tasks.processResources and tasks.withType<ProcessResources>? It gives a warning with the 2nd example
Gotcha, ty
statically typed* ๐ค
could also just apply a json schema to plugin.yml
umm akshualle ^
so, i still like it better
just my opinion tho
(also i want yml to die)
thats fair
tasks.withType<...> gets it "dynamically" by its type while tasks.processResources gets it from the public val org.gradle.api.tasks.TaskContainer.processResources
HOCON ftw
Gotcha, kinda lol, thanks
you mean ```kt
tasks {
processResources {
...
yep
Yeah I just have it in tasks usually
yep
i believe thats for paper
if you use paper plugins (instead of bukkit) it has to be 1.19 or higher since paper plugins didnt exist back then
for paper plugins you need this too:
bootstrapper = "com.example.testplugin.bootstrap.TestPluginBootstrap"
loader = "com.example.testplugin.loader.TestPluginLoader"
hasOpenClassloader = false```
yes
bukkit is your regular plugin.yml
paper is paper-plugin.yml
also api version 1.12 doesnt exist
you have to use 1.13
Shouldn't this still work?
or just put nothing
itll use the legacy names then which also sucks
thats the preferable option for legacy plugins
i mean...
if theyre writing a 1.12 plugin
you dont have a choice
you can still put 1.13
i dont think thats true
i dont think it'll do the material conversions if you put 1.13
if you actually use 1.12 api you shouldn't set any api-version because you'll wanna have the legacy material support enabled
^
hm alriight
But uhhh?
you forgot the close bracket
(unless you don't use any materials, e.g. a chat plugin could use 1.13 api version to avoid the huge material enum conversion thingy)
eh, isn't like api-version will do anything on pre 1.13
No, it's there, just not in the screenshot
What is that ?
did you reload gradle?
Yes
on pre 1.13 it won't do anything. But someone would run the plugin on 1.13+ and then having the api-version set will break your Material references (unless you have NOT specified an API-version, in that case bukkit injects the legacy material names into your classloader's material class)
oh yes i remember
very dirty black magic
ye
it'll be fun when all the Keyed enums will be gone
I don't understand your concern
@atomic trail you probably used the paper plugin
This plugin will only be used for a 1.12.2 server btw
spigot still enables legacy support if a single plugin doesn't have api-version defined
use id("net.minecrell.plugin-yml.bukkit") version "0.6.0"
yes but you want YOUR plugin's classloader to get the legacy material enum
not just some other plugin
Ohhh yeah ofc... lol
why do you want that?
xD
because otherwise no worky
because you (or the person we're talking about) is coding using the 1.12 API
so they will expect Material.GRASS to be a grass block and not the "normal grass"
yes
and hence they wanna have legacy material support enabled = no api version set
yeah whatever
ofc I'd just suggest to stupi using 1.12 API ยฏ_(ใ)_/ยฏ
Sooo I set no api version? Lmao
if you use 1.12 API, you set no api-version
Alright
I'd like to upload an extension to the papi ecloud but registration is currently locked, and it says to ask on discord to get an account - where exactly shall I ask? here? ๐
i'd like to add this extension https://github.com/mfnalex/PAPI-Replace
@robust crow that should sort it
thx
hell respond once he can :D
Shouldn't the .gradle/ directory be in .gitignore?
it doesnt need to be a plugin if you want to publish it to the ecloud
I know, it's just a plugin right now because I can't upload it to the ecloud without an account
and I can't register an account myself because it's closed
Yeah, because of the wrapper mainly I assume?
Yes, at least the properties file should be there
The .jar doesnt have to but also doesnt hurt
Yeye I'll just keep it there
I always upload the whole gradle dir
so? You can place the jar on the expansions folder and it will be loaded by papi
it does hurt, cuz there's no jar to run
(I have made that mistake before)
oh I didn't know that. Does it not require some .yml file or anything to tell PAPI which class to load exactly? because I couldn't find anything about that in the docs
no
nice
They already extend PlaceholderExpansion so it's pretty easy to find the right class without any yml


