#[MEGA THREAD] Get Your Code Reviewed or Review Others
1 messages · Page 10 of 1
yeah makes sense
my goal here is just to get used to multi module projects
and redis is pretty easy to implement so
so you optimistically send a message that setting a home succeeded and in the case of a db error, you send the error message after you just said it succeeded? \👀
just a design decision, i believe i also send the message after the db call cuz i assume a local db which is fairly fast
No. You use a CompletableFuture like a normal person lol
this is why i love clouds async commands
kinda odd to the end user that - in the case of a very slow db - the confirmation message only appears a few seconds later
just imagine
just block the main thread 
If you have a very slow DB, you have other problems to concern yourself with
facts
is 1s considered slow
if it doesnt include a network call yes
it includes a network call
atleast in minecraft land id say
Even with a network call, that's still relatively slow
need to start moving to selfhosted dbs then
Ideally a database call takes no more than like 200ms
i mean i have a selfhosted supabase instance running i'm just not using it
tbf it's using postgrest
I mean doesn’t really make sense to me why they would seeing as there is no brain behind them
It just seems kind of goofy
blah blah ancient code blah blah
its probably harder to have them not tick then to have tehm tick a little bit
Idk y2 said theres 2 ifs behind the ticking
exactly
So then it sounds quite easy to make them not tick lol
gonna get banned for sending mojmapped code
no
they tick
but its only doing some ifs inside the tick
so its comparitvely like nothing compared to other entities ig
this is Display#tick
Right which again, means it'd be quite easy to make them not tick?
I mean what is the point of them ticking anyway
to stop riding eachother apparantly
hmm
I guess it makes sense for some entity methods such as passenger ones for example
Beyond that I can't really think of a reason
ya know
I thought that was his code and didn't even bother to look cuz I assumed it was kotlin
guess I should read the message kek
Is this bad practice?
public boolean homeExists(UUID uuid, String name) {
for (Home h : getHomesMap(uuid)) {
return h.getName().contains(name);
}
return false;
}```
Why .contains and does getHomesMap return a map?
The homes are stored into a map with a home record with the name and location.
What does the method getHomesMap return?
Also you should not be using String#contains
A set
public HashSet<Home> getHomesMap(UUID uuid) {
return homesMap.get(uuid);
}
which that gets the map with the uuid
private final HashMap<UUID, HashSet<Home>> homesMap = new HashMap<>();```
The name should be getHomes() i guess but i have that already returning a configurationSection
Did i go about this wrong?
also why shouldnt i use String#contains on this?
Any reason why it's a set and not something like a Map<String, HomeData>?
It's already in the playerData. I thought it would be kinda redundant to make another manager
well, it's unconventional because redis isn't ACID unlike traditional databases (mongo, postgres, etc...), so it's unsafe to use it as a persistent storage
dont make another manager, make a Map<string, home> in the playerdata
I mean it has partial ACID compliance, but even so u can deal with it using replication, sharding, 2phase commits and multiver conc control
ofc redis is still often considered unideal for persistent storage, but yea just saying ^^
(there's also other cool transaction models like BASE or CAP, one more I forgot the name of)
Whats wrong with the way im doing it though?
Also that doesn't store multiple homes
it does?
nested manager within the PlayerData doesn't make sense
Map<String, Home> Would cover anything you need
Why would it be <string, home>?
Home name home data
So <UUID, New HashMap<String, Home>>
is each player supposed to have a bunch of homes
indexed by some String id
or UUID or something
Yes, A player can have multiple homes. storing it in per uuid ymls.
a player's data should hold your homes then for that player
PlayerManagwr is okay
They're saying sont add another manager
Just have your PlayerData object
This is within the PlayerData
Why do you need UUID hashmap inside PlayedData
When i tried without it for some reason when i set a new home the other players home changed aswell
then you have a bug
Sounds like a saving issue
and you need to figure out why
^
It's because i put the map in PlayerDataManager instead of PlayerData🤦♂️
I dont think i tell you guys enough, Thank you for the help ❤️
Updated code java public boolean homeExists(UUID uuid, String name) { return getHomes(uuid).containsKey(name); }
use this more
this is for the weak
correct
why use this more?
its to qualify between static method calls and instance method calls
I usually do it the other way around and call static stuff with the class prefixed
since my majority is not that
which also means it still works if I move my code out of the class for any reason
I use this becuase I like the look of it
get yourself a better theme
I am infatuated with random strings of text
I have gone truly insane 💀
hell I'd hug ok
because it looks so huggable
what the fuck
EXACTLY
I also use it to differentiate fields from variables inside deeper scopes (like methods)
fields always have this in my code
I mean the concept extends to fields ofc
but yea sometimes its even mandatory when inner variables shadow outer variables
Also @covert marsh can u check the staff channel? I need ur opinion on it
Should my service handle CompletableFutures, or should I give that responsibility to another class?
CFs can be good api
so maybe
esp if u dont bother to implement ur own futures etc w/e
I meant should my service return CompletableFutures for the consumer to be used
Or should I wrap my service and make the wrapper return CompletableFutures
What do yall think about string interfaces?
public interface messages {
//Homes
String HOME_SET = "&7Home: &a%s &7set to your location!";
String HOME_MODIFIED = "&7Home: &a%s &7modified to your location!";
String INVALID_HOME = "&cThat home is invalid!";
String NO_HOMES = "&cYou don't have any homes set!";
String HOME_LIMIT = "&cYour home limit has been used!";
String TELEPORT_HOME = "&7Welcome to home: &a%s";
String HOME_DELETED = "&7Home: &a%s &7was deleted successfully!";
}```
Even better for maximum agony: Make the messages depend on the player's locale
might be even more annoying, then that player needs to find a way to change it
Well, you'll usually not have a player play with non-english minecraft while still insisting that plugins be english
What if I just want my plugin to have all its messages in differing languages
i forgor
Plus you kinda need an excuse as to why your server is collecting personal data
ooo selling player data?
this is not to farm and sell to the Chinese I swear
Gotta maximise profits somehow, you know
Encrypted logs? Psh nah those go straight to china
now you somehow gotta comply with gdpr bonk
No one has to know
https://docs.papermc.io/paper/dev/component-api/i18n paper has this
If I work with the CCP I will get a safe place in china during ww3
And that's why we all should sell data to china!
Idk that id call china safe in a ww3 scenario
Yeah, I18N is best done in conjunction with adventure
But it's not required
well, they are very important for the worlds economy and whatever
That’s why we steal their kids and leave the rest to rot
I mean there’s something called humble object principle that just says it’s generally a good idea to separate logic itself from asynchronous and concurrent code, but that is not always possible, there’s also a design pattern to return an async interface and a sync interface (idr the name of it), however remember the sync implementation may still need to be synchronized
Now im trying to think of a good way to do lang files -.-
make a new package/class named files/LangFiles and make it instanced.. then a whole lot of getters
Yeah, I first saw this when I was inspecting the LuckPerms codebase, here's what I have now:
public interface PunishmentService {
void init() throws DatabaseException;
void shutdown() throws DatabaseException;
@NotNull PlayerPunishmentHistory getPlayerHistory(@NotNull UUID target) throws DatabaseException;
@NotNull PlayerMutePunishmentHistory getPlayerMuteHistory(@NotNull UUID target) throws DatabaseException;
@NotNull Saved<PlayerMutePunishment> savePlayerMute(@NotNull PlayerMutePunishment mute) throws DatabaseException;
void savePlayerMute(@NotNull Saved<PlayerMutePunishment> savedMute) throws DatabaseException;
}
public final class AsyncPunishmentService {
private final PunishmentService service;
private final ExecutorService executor;
public AsyncPunishmentService(PunishmentService service) {
Preconditions.checkArgument(service != null, "service");
this.service = service;
this.executor = Executors.newVirtualThreadPerTaskExecutor();
}
public void init() {
this.service.init();
}
public void shutdown() {
this.executor.shutdown();
this.service.shutdown();
}
public CompletableFuture<PlayerPunishmentHistory> getPlayerHistory(@NotNull UUID target) {
return CompletableFuture.supplyAsync(() -> this.service.getPlayerHistory(target), this.executor);
}
public CompletableFuture<PlayerMutePunishmentHistory> getPlayerMuteHistory(@NotNull UUID target) {
return CompletableFuture.supplyAsync(() -> this.service.getPlayerMuteHistory(target), this.executor);
}
public CompletableFuture<Saved<PlayerMutePunishment>> savePlayerMute(@NotNull PlayerMutePunishment mute) {
return CompletableFuture.supplyAsync(() -> this.service.savePlayerMute(mute), this.executor);
}
public CompletableFuture<Void> savePlayerMute(@NotNull Saved<PlayerMutePunishment> savedMute) {
return CompletableFuture.runAsync(() -> this.service.savePlayerMute(savedMute), this.executor);
}
}
this assumes PunishmentService impl is thread safe
Yes it will be
Is there any bad practice in this code especially for performance? Thanks in advance
I wonder if your run method could be converted into a removeIf
https://github.com/NukeCaps/NormalSkyblock
Throwing myself into the gauntlet here, most of the implementation is in NormalSkyblock under impl (obviously), uh I mean theres a lot so I suppose go over whatever you guys feel like ❤️
would also like to point out at that I'm still figuring out my design as I go lol, some things might be in a questionable place
I just created new modules and that was what was produced 🤷 , is it wrong?
I was thinking that too, wasnt sure if they needed to be implemented or not or whatever, it's like it created a plugin within NormalSkyblock
do you really need a seperate class for the visitor log?
Hmm, I could probably remove the player on disconnect but then I still need to have the task to fire some code 2 ticks after the switch item event because the attributeinstance isn't updated yet with the correct item in their hand.
Edit: fixed it by predicting the future so I completely removed the runnable thanks
Teach me how to predict the future
3
SRP principal
Also some advice on staying motivated for a project this large would be incredibly helpful
Break things up into smaller chunks. Don't see it as "I want to make a skyblock plugin", try and see it as "I want to make a skyblock-style island generator", "I want to make a /spawn and /island command", "I want to make a simple invite system"
If your final goal is "skyblock plugin", that finish line is going to seem farther away for longer. If you move the goal posts to be closer and achieving smaller tasks, you'll feel more accomplished as you finish each little feature.
I did this for a mod I was doing. Piece by piece, I wanted to tackle the project as smaller tasks and was really happy when I saw it working. Then I was like "Oh I can't wait to move on and do this with it!"
That is very good advice thank you choco!
Also apparently it seems I also have no idea how to setup a multi module maven project so some tips there would help out if anyone would be so kind
this is how ive been doing
private static LangHandler instance;
private final FileHandler fileHandler;
private final String no_homes;
private final String invalid_home;
private final String home_set;
private final String modified_home;
private final String teleport_home;
private final String home_deleted;
private final String home_limit;
private LangHandler() {
instance = this;
this.fileHandler = new FileHandler("", "lang.yml");
this.no_homes = this.fileHandler.getConfig().getString("NO_HOMES");
this.invalid_home = this.fileHandler.getConfig().getString("INVALID_HOME");
this.home_set = this.fileHandler.getConfig().getString("HOME_SET");
this.modified_home = this.fileHandler.getConfig().getString("HOME_MODIFIED");
this.teleport_home = this.fileHandler.getConfig().getString("TELEPORT_HOME");
this.home_deleted = this.fileHandler.getConfig().getString("DELETED_HOME");
this.home_limit = this.fileHandler.getConfig().getString("HOME_LIMIT");
}
public void create() {
if (!fileHandler.getFile().exists()) {
Core.getInstance().saveResource("lang.yml", false);
}
}
public String getNoHomes() {
return no_homes;
}
public String getInvalidHome() {
return invalid_home;
}
public String getHomeSet() {
return home_set;
}
public String getModifiedHome() {
return modified_home;
}
public String getTeleportHome() {
return teleport_home;
}
public String getHomeDeleted() {
return home_deleted;
}
public String getHomeLimit() {
return home_limit;
}
public static LangHandler getInstance() {
return new LangHandler();
}
}
Is this a good way to go about a lang file?
i think you are better off using a library to handle localizations
and then creating some class to store all your message constants you can then use because you are going to have to make a ton of messages
and i dont think you want one class with like 500 getters in it
do you have a suggestion on a lib?
or recommendation would be a better word to use here
If I'm going to be honest with you, I think adventure is great
they have a very good localization system api
but that'd require you to of course use their components and stuff (which i do strongly recommend)
https://docs.papermc.io/paper/dev/component-api/i18n they have this
i am not sure if that is paper specific tho
I dont think so
I was just looking into this lol
you would have to use the bukkit platform module too tho if you want to support spigot
this what you were talking about?
Yes
I'll have to give this a try, I've never done this stuff before
I've always just hard coded most messages
I use a properties file to store my locale messages which are written in minimessage
i define a custom <arg> tag to substitute arguments
Set the arena's first corner to (<red><arg:0></red>, <green><arg:1></green>, <blue><arg:2></blue>)</gold>
Then I have my own custom minimessage translator here https://github.com/PulseBeat02/MurderRun/blob/main/src/main/java/io/github/pulsebeat02/murderrun/locale/minimessage/MiniMessageTranslator.java and it reads it into a Component
(ignore the checkIfSpecialString method cuz thats for smthing different)
Using that, I store all messages in components here https://github.com/PulseBeat02/MurderRun/blob/main/src/main/java/io/github/pulsebeat02/murderrun/locale/Message.java where I can get them from my classes
it includes the properties key and then i can just call component.build(args...)
You don't have to use a properties file btw, you could use json, yaml or anything cause the translator method just accepts a key and you try to read it from your locale file
Whats better to use though? do you have to reload/restart the server on all of them?
I know txt files you dont. but if im just updating a simple message no need to restart you know?
and probably not do anything with lores
No need to restart it just reads from the Locale
if you just need like a single message then use properties
%s 
I've been using the one from the minimessage locale pr
cause its not in adventure yet
they are gonna add it soon
Kk yeah
You would use json for lores cause multiple lines and stuff
i use properties for lores cuz i have text wrapping but you should avoid it
Minimessage has newline support iirc
it's weird tho like i dont think it carries color components to the next line
newline dont work on lores
It's iffy in chat, but may work for item lore with plugins
A little split("\n") never hurt nobody
You can’t split a component like that silly
i think the main issue is that the lore would accept a component[] for the lines, but the properties file would only give you a singular component to work with even if you used \n
maybe the new lines would work if it was the single element in an array, but idk
https://github.com/NukeCaps/NormalSkyblock
Back again (made a new repo for this project), I believe I have correctly setup the modules this time let me know if you guys find anything questionable or any tips or anything of the sort
I'm not a fan of limiting "stats" to a hardcoded set of values
Experience, score etc should all be reworked into a generic "Statistic" that basically acts as a fancy named number formatter
Same with settings. In most cases they're just a fancy boolean wrapper. I remember writing a fully-generic settings system with fancy codecs
Your Settings class not being specific to a player is concerning. If you want server-wide settings consider making feature flags
how'd that work?
It converts every statistic to a common format (double in my case) and that's how it's tracked internally
It's just a very fancy converter between Double <-> T extends Number
and cached as a Map<String, Double>
isn't that basically what he's doing? aside from not using doubles
The idea isn't to just have a bunch of getKills getWhatever getThis getThat
But instead a getValue(Statistic<T>), modify, update
oh
We use kotlin at work so we end up having access to fancier methods
like player.updateStatistic
so you'd just have an empty class for each statistic?
You have like 5 or 6 statistic classes
DoubleStatistic, IntStatistic
And a class / object or whatever that just holds them
Which I usually call BuiltinStatistics
it's very much a static registry
(ignore the very inconsistent code this is old)
oh so you'd just have an extension fn on player that takes Statistic<T> and T to update it?
Pretty much
why have 6 statistic clases instead of just new Statistic<Long> or Integer
The class impl is responsible for the casting and formatting
TimeStatistic uses Longs but renders it in a time-like format
o
what does that mean btw
(not me using this post as my own btw 😭)
In short there's a settings class that's just a Map<String, Object>
It doesn't seem to be attached to a player so I'll assume it's server-wide. My point will still stand under both scenarios
There are 2 paths this can go:
- Settings are loaded on startup: Make it an immutable map, nuke any set methods
- Settings are updated on runtime: Either attach them to a player or use feature flags
The idea of feature flags is that you have a hardcoded set of flags that you can modify on runtime
They basically act as "mutable constants" in the sense where they're never updated in production unless something catastrophic occurs
The benefit they bring is that you can update behavior with no downtime
Now, you can be minimalistic with it, or you can go all out and have them synchronized to some server / use a third-party service that does it
At work I've been introducing this philosophy of "no hardcoded variables, flag everything" just in case something goes wrong and we need to tweak spawn rates / weapon damage / anything tbh, and not only does it make playtesting a breeze because we can tweak numbers in real time, but it also makes development a bit less cluttered
but what are feature flags in the first place?
fancy T wrappers with a name
oh I get it
it's similar to the statistic thing
but then, how do you modify them at runtime?
They're mutable
they're mutable so you'd just have a set / get method?
Yep
ah alr ty
You modify them with some fancy command and spam get on them
and they're constants in the sense that they're predefined
List as a registry for that juicy O(n) retrieval. Without having random access to the List (Which is the only purpose for a List)
shut up nerd

would he use a set instead?
or?
I get that it should be a map because O(1) which is actually O(N / bucketSize) or whatever
A Set would be just as bad. Even worse since the iteration on HashSets is slightly slower than those of ArrayLists since you have to concatenate the hash buckets for iteration.
a Set is just a HashMap but every value is constant
There'd be no point given we want K-V lookup
oh
Thank you for the feedback illusion, I just woke up so I’m not in a place to respond intelligently lol so I’ll come back later with some more questions probably
Do you think the same applies to settings by the way? I was just trying to boil down these really common things as to make them easier to reuse
Wait I am just dumb and waking up you were literally talking about settings, I told you I wouldn’t be intelligent yet kek
Dont use stream.findfirst, use iterator.next
singletons vs passing state
Fair, also these sorta things are subject to change as I'll be implementing (at least for invites) /invite accept (some param to define a specific invite)
Though it works in a couple of my systems for sure, could still be better
Also I assume stream methods are a lot slower than iterators?
Was this a question btw?
yes
Passing class instances for example through di is a more modular approach, it also helps when trying isolate some state in a more effective way. Singletons I suppose you could say is a form of global state management which a lot will argue is static abuse, though most cases you're probably only going to have a single instance of this class anyway, I feel it's still a valid approach depending on your design. In the case of spigot plugins however, it's perfectly acceptable for your main class to be a singleton considering Bukkit only instantiates the main once.
Someone could probably explain this better than I though
I personally use di more however considering it helps me keep organized and what I feel to be cleaner code. I also feel like it helps with tracking down issues and their sources which is again incredibly helpful (especially for someone who's disorganized like I am)
All in all, in the context of spigot, your main class is something a lot will argue should just be passed in the sense of di though if it's a singleton that's perfectly fine as I mentioned above. It more so relies on how you feel your system should work and what you've already got implemented.
@willow bone sorry that took me a while lol
Not for a spigot plugin, in general
I'd argue that di is better but I'm probably biased simply because I'm not organized
It helps imo
Item builder?
Oh actually you're right I forgot air has no meta right?
Also I just think an immutable item stack is better
https://paste.md-5.net/avigutehon.java
I feel like this may be something to do down the line, but as it stands in the current impl my plan was to have different implementations of settings per things like Player, Island, Rpg stuff, etc, though I feel like feature flags is something a bit more complex. That being said I'm really just trying to get a foundation of which some aspect is playable before making optimizations
Hey, so I want to create an enum for my ability keys so I can't make typos when applying them to items, but I also need to make sure every enum constant has an registered ability and every registered ability has an enum constant. The problem is I can't just do everything in the enum because most AbstractAbilities need other classes as parameters.
I came up with these two solutions, I'm not sure if they are SOLID or if I will regret one (or both) of them in the future. Feedback is appreciated.
A: lazy initialization or something like that:
https://pastes.dev/jgC5Ay96p0
B: Requiring every AbstractAbility to take an enum constant as parameter and then checking if every enum constant has an registered ability: https://pastes.dev/vFYaUYGQql
The way I usually do it is with a factory pattern
Map<AbilityType, AbilityProvider> where AbilityProvider creates an Ability instance with whatever params you need
But overall method B seems to work better
Alright thank you 🙏
Would the Enum Interface trick work for you?
enum Example implements Interface {
}
Then for each enum constant, you have to implement the methods of the Interface
https://github.com/TheNewEconomy/TheNewItemLibrary/tree/feat/cleanup mainly looking for feedback on the recode(feat/cleanup branch) of my internal Item Library I use for plugins. Pretty much just lets me serialize/deserialize ItemStacks for JSON across multiple platforms(Paper/Spigot/Sponge/Fabric soon), and build item stacks using a builder pattern without worrying about the platform-specific stuff so write the build once and use it for any of the supported platforms. The rewrite mainly was to clean it up and allow for additions without needing to include them into the project itself with the goal being to do something like ItemPlatform.addCheck(new PersistentCheck()) in my plugins. Please note: not completed in the current state, but fairly useable for the bukkit/paper part.
Example usage just to get an idea(from the old code base, but will be similar to the new) provides an itemstack for any of the platforms without changing the code itself
PluginCore.server().stackBuilder().of(denomination.getMaterial(), amount)
.enchant(denomination.getEnchantments())
.lore(denomination.getLore())
.flags(denomination.getFlags())
.damage(denomination.getDamage())
.display(MiniMessage.miniMessage().deserialize(denomination.getName()))
.modelData(denomination.getCustomModel());
what do you need those since comments for, git exists
for stuff like the spigot api it's very useful tbh, there's also the 1.8 people who want support lmao
and it's inconvenient to check the git for when the things got added
It lets developers know that they should only expect that method to exist at that version
Especially when dealing with something such as ItemMeta that is volatile(see how they changed pattern type between interface/class)
Not really needed when dealing with sponge since the item data is stored with keys, but for spigot it's a great indicator on the Javadocs without having to read through Github commits.
"Hey I made this documentation you can use without digging through everything, but you should dig through everything anyways because you may not have access to a method on a certain version"
Yeah @since is one of the hallmarks of good API design
I wouldn't go that far xD
Good APIs are APIs that can last.
If the API changes all the time to the point that @since is not useful, you got a serious issue with API maintenance
true
mostly why I overhauled it to support components which seems to be where Mojang is taking all meta data
@since in itself is not /that/ important, but the implications of it are.
heck, the food component is already outdated because mojang change its usage in the snapshots
I think im getting better at this... i mean this was first try and compiled. worked no errors
There will be a reward system but i wanna see if im doing this better
Problem with the currenct structure is that you're going to end up with a lot of duplicate checks
I like to structure my quest systems around a "Quest" that's broken into "Metadata" (name, description etc), "Objectives" and "Rewards"
Might add requirements if you're really fancy
An objective has an ID and type, but also tracks per-player progress
And rewards can be commands, items etc
A MetaData? What does this mean?
What do you mean by a lot of dupe checks?
?paste
what could i improve + tips: https://paste.md-5.net/nasovezaqa.java
Meta data is what makes something unqiue such as the meta data for an item could be the name, the count, the lore, ect
To me this all seems really redundent
private Ability1Handler(JavaPlugin plugin) {
this.plugin = plugin;
this.wardensAPI = WardenSMP.getInstance().getWardensAPI();
}
public static void initialize(JavaPlugin plugin) {
if (instance == null) {
instance = new Ability1Handler(plugin);
}
}
public static Ability1Handler getInstance() {
if (instance == null) {
throw new IllegalStateException("Ability1Handler not initialized");
}
return instance;
}```
But i'm still new to programming
public void start(Player p) {
}```
Pass UUID instead of player
This can cause memory leaks
passing Player itself can't cause memory leaks
but storing it past the time where the player does, indeed causes memory leaks
Regardless if you use a UUID or a player it'll still leak
But if you use a UUID you contain the leak and it kinda fixes itself if the player ends up rejoining
Is it fine to abstract an unit test so I can test multiple implementations of an interface without a lot of duplicate code?
I have a service interface, and its implementations all use different technologies, so to test it, I want to know if I should make an abstract unit test, then in a concrete unit test I can test the service implementation
whatever is easier for you
tests are for you anyways as long as they cover what you need to be covered I see no harm
just provide a parameterized test for all four impls
so like this:
Player p = Bukkit.getPlayer(playerUUID);
PlayerData pd = wardensAPI.getPlayerData(p);
List<String> ability = pd.getAbilities();
if (ability == null || ability.isEmpty()) {
p.sendMessage("No abilities found.");
return;
}
String element = ability.get(0).toString();
COOLDOWN_TIME_MILLIS = getacooldown(element);
long cooldownEndTime = getCooldown(p);
if (!isOnCooldown(cooldownEndTime)) {
startCooldown(p);
switch (element) {
case "dash":
doDash(p);
break;
case "windblow":
doWindBlow(p);
break;
default:
p.sendMessage("Unknown ability: " + element);
break;
}
} else {
p.sendMessage(getCooldownMessage(cooldownEndTime));
}
}```
Yeah, Also looks like WardensAPI is passing player aswell. I'm still learning but this is what i've been told. Use UUID for everything you can
If you have access to WardensAPI i would redo all that aswell.
I don't have access to the warden API so is it still worth it or should i just pass the player in this case
K thanks for the tips!
This would greatly benefit from SOLID concepts
Check the pinned message on #help-development
So I have a runnable that does stuff every tick for every online player. https://pastes.dev/uLpaIHZoHs
Like sending and actionbar. But now I want to do more stuff every tick for every online player, like regenerating mana.
Should I put this and future tasks that require the same players and timing in the same runnable and break SRP, or create a separate runnable, listener and collection for every different task and have duplicate code, runnables, listeners and collections?
Ideally you should attach some sort of "entity data system" that tracks data and ticks a given entity
For example at work I made a system that we call "entity components" where you can add components to an entity that let's say, run a method every tick for that given entity
designed an ecs by mistake...
Do you mean something like this? https://pastes.dev/oBZ9F7SQX1
Or would this store the tick method in memory for every player even though it's the same for every extension of AbstractData apart from the parameters?
I'm quite lost about what would be a SOLID implementation for something like this.
Depends if the data needs to be ticked or not
Different component types do different things
removeIf please
Alright thank you both
How much hate can i get for this? 😂
public void rewardPlayer(UUID uuid, Task task) {
Player p = Bukkit.getPlayer(uuid);
for (String s : task.getRewards()) {
if (s.contains("CMD:")) {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), s.replace("CMD: ", "").replace("[player]", p.getName()));
} else if (s.contains("ITEM:")) {
String item = s.replace(" ", "").replace("ITEM:", "").replaceAll("\\d","");
int quantity = Integer.parseInt(s.replaceAll("[^0-9]", ""));
ItemStack itemStack = new ItemStack(Material.matchMaterial(item), quantity);
if (Material.matchMaterial(item) != null) {
p.getInventory().addItem(itemStack);
return;
}
System.out.println(item + " is invalid!");
}
}
}```
yes
I got drunk last night and tried to code. 😂
I didn't just had an idea in my head and tried to make it work
This is what its getting 😂
Rewards:
- 'ITEM: diamond 5'```
Now thinking about it instead of a stringlist i should be using a ConfigurationSection like
Rewards:
Item: diamond
Quantity: 5```
Redoing this
Wont work
what wont?
That YAML snippet isn’t valid
You can make a list of objects but you can’t make an object that also has a value
e.g.
Rewards:
- Item: ‘minecraft:diamond’
Count: 5
- Item: ‘minecraft:emerald’
Count: 8
Yeah i was just writing it on a fly, i getcha
Only downside of object lists is that they’re syntactically awkward
Yeah, im actually learning that now and its annoying 😂
adding it into a hashmap i should say
yaml cringe
toml best
Someone needs to add getSerializableList()
nbt best
I stg these end up looking so much better in JSON
Well, yeah, they do. It's just a list of objects
"Rewards": [
{
"Item": "minecraft:diamond",
"Count": 5
},
{
"Item": "minecraft:emerald",
"Count": 3
}
]
wondering if theres a "cleaner" way :/
You're checking opt != "" twice. No reason that can't be inverted and continued, right?
where would you set opt_set = i then
what language is this
odin
english
한국어
what
its korean
shooter.getWorld().playSound(shooter.getLocation(), Sound.ENTITY_ENDER_DRAGON_SHOOT, 2f, 1f);
Location startLocation = shooter.getEyeLocation(); // Start the beam from the player's eye level
Vector direction = startLocation.getDirection(); // Get the direction the player is looking
double maxBeamLength = 50.0;
new BukkitRunnable() {
double currentLength = 0;
@Override
public void run() {
if (currentLength > maxBeamLength) {
this.cancel();
return;
}
Location currentLocation = startLocation.clone().add(direction.clone().multiply(currentLength));
shooter.getWorld().spawnParticle(Particle.END_ROD, currentLocation, 10, 0.2, 0.2, 0.2, 0.01);
for (Entity entity : shooter.getWorld().getNearbyEntities(currentLocation, 1.5, 1.5, 1.5)) {
if (entity instanceof LivingEntity) {
LivingEntity livingEntity = (LivingEntity) entity;
if (!livingEntity.equals(shooter)) {
livingEntity.damage(3);
}
}
}
currentLength += 1.0; // Increase beam length
}
}.runTaskTimer(WardenSMP.getInstance(), 0L, 3L); // Run the task every 2 ticks (0.1 seconds)
}```
Nothing partially wrong just looking for tips and things to improve
I mean tbf that's a suitable way to schedule tasks, but yeah, ideally you use the scheduler. Less nesting involved
Is there any reason you're cloning startLocation and direction though? Doesn't seem you're using them anywhere aside from in that loop. You could save yourself lots of object allocations if you just do something like this:
public static void doLightBeam(Player shooter) {
shooter.getWorld().playSound(shooter.getLocation(), Sound.ENTITY_ENDER_DRAGON_SHOOT, 2f, 1f);
World world = shooter.getWorld(); // <----- Save this in a variable so you don't have to keep fetching it
Location location = shooter.getEyeLocation(); // Start the beam from the player's eye level
Vector direction = location.getDirection(); // Get the direction the player is looking
final int iterations = 50; // <------ this can just be a simple int now
new BukkitRunnable() {
int iteration = 0;
@Override
public void run() {
if (iteration > iterations) {
this.cancel();
return;
}
iteration++;
location.add(direction); // Mutable, and direction is normalized so it adds by 1
world.spawnParticle(Particle.END_ROD, location, 10, 0.2, 0.2, 0.2, 0.01);
for (Entity entity : world.getNearbyEntities(location, 1.5, 1.5, 1.5)) {
if (entity instanceof LivingEntity) {
LivingEntity livingEntity = (LivingEntity) entity;
if (!livingEntity.equals(shooter)) {
livingEntity.damage(3);
}
}
}
}
}.runTaskTimer(WardenSMP.getInstance(), 0L, 3L); // Run the task every 2 ticks (0.1 seconds)
}
}
Everything else honestly looks fine
di 👉👈
How would you simplify this without losing clarity? Or what would you change?
colors:
default:
need_permission: false
permission: "holotools.holocrafter.color.default"
slots:
default_slot: light_blue
slot_0: blue
slot_2: blue
slot_4: blue
slot_6: blue
colors_lists:
blue:
unselected:
hex: "#19a7d2"
alpha: 150
selected:
hex: "#28bae6"
alpha: 200
light_blue:
unselected:
hex: "#24dce5"
alpha: 150
selected:
hex: "#5be4ec"
alpha: 200
If need_permission is false you shouldn't have to configure the permission right? (You can check if the permission object is null and if it is assume need_permission is false).
And unless colors will have more keys in the future you can remove it and make default the highest one
what exactly is this for
Alpha can be part of hex
making default the highest one is sure to cause issues, I think this format is fine
It's so you can configure colors for ranks, and basically, each panel is a slot
https://cdn.discordapp.com/attachments/849481473496580116/1282816769937117288/2024-09-09_02-40-05.mp4?ex=66e0bbb7&is=66df6a37&hm=6c221134436af23a75c5f046406cc9c9ee880a271ed9c788d2673a857814dffe&
why does the slot number have increments of 2
are you just using item displays for the background
In the config I sent, there are only 2 colors, and since slot_1, slot_3 is not defined, it uses the default color, making it look like this:
TextDisplay
Yes, it's the only thing I could think of to simplify the config and avoid having to specify 8 slots all the time 😅
yes, its a good idea
yeah other than the suggestions already made by people i think its fine
not much more you can do without removing information
why
Because it can be set to transparent
okay but why not use an item display
Because I want it to be see-through. Do ItemDisplays allow you to set transparency?
But with a resource pack, right?
yea
I don't like that >.<
why exactly
you can make your plugin generate a resource pack
which then works with other ones on the server
i think there is a case to make for no resourcepack
like if its possible without resourcepack with seemingly the exact same look, why not
well you can achieve a lot more tho
visually speaking
yes
but if you dont have to
like if you are already using one then ofc but if you dont use one yet and dont plan to, why go through the trouble
Exactly. I prefer to do it this way and add optional features with resource packs if the end user wants them
yeah same for my plugin
How can text turn into a colored background without a resourcepack?
nvm
its related to the convo
I guess its by using the text display background
and then just haveing some arbitrary text with invisible color
You can set the text display background (including alpha)
Then I think you can just fill the text display with spaces
Oh cool, thanks
Thanks for the help @sharp epoch. This is how it looks in the HoloWardrobe 🐱
That is very cool
That is amazing
that is actually really cool, I like it
I love the amount of stuff display entities allow us to do nowadays
Not a big fan of the empty slots that say "Air" on hover tbh, otherwise really awesome!
How did you do the tooltips
Text Displays
Well yeah
But how does one get all the data from the item to the display
Is it just a bunch of checks for stuff like attributes
||ItemStack#calculateTooltipLines in Paper||
the tooltip is gotten from the component list, so it should be relatively easy to make an API for it (each component with a tooltip info has an appendHoverText method, I think there's a method in ItemStack that collects them for you)
Maybe once we have component api merged
That feels like it should be a client-only method, no?
Why would the server have any use for that whatsoever?
Yeah. Its only uses are in the client. Weird that that's not stipped from the server and even weirder that Paper added API for it
The server has to use it at some point, right?
Nope
3 method invocations, all on the client
Either for searching or for rendering
Maybe Mojang is just being nice
They probably just don't strip out code that isn't under the .client package
I think that's intentional. Pretty sure they mentioned it in a snapshot at one point
YOU USE ECLIPSE??
WOW
They actually finally added a better, in-lined search widget which is great
I don't see Mojang removing it any time soon, so I'd say it's fine for an API
Death to search window 
Hesitant. Last time I added API for methods that were on the server but were used exclusively by the client, we ended up having a dead API that doesn't work anymore
RIP to CreativeCategory. Lived for like 2 versions
lol
Is this too much for one object? Should i split it up into more objects?
public Task(String name, String description, String icon, TaskType type, int amount, @Nullable String material, @Nullable String word, boolean repeatable) {
this.name = name;
this.description = description;
this.icon = icon;
this.type = type;
this.amount = amount;
this.material = material;
this.word = word;
this.repeatable = repeatable;
}```
Maybe Task, TasksRequirements, TaskRewards, TaskType?
You could also use some builder for it if you wanted to also
Record + RecordBuilder 
Actually already changing it to record
public record Task(String name, String description, String icon, TaskType taskType, boolean isRepeatable) {
This looks really cool
Yeah it is nice
Why is it everytime i look at an API i get overwhelmed?
Well actually @Builder I guess
I don't know why it chose to do TypeBuilder.build(). That seems redundant, no?
Couldn't they have generated a Type.builder() method instead to return the builder type?
I also really don't like the removal of new using a static factory method lol. But to each their own I suppose
I've always wanted to make something along these lines but making IDE plugins is such a real turn off
You don't need to make an IDE plugin. You just need to make an annotation processor
The IDE should handle the processing
I've always been under the impression you'd need something to understand the methods are actually there
Yeah. That's what the annotation processor is. It generates code. But the IDEs know how to deal with the code that an annotation processor generates
It just has to be aware of it
huh neet
Lombok's got an installer for Eclipse, but all it does is add the agent to the ini file
It's not a plugin
its a plugin on intellij and VSCode too
which is why I was confused its the only annotation processor I've ever used
what do you use to look into client code? Yarn mappings or neoform?
I usually use Paper userdev to look
Nah I make my own enhancement mod for small quirks I think would be useful lol
We do have an official modding API though, finally. It's extremely primitive, but it exists
WIP obviously
via the PMC lmao
I don't think they'll remove it. The code, or at least the method, has been in the ItemStack class since version 1.17. (I really hope they don't remove it, or I'll have to do it manually again, like I was doing at the start 💀)
that's the standard way for server and clients to communicate on modding platforms
mojang added them for that very purpose, rather
It uses a built in packet
Meaning clients without the mod won’t freak out
Or servers without the mod
https://github.com/HuskyDreaming/Settlements Can somebody review this code (You might need to look at HuskyCore also), and would be nice if someone could join the testing server to test
Not a fan of the collapsed if statements
If you're opening braces on for loops I feel like you should open them on if statements too
Thanks, I will do that better. It's a good practise
Hoping there's an isEmpty method available. Computing the size often takes longer than just checking if an entry exists
I'd also like to see more registries and less enums. If I want to hook into your plugin and add a flag type I'd need to hard fork it
There isn't 😦
I feel like DependencyType is stupid, should rely on interfaces instead
And your Placeholder expansion seems to have a bunch of duplicate code. could rely on even more interfaces
Not sure what versions this plugin supports but having hard references to locations can result in memory leaks below 1.13.2 if the world is unloaded
This plugin should only be downloaded on the latest versions, I am going to make an update soon
I don't like supporting lower versions
I also feel like your Config class should be immutable. Config files are meant to be read-only at runtime
Needs to be mutable because players can change configuration in game via GUI 😉
And I'd like to see you split your API into an API module. That allows you to expose an API without any of the implementation quirks
It also feels nicer to import a com.huskdreaming.settlements.api.whatever package instead of com.huskdreaming.settlements.services.interfaces package
As for package naming, it makes sense as a developer to toss all your enums in a corner but I tend to organize my packages by feature instead of by what they contain
Sounds good, I will make sure to organize it better and make it friendly for other developers to use
Now, on your API, you should also validate the inputs
Because there's going to be an idiot tossing null players at some given point
It's fine to throw an exception but make it clear it's their fault, not yours
Good idea, will make sure
On your flag service, it isn't clear what this runnable's purpose is. If it is a callback, try using futures
Something like
CompletableFuture<FlagOperationResult> addFlag(Settlement settlement, FlagType type);
That allows them to chain into the future if they'd like a callback, or ignore it completely if they're just going in blind
The result can be an enum that can, for example, tell if the flag was already set, if it's successful or if an exception was thrown
This can be reworked into ProtectionHook and FactionHook or something
Because while it might not be worldguard protected it can still be claimed with something else
Yeah and it’s technically also not a service. I will make a better interface for them
hasNoInvitation is negated by default. Prob your IDE yelling at you but this should not be negated
and what do the longs even mean
yikes you're returning a mutable set
This naming makes no sense. call it init or something
Set.copyOf will do the trick
what if settlement was immutable and this was just a builder 🤔
Do these really need to be a set? what stops it from just being a generic collection
Yeah I was thinking of making it a builder. Wasn’t sure if it was overkill because I only need todo it once but yeah 100% agree on it being immutable
Record + RecordBuilder 
@jagged rock anything that you see that is a big problem or overall looks pretty okay?
Just some minor changes and quality of life improvements?
Make sure you're not doing IO on the main thread type deal
haven't seen your repository impl
more nitpicky: this creates multiple instances of the same object. Reuse your variables
Add a gitignore to remove the .idea folder, target folder and dependency-reduced-pom.xml
Yeah sometimes it’s just me being lazy
Overall good code?
Yeah 😬🫣
epic markdown fail
You should be using read and write locks and making sure your configuration class is thread safe (for example synchronized)
omg
- you should exlclude your .idea folder
- Don't call your main class Main for rational see https://www.spigotmc.org/threads/why-you-shouldnt-name-your-main-plugin-class-main.493289/
- I'd personally avoid star imports though that's up to you
- avoid
§instead use Bungee's ChatColor class instead, Most keyboards don't have the section symbol also ChatColor constant use makes the goal of the string join more clear and less arbitrary e.g.§lcould be confusing to someone where asChatColor.BOLDlacks any such confusion - Don't run database queries on the main thread its a good way to cause the server to freeze or possibly time out if queries run long or too many of the action happens at once. In your case its players joining. You should really be caching this stuff instead of just going raw straight from the databse on the main thread. see PlayerConnection#L38
- Don't hardcode messages. You already have a messages config I don't see the reason for any of these messages to be hardcoded.
- I wouldn't hardcode kits. Make kits configurable Ideally you should have a very rich configuration system for kits. Otherwise things get dull from a customization standpoint. Likewise don't hardcode kit price etc. The user should beable to configure these things.
- PlayerKitManager#getKitPrice is just a bad method it makes no sense. If you're switching over a enum and you don't want to make anything configurable why not just bundle kit price in the enum?
- I wouldn't start import PlayerStates in PlayerManager it gets confusing especially with the clash between PlayerStates.SPECTATOR and GameMode.SPECTATOR
- Especially on spigot DO NOT USE INVENTORY HOLDER EVER see rational https://www.spigotmc.org/threads/why-items-with-lots-of-metadata-actually-cause-lag-an-inventoryholder-psa.607711/ instead follow this guide for sensible inventory gui design https://www.spigotmc.org/threads/a-modern-approach-to-inventory-guis.594005/
- Exclude the dependency-reduced-pom.xml from git it doesn't need to be there for git
- In your kit selector I'm confused behind why you define the ItemStack variables before assignement? The naming of them too is just bad you aren't a compiler KitSelected#L24-L67
- Your entire GUI design is primitive, but switching away from InventoryHolders should help your design especially with the guide thread above.
- Another nitpick is just that this code plain and simple isn't reusable at all if you were to ever make a minigame again. The lack of a more generic Team definition or kit system just leaves a lot to be desired both from a server owner and developer perspective. You could make things way more configurable than they currently are with a tad of redesign
Eh, one doesn't necessarily have to exclude the whole idea folder, there are environment settings there that could be of use
also, what is wrong with star imports? They're fine, in fact, Java is encouraging to go towards that route with module imports now
They don't take advantage of .idea configurations that would benefit from .idea being g included
Nothing per se it's stylistic, though I'd say personally I don't like them because it makes it less clear what I'm using from each package. I like to know especially when refactoring
Thank you i have improved so many things if you have time check it now!
Castle Siege is my first coding project built using spigot-api and java, inspired by old minecaft game mode on Mineplex - cbhud/Castle-Siege
java 8 and spigot 1.17.1 
also unrelated, but you should put a license on that repo
something like MIT will do if you don't know which one to choose
nitpick: the comments look kinda over the place, TODOs above the package declaration (only thing that usually goes there is the license header), // Added this field comment which is just ??
same nitpick from me, I really don't understand these kinds of comments
smells like GPT ^
the code seems fine, but it is kinda all over the place, the abstractions don't have a sense of purpose
I don't like the nesting here and from what I've seen, everywhere else, use guard clauses instead
we're really just nitpicking since the code is fine as is lol
I've always been told, "ask for a review, receive a review."
thats the point of the channel
I think the biggest point of having your code reviewed is so that you can fix these nitpicks and ultimately make your code better
my major trouble with it is just the fact that it is using java 8 really, and I would personally work out more the architecture of the plugin itself
Otherwise if it works, why do you care to have the code reviewed
I think it really depends, in this case there's really not much room to improve anything since most of what's been suggested are majorly stylistic choices
Again back to this point
You can't argue the fact that they asked for this, at the end it is their choice, we just offer the advice as you imply
oh, I'm not saying to not review the code, I'm simply emphasizing to the dev that there's nothing to really take at heart here
if they make the choice to follow what we're saying then good, but either way would be fine
If it's a nitpick now, it's probably a nitpick later. Why not practice writing your code in a way that looks cleaner and is easier to read? If the nitpicks were meaningless then again there would be no reason for a review unless some other major issue was the focus
But as it seems, this project is complete and only what I can assume to be tested, therefor the nitpicks are what this person is after
nitpicks are meaningless, hence why they're called nitpicks
Not if it's what the person is after
Nitpicks in the way you put it are stylistic choices, in which that person may find value in
so really they have subjective value
It's all we can do to offer as advice because again, this project seems to be complete
if anything, I like the fact that the code is simple, they're not trying too hard to make things complex
it is really easy to fall down that path the bigger your project gets
My nitpick about the guard clauses just make it easier to read imo
But hey if it works it works and it's only up to them if they want to make any changes
2 days without activity, i will throw one into the round:
https://github.com/godcipher/gutil please for review :)
I think the only thing I notice is I'm not sure if I vibe with the ListPaginator design. The use of subList is quite strange imho. Sublist provides a mutable view, which is great if you want to mutate pages, but yet there is no way to add extra pages to the ListPaginator easily. I feel like if you were to allow mutating of the pages themselves wouldn't it make sense to also allow the addition and removal of pages as a whole?
good catch, that wasnt intended. yeah i agree its a bit odd in this context. i will make it immutable, thank you 👍
Wrote this in class today fire away ladies and gents https://github.com/Y2Kwastaken/AdvancedGreetingService
wtf am I reading
Nit pick it. Go enterprise on him
I just stopped reading since I can't review something I can't take it seriously lol
so i wasnt the only one being confused
Not confusing at all its just a multi lingual hello world program
i expected something else, so i was confused
first thought its a greeting service for devices
I should add android support that is a good point
not what i was trying to say, but go for it
After some time of just copying them every time, I put some classes together in a small library
https://github.com/steve6472/SteveCore
Mostly interested in review of settings and registry
Very basic implementation is in https://github.com/steve6472/Orbiter
Rarity probably shows the registries best I think.
You're missing a license file and something else is amiss when looking at the root directory structure
https://github.com/steve6472/SteveCore/blob/8589edb4f84fadebf86edd40ef7abc640fdaa0da/src/main/java/steve6472/core/util/Preconditions.java#L14-L26 let's not ignore that the Objects class has similar methods for null checks.
https://github.com/steve6472/SteveCore/blob/8589edb4f84fadebf86edd40ef7abc640fdaa0da/src/main/java/steve6472/core/util/Preconditions.java#L60-L70 checkAboveZero is a misleading name when 0 is also in the supported range of value.
https://github.com/steve6472/SteveCore/blob/8589edb4f84fadebf86edd40ef7abc640fdaa0da/src/main/java/steve6472/core/util/Preconditions.java#L72-L106 at this point I'd call them assertX and throw an AssertionError, but I suppose it depends on the usecase.
https://github.com/steve6472/SteveCore/blob/8589edb4f84fadebf86edd40ef7abc640fdaa0da/src/main/java/steve6472/core/util/RandomUtil.java#L19-L38 calling it randomRadSin etc. is a bit misleading, since sin and cos return values from -1 to 1, making it an implementation detail whether the sine and cosine were obtained through a random radian or through a random degree.
https://github.com/steve6472/SteveCore/blob/8589edb4f84fadebf86edd40ef7abc640fdaa0da/src/main/java/steve6472/core/util/RandomUtil.java#L108 probably not the most … inline naming out there. randomBoolean might be a slightly more conventional name there.
https://github.com/steve6472/SteveCore/blob/8589edb4f84fadebf86edd40ef7abc640fdaa0da/src/main/java/steve6472/core/util/RandomUtil.java#L113 using an integer for probability can easily be a bit misleading. Unless you need the performance, the good old return (randomDouble() < probability); is more intuitive in what it means. If you want to go the integer route, compare with 0 instead since that results in fewer Opcodes, meaning it's more likely to be inlined
Preconditions are indeed shitty and unfinished, not sure if I even want this.
RandomUtil is very old. All your comments make sense, I'll implement those, thank you.
I mean in Preconditions, you may wanna throw more specific exceptions than just runtime exception
can be useful if u unit test around a special type of failure for example
junit's assertions are usually good enough in tests and IDEs have auto-completion built-in for them and even do static imports (which is like the only time eclipse does static imports by default, but it's a coding style I don't really oppose to)
Rate my JLS-compliant code: List<String> = new <Integer, Long, Boolean> ArrayList(); (credits to the VF discord who figured out that this is valid Java code)
Yeah, could you please not?
Also im totally gonna look into this when im home... What a mess
for the randomRadSin and other functions that use sin and cos, couldn’t they just return a random number between -1f and 1f
lol
Then you might need to check the graph of sin and cos again
they aren't linear distributions
Well what I’m saying is that, because it returns a double, and the double is the sin/cos of a random number between -PI and PI, wouldn’t that basically just be a random number between -1 and 1? Or am I wrong in thinking that?
it would be a random number between -1 and 1. But the frequency of those values will not be uniform
Ah I see what you mean
This is mainly caused by sin'(x) not being 0 for every value of x
What
It's thanks to UnqualifiedClassInstanceCreationExpression defined by JLS 22, §15.9. I'm not entirely sure what the TypeArguments are there for though
Unqualified who what where
Class instance creation expressions have two forms:
Unqualified class instance creation expressions begin with the keyword new. An unqualified class instance creation expression may be used to create an instance of a class, regardless of whether the class is a top level (§7.6), member (§8.5, §9.5), local (§14.3), or anonymous class (§15.9.5). Qualified class instance creation expressions begin with a Primary expression or an ExpressionName. A qualified class instance creation expression enables the creation of instances of inner member classes and their anonymous subclasses.
import me.jonnite.wardensmp.WardenSMP;
import org.bukkit.Bukkit;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.List;
public class passiveTask extends BukkitRunnable {
private final WardenSMP wardensAPI;
public passiveTask() {
this.wardensAPI = WardenSMP.getInstance();
}
@Override
public void run() {
var onlinePlayers = Bukkit.getServer().getOnlinePlayers();
onlinePlayers.forEach(player -> {
var playerData = wardensAPI.getPlayerData(player);
List<String> passives = playerData.getPassives();
if (passives.isEmpty()) return;
passives.forEach(passive -> {
switch (passive) {
case "speed1":
player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 30, 0, true, false));
break;
default:
break;
}
});
});
}
}```
is this the best performance wise way to do this? btw there will be more than just speed1 passive?
Using a regular for loop is better
also just use contains and passives could be changed to a Set
I mean I don't know about "better", but yeah, generally best to reserve calls to forEach() with either single-line lambdas or method references. If you're making a block out of your forEach(), you might as well just use a for loop
It literally makes no difference at all, but stylistically it's just clearer
I would also opt for just a single if statement over the switch, but I guess that's preference too
Ultimately I would have written your class like this,
public final class passiveTask implements Runnable {
private final WardenSMP wardensAPI;
public passiveTask(WardenSMP wardensAPI) { // Pass it directly
this.wardensAPI = wardensAPI;
}
@Override
public void run() {
for (Player player : Bukkit.getServer().getOnlinePlayers()) {
for (String passive : wardensAPI.getPlayerData(player).getPassives()) {
if (passive.equals("speed1")) {
player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 30, 0, true, false));
} else if (passive.equals("whatever else you want to add")) {
// blah
}
}
}
}
}
But you should really look into an alternative for how you define your passives. Maybe you want to actually define a PassiveAbility or PassiveEffect class that would apply whatever needs applying to a player, then you wouldn't have to operate based on strings and add a new if condition for each new passive you define somewhere else
Your whole run() method could look like this:
@Override
public void run() {
for (Player player : Bukkit.getServer().getOnlinePlayers()) {
List<PassiveEffect> passives = wardensAPI.getPlayerData(player).getPassives();
passives.forEach(effect -> effect.applyPassive(player));
}
}
Quick question, I recently forked a project from GitHub and made a few changes to it, can this be reviewed as well?
The problem is, I don't really have a GitHub account and the plugin is based on an extremely old API
I mean, just make a github account? Lol
or host it somewhere else if you don't feel like using github, there's plenty git hosting providers nowdays. Gitlab, bitbucket, gitea
I'll give this a try, thank you!
I love gitlab
we use gitlab at work, its pretty nice
gitlab my beloved
1000 rizz isn't enough 🤔
I like your use of lambdas and anonymous classes
The module names aren't consistent and I don't get the point of tests not just being in core or the route module existing and not being in core
Tests is a plugin so I can test the library manually. Route is not fully implemented yet I think it will be big.
Use consistent naming, some is plural some isn't
object LinearCurve: (Float) -> Float
For the future, ALWAYS put a space after a class name, not LinearCurve: ... but LinearCurve : ...
See https://kotlinlang.org/docs/coding-conventions.html#colon
private fun minimessage(parse: String): Component {
return MiniMessage.miniMessage().deserialize(parse)
}
private fun minimessage(parse: String, vararg tagResolver: TagResolver): Component {
return MiniMessage.miniMessage().deserialize(parse, *tagResolver)
}
The first function is redundant, and I'd also make this public for use in other places, and have an extension fun on string for that
guiComposable.add( e )
val hooks = mutableListOf< ComponentState<*> >()
inline fun Gui.component( slot: Int, component: GuiComponent ) {
Please ffs don't do that spacing
I think you need to listen to more inventory events and you can just drag items out currently, don't know if that's intended or not
I don't get why you'd have a seperate module for a singular class
RouteCommandTest is a very inconsistent name considering all others are just ThingCommand
Other than that, it looks pretty cool
is the first point something normal to kotlin devs
as in, is it defined in some code style guide
I'm a dumbass, you linked to it lol
ah, it makes sense now. I thought it'd be fine since it would look more consistent with how methods use the colon, however it'd definitely look weird with parametized classes
Use ktlint or something and stick to a standard
Your miniMessage methods could become extension methods
Make sure to stick those in dedicated extension classes
https://github.com/RaydanOMGr/BasicModInfoParser rate my ass code
Why not make BasicModInfo a record?
Java 8 compat 🙃

I'd write it in java 5 but I fear that has no lambdas
Can we ban raydan
why
simply because I can
sigh
and if I can, why shouldn't I



I think you wanted to say "forwards compatible"
it is dumb compatible
modern software should be written using modern technology if there's the choice
this is modern software written for ancient software
paper!?
writing code that unnecessarily delays the inevitable deprecation of older technology is a sacrilege as a developer
there's nothing in that code that requires it to be written in java 8
anyhow, as per the review goes
it looks fine, kind of annoying that it uses older IO APIs but that's fine
would rather see take advantage of ZipFileSystem instead of JarFile, and maybe a DirectoryStream or a Files#walk for the archive lookup
the code for FORGE_LEGACY and FABRIC is pretty similar, you could probably take better advantage of Gson by creating records/classes to parse the metadata, unifying the logic
it's pretty well-written as far I can see, just a shame that it doesn't really take more advantage out of the newer I/O APIs out there in the JDK and in the language as a whole
considering the amount of resources for the old IO is insurmountably larger due to it being the peak era for java, I guess it can't be helped
nuh uh
The main issue is finding a J5 JDK I believe
And then the second issue is finding an IDE that even allows you to compile against J5. Eclipse (and thus every other system based on JDT) recently removed support of Java 7 and below, and I'm not sure how IJ is doing.
And honestly, going with anon classes isn't terrible for enum members. It's only more of an issue when you expect to have public API be based on it, but that's not really the case
I use java 8 to show people why j21 is better :p
me using J6 for micromixin
No no it’s the opposite, you make them jealous with all the j21 features
Jealous in respect to what?
Java 8
The only real J9+ feature I'm missing and that one cannot easily port over to J8 world is named classloaders, but Multi-Release Jars are a thing so that's something limited to the production environment
instanceof casting would like to have a word
Well, that you can downgrade to older java versions rather easily thanks to compile-time tools
What about pattern variables
pattern vars? Probably never used them so there I actually don't find any reason for using them going forwards. And even then, that's syntax sugar which can be downgraded extremely easily
Still have to put the effort into compatibility, I'd rather just have it available
I mean, it's pretty much only copy & paste once you have written the gradle buildscript once
I don't think I really want to create an Oracle account, notwithhelding any other complications associated with it.
I'll throw this one out here I just made it
https://github.com/PineappleDevelopmentGroup/PineappleEnvoys/
no entry loop?
Why is your list named as if it wasn't a list
This can be tossed up to save yourself performance
Pretty sure there's a take builtin method
Not sure why you're returning a "defensive copy". This list isn't mutable
You could use some sort of FSM / Phase system for the envoys themselves (wait phase, drop phase, collect phase)
Lots of hopes and prayers here
9/10 chance you have a memory leak if the world decides to unload
I'd make a dedicated ChunkKey class. Could just be a typealias, but using generic pairs is quite stupid
It might also be worth to have some central "chunk snapshot cache" if multiple envoys decide to fire around the same time
Also hardcoded messages ew
@woeful pasture
debug messages stay hardcoded its just there for if shit explodes
I made everything that is actually generally supposed to be used configurable
are you sure about that
what class is that in
which one
debug 
loot table
yeah I should switch that over to a String with a getter to the actual world
or.. some world reference class
yeah gp there
yeah for sure the actual "game" portion could use some work tbh
where is that at?
is that my EnvoyTile?
probably
if so it can kind of just explode If the input never lines up it should explode and it'll be deleted pretty much
Also why are half the variables nullable
Wouldn't it be better to migrate to some sort of builder -> constructed object pattern
its kind of an unfortaunte symptom of the top level library load and save design. There isn't a much better way to design a super generic load save system that could work for every conceivable thing without reflection thoguh
Here we go I guess
https://github.com/notFoxils/foxutils/tree/master/foxutils-items (utility for adding custom items, you can poke at the other stuff, but its all broken i think lol)
https://github.com/notFoxils/SynthSMP/ (implementation)
I'm quite new to Java, OOP all of that
and I have a feeling I may or may not be making some mistakes here and there, so id like to hear some feedback or just get some pointers in the right direction (which i guess is the whole point of the channel)
looking at foxutils-items right now, and the main class looks good so far. Just one mistake: you're using Objects#nonNull wrong
I am aware that IJ suggests that for hiding the warning, however it isn't a good solution as it is an assertion and not an assurance
i believe i just put those there to make intellij stop complaining lol
So, like, we are telling the editor (compiler maybe idk) that ooh this is never gonna be null, but we never check it? That seems about right
yep, so it is just gonna throw instead. Though that might be fine in this instance since getCommand only ever returns null when you forget to put it in the plugin.yml, or forget the plugin.yml altogether lol
a question relating to this, im i think my doubt in the structure of the modules i have there is from a lack of understanding of OOP/OOD
im kinda just throwing shit at a wall and seeing what sticks atm (foxutils-hud module) and yknow i end up wasting a lot of time that way (foxutils-hud again), just to create something im not really 100% confident in, or just something that dosent work (foxutils-hud, AGAIN)
what is this supposed to be, an API for hud configurations?
oh you got your own config API too, fancy
it was a bit ambitious, but the main goal was to get something working where i could specify a "hud" configuration inside a dedicated configuration file EX:
hud-configs:
five-hud:
x-offset: 0
texture-unicode-character: "\uE000"
# Other custom data can be stored here for usage later for implementing plugins
alternative-texture-unicode-characters: {
"bleh"
}
player-hud:
x-offset: 0
texture-unicode-character: ""
first thing i instantly noticed: your registerItems method is awful
and then get the api to consitiently send action bar messages with custom unicode characters to the player
rather put it into another class or hold constants, f.e. your ItemAbilities.
Eh, it is fine
while having those same hud able to be extended like a class, or atleast manipulated through a class, and get info from a custom config class
it isn't big enough that it couldn't just be in the main class, they can move it later when it becomes too much
its already too much
each of them could be a constant, all the hardcoded strings are a bad practice
rather save it somewhere
have a repository for them
the names could be an enum as well
it's 135 lines, that's not much
that just flew over my head, could you further explain that?
you have a huge method to instantiate the itemabilities f.e.. you could put that into f.e. a ItemAbilityHandler, -Factory, -Repository, -Service(if you load it from a db or smth f.e.)
and handle the logic there
you can modulize it into smaller pieces as well
ohh, that's kind of like this plugin: https://www.spigotmc.org/resources/gui-api.95468/
f.e. the name as an enum and map the ability to it
unfortunately I am not too informed on the whole deal with negative fonts and how to make custom HUDs with them, however you may take inspiration from something similar
that said, the whole thing looks pretty solid, you'll probably find the rough edges the more you use it
is that necessary when there's like, 10 custom items max
nothing is necessary, but QOL and best practice
at the point it starts to scale, they'll probably make some kind of configuration-based approach like they did with huds anyway
bet he already has to search for single abilities if he wants to modify them
by making it modular and having a handler and factory for it he probably dont have to
i mean the implementation is there
you can check how i did that
most what sucks in it is the description, but thats not on him but just how it has to be done sadly. or you save it in a resource properties and modify it there.
ideally it'd be just a whole of translatable components, but we can't do that in spigot, can we sigh
yeah i see, thats well structured. i would refact it still tho by extracting methods but it looks good
its just the instantiation that caught my eye
having a properties with the description strings which you can just dynamically load in would be top notch tho
by that you get away from hardcoding string literals
not to sound like an idiot, but instantiation being when i do
new WhateverItem(bla, bla, bla)
and you are talking about how the constructor ends so huge (which i was talking about with another developer friend moving most of the bulk to a config file)
exactly, but im referring to the description strings to be exact
they are suggesting you consider i18n-ize your item lore/names
^
the whatanize 😭
simply said put your ability descriptors into a file
okay so mainly the ItemAbility class and how those can turn out quite huge
okay, makes sense
i18n is a short for internationalization (there's 18 letters between the i and n in internationalization, so i18n), it means having your strings be configurable/translatable via a properties file of your choice
okay yeah i see what you mean now
yes, by that you have everything at one spot and dont have hardcoded descriptions
yep yep, so move that to a config, and along with that i could probably move some of the other properties like material, names, custom model data, recipes probably
leave it to the strings first
and lookup Properties
java has an integration for that
everything else is serialization
https://github.com/notFoxils/SynthSMP/blob/master/src/main/java/me/foxils/synthsmp/databases/Database.java if you want to have something more robust you could think of switching to a database framework
yup
thats why i had the foxutils-data module, but i got stuck on constructing a solid structure for that
.
but most would argue that hibernate is too bloated for a minecraft plugin
isnt it quite similar to what you can do with FileConfigurations in bukkit?
yesnt. one is properties, one is yml
its not a config to be clear
wait
whats the difference
i know yml files are supposed to have a specific structure to them
but in the end you can do i/o on both of them?
properties = the properties of your application
config = users can configurate your application
im really bad at explaining lol
so properties are never seen by the end user? its just so that i have an easier way to edit the info of the ItemAbilities?
exactly, the properties are just inside the jar so people would have to decompile it to modify your properties
https://github.com/Metaphoriker/antiac/blob/master/src/main/resources/messages.properties i have that as well here
so i can just call Messages.getString("the.message.i.want.to.get");
by that your code also doesnt changes when you have to modify your descriptors f.e.
okay so in the same way i could hold the descriptions, would it be preferable to hold other constants like the Material, Custom Model Data, etc inside another properties file?
i wouldnt see why, since they are already constants
but you could wrap the custom model id and turn it into an enum or whatever so you also have them all at one point centralized
what would be the point in that?
that you dont have magic numbers flying over your code
- turning it into a value object and having a constant for it increases the readability since you know directly what it is
i know what they are, but i only ever specify the custom model data in the constructor, i never check for it
f.e.
CustomModel.MY_MAGIC_SWORD is more readable than 1027
i guess thats true
or if you are working with value objects
new CustomModelId(1027); is more descriptive than 1027
- changes to the code of CustomModelId doesnt directly affect the code where it is used
and ofc an underrated point, you can just ctrl click on CustomModelId to see where you have custom model ids put
with only integers in your code you cant
alright, on all that, do you have any resources where i could learn how to properly plan OOP projects?
not the programming part, but just learning how everything should fit together i guess would be the right phrase?
So instead of just throwing a whole day into something that is only like half functional, i could plan a proper structure for my projects and then build based off of that
resources not really, just a mindset
always ask yourself what could be better
I mean, from the looks of it you're doing OOP properly
first put your stuff together. do what you need. then think of optimizing
what you seem to be concerned about is more on the API design side, and that mainly comes from experience to be honest
I believe your code is good since it doesn't try to be clever, so intent is pretty clear from a first glance
yeah. there is no proper resource on how to do stuff the right way. everything is more like an opinion people share
but what you could look up is Clean Code, Design Patterns and Best Practices for java
that will help you build a fundament of a good structured code
everything else is software architecture
alright
thats the main part im really trying to get at, but like flores said, the design side probably just comes from experience
i mean for most part, if u've never coded the infrastructure of some feature, its really hard to know what the "right structure" in presupposition
so yea experience does help quite a lot with familiarity and confidence in correctness
to gain practical experience you have to understand the theory behind it
those principles make it easier and give you a direction
or if you want to deep dive https://en.wikipedia.org/wiki/List_of_software_development_philosophies
alright, sounds good then, ill read up on all the resources you guys mentioned
Clean code is crazy just learn your data structures and common design patterns
You'll develop your own style from there, but learning common design patterns and data structures is important
Also be willing to adapt to feedback and your environment. My code style differs depending on which code base I'm in
The biggest keys to a good codebase are (a) malleability and willingness to learn, and (b) consistency
Please don't just throw around Objects.requireNonNull it will just throw if it's null
Use actual error handling instead
Okay, thank you
In your send method why not just use the scheduler instead of doing anonymous classes?
sorry, what do you mean?
Bukkit.getScheduler().runTaskLater(plugin, 0, 3, () -> {...})
I believe those are the right arguments
Oh you used runTaskTimer
well doesn't change much
plugin, runnable, delay, interval
Oh okay
Or just plugin runnable delay for runTaskLater
what a nerd
You use them for 10 years, you start to remember them after a while
And why call Main.getInstance() every time when you have a plugin field already?
also
?main
Damn u right
new CreateScoreboard()
that's an odd class name
And please don't just scatter fields around your classes, it makes it hard to find them
Okay okay
Did they delete the link To see the code?
Yup lmfao
No one is stealing your code lmfao no point in deleting it
In the industry bad code is a requirement
Because we have to get this shipped yesterday
Deadline: 37 days ago
