#[MEGA THREAD] Get Your Code Reviewed or Review Others

1 messages · Page 14 of 1

rancid fern
#

Depends on the data being saved

#

but if possible it's a good idea

woeful pasture
#

That's what math is for

#

Ig though it makes sense if the server lags now that I think about it

#

Because of the server lags the time would he wrong

dense pond
#

so what? i asked how to do it before and they told me to do it like that

pine grail
#

this is also wrong because the scheduler uses ticks afaik and not ms

#

you'd need to convert it to seconds and then do * 20

#

not ms

dense pond
#

oh

#

what do i actually do..

#

i think my solution is right but i think i forvot to multiply

woeful pasture
dense pond
#

okay cool thsnks

dense pond
#

this means "target" folder?

dense leaf
#

yes

#

please learn to use a gitignore

dense pond
#

okay thanks im new to github

#

and git

#

can i just name my main class "Plugin" instead of "Main" if i dont want to name it with the name of plugin or something

#

okay i think thats not a good idea either

dense leaf
#

give it some name

sleek shard
#

Name it after your project

dense leaf
#

yea ^

dense pond
sleek shard
#

For example, if your project is named, foodgiver, name your main class FoodGiver

#

You could also have Plugin as a suffix

dense pond
#

oh, can i just name it FoodGiverMain

sleek shard
#

Like so - FoodGiverPlugin

dense pond
#

yes

junior holly
#

Oh

#

Purple said that already kek

dense pond
#

yepp

junior holly
#

Your main class should at least have plugin in the name, I think this is general plugin dev semantics when it comes to spigot anyway just makes it clear what the main class is

hybrid osprey
#

hm

sharp epoch
#

that looks like chatgpt wrote it

hybrid osprey
#

what

#

no :(

sharp epoch
#

well, it is a flood fill algorithm, it looks fine to me

hybrid osprey
#

thats all I needed to hear

sharp epoch
#

I like the recursive approach more as it is easier to grasp

#

but the stack based approach is fine too

hybrid osprey
#

my plugin adds co2 poisoning

#

if you stay in a small area for too long

#

or there's too many people in an area

sharp epoch
#

ohh I asked chatgpt about different flood algorithm impls and the breadth-first one looks pretty clean too:

public long floodFillBFS(World world, Location origin, long limit) {
    Set<Location> visited = new HashSet<>();
    Queue<Location> queue = new LinkedList<>();
    queue.add(origin);
    long volume = 0;

    while (!queue.isEmpty()) {
        if (limit >= 0 && volume >= limit) break;

        Location current = queue.poll();
        if (!visited.add(current)) continue; // Already visited

        if (current.getY() < world.getMinHeight() || current.getY() >= world.getMaxHeight()) return Long.MAX_VALUE;

        Material blockType = current.getBlock().getType();
        if (!blockType.isOccluding()) {
            volume++;
            for (Vector dir : DIRECTIONS) {
                Location neighbor = current.clone().add(dir);
                queue.add(neighbor);
            }
        }
    }

    return volume;
}
hybrid osprey
#

this looks to just be exactly what I did

#

but with a queue

sharp epoch
#

yeah, only difference is the stack and the randomization of directions

hybrid osprey
#

i also store a vector instead of a whole location

sharp epoch
#

if anything, I'd recommend using a normal random instead of thread local random for this kind of thing

#

that way you can unit test the thing properly

hybrid osprey
#

TLR is faster

sharp epoch
#

why would it be faster

#

it is just a thread-local random instance

pine grail
#

you should use a specialized random though

#

if you need perf at least use a SplittableRandom

#

it's even faster

sharp epoch
#

what

#

SplittableRandom has a different use-case

#

which is, being consistent across parallalel streams as far I remember

pine grail
#

SplittableRandom is around ~2x the speed and has better distribution last I recalled

sharp epoch
#

it isn't a matter of performance

#

they're all pretty fast on their own right

#

but the semantics for each one of these implementations are different

hybrid osprey
#

It's just randomizing the directions

#

I'm not generating keys here

#

so speed is good

sharp epoch
#

speed isn't relevant to this

hybrid osprey
#

It's doing this randomization for every block

sharp epoch
#

if you wanted to unit test the algorithm, then you can't do that with ThreadLocalRandom, as the seed will never be the same

hybrid osprey
#

In an area, it's randomly possible for it to always pick the direction that leads to open air

#

but for small certainly enclosed volumes, that randomization of directions doesn't affect anything

#

I see what you say but it's not really something I'm testing for, not that scenario. In that case, it'll either return MAX_VALUE or the limit, which is fine

pine grail
#

use a splittablerandom

hybrid osprey
#

I just changed it yes

hybrid osprey
#

What the fuck it was working an hour ago now its broken

#

I changed nothing

round fossil
#

but if u need that, ur app prob sucks

#

Either way don’t we have the RandomGenerator interface to abstract over now?

pine grail
round fossil
pine grail
# round fossil Which ones dont?

some library ones such as XorShift128 or whatever, it's one of the fastest implementations but I don't recall if it follows the interface

round fossil
#

It’d really make no sense if all the algorithms weren’t

dense leaf
#

are users able to seperate components out of the GUI though?

#

as in, have them in a seperate class

night knoll
#

Yep

dense leaf
#

that's cool

dense leaf
#

yeah pretty much. what we do is pretty much just

object ConfiguredTiles {
    val QUEUE_BUTTON = tile { ... }
    
    fun playerProfile(player: StandalonePlayerReference): Tile
}
#

same for the actual GUI objects, this is where I love those kinds of builders

#

I'm not sure I fully understand the routing thing though

night knoll
#

Switch between GUIs like in a browser

dense leaf
#

ah

night knoll
#

Literally react

#

🗿

dense leaf
#

Might switch to yours once it's finished, we'll see

night knoll
#
public class PartyConfiguration extends Configuration {
    private final List<String> inviteMessage;
    private final List<String> leaveMessage;

    public PartyConfiguration() {
        super("party");
        inviteMessage = new ArrayList<>();
        leaveMessage = new ArrayList<>();
        loadJoinMessage();
        loadLeaveMessage();
    }

    private void loadLeaveMessage() {
        // empty the list first
        leaveMessage.clear();
        // load the messages
        leaveMessage.addAll(getStringList("leave-message"));
    }

    private void loadJoinMessage() {
        // empty the list first
        inviteMessage.clear();
        // load the messages
        inviteMessage.addAll(getStringList("invite-message"));
    }

    public @NotNull List<Component> getInviteMessage(@NotNull Player inviter, @NotNull Player invitee) {
        List<Component> formattedInviteMessage = new ArrayList<>();
        LegacyComponentSerializer serializer = LegacyComponentSerializer.builder().build();

        for (String message : inviteMessage) {
            // Replace the %player% placeholder
            formattedInviteMessage.add(serializer.deserialize(message
                    .replace("%invitee%", inviter.getName())
                    .replace("%inviter%", invitee.getName())
            ));
        }
        return formattedInviteMessage;
    }

    public @NotNull List<Component> getLeaveMessage(@NotNull Player player) {
        List<Component> formattedLeaveMessage = new ArrayList<>();
        LegacyComponentSerializer serializer = LegacyComponentSerializer.builder().build();

        for (String message : leaveMessage) {
            // Replace the %player% placeholder
            formattedLeaveMessage.add(serializer.deserialize(message.replace("%player%", player.getName())));
        }
        return formattedLeaveMessage;
    }
}``` erm can i do better?
thorny jetty
#

you woulnt have to create a new LegacyComponentSerializer for every message

late smelt
#

You can also just have a static legacy serializer somewhere

hexed heart
#

This is my first time creating a plugin soo can someone give some feedback on it?

dense leaf
#

please don't use ansi codes

digital galleon
#

+1

#

Ansi codes arent always supported on all terminals

dense leaf
#

especially in log files

digital galleon
#

Bukkit has methods for that.

#

@hexed heart This isn't completely necessary, but some people like to utilize "packages", little subfolders if you will which store Listeners and Commands respectively.

hexed heart
#

one for listeners

#

and one for a reload command

#

thats it

dense leaf
#

ReloadCommand feels very chatgpt

digital galleon
#

I understand, I was just saying when it gets bigger.

hexed heart
#

and main one

dense leaf
hexed heart
dense leaf
#

why

hexed heart
digital galleon
#
        // Show correct usage after incorrect arguments
        if (sender instanceof ConsoleCommandSender) {
            plugin.getLogger().info("Usage: /nocreeperexplosion reload");
        }

        if (sender instanceof Player) {
            sender.sendMessage(ChatColor.RED + "Usage: /nocreeperexplosion reload");
        }

Whats the point in the distinction, just do if not instance of player.

digital galleon
dense leaf
#

the content

digital galleon
#
    @Override
    public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {

        List<String> suggestions = new ArrayList<>();

        if (sender instanceof Player player) {

            if (player.hasPermission("nocreeperexplosion.reload")) {
                if (args.length == 1) {
                    if ("reload".startsWith(args[0].toLowerCase())) {
                        suggestions.add("reload");
                    }
                }
            }
        }

        return suggestions;
    }

Whats the point of this?

#

ohh paramater, duh.

hexed heart
#

tab complete

digital galleon
#

Yeah I thought this was a standalone command but realized now it's /nocreeperexplosion reload

#

Also you dont need to do:
private final Plugin plugin = NoCreeperExplosion.getPlugin();

Because you can just pass the singleton instance directly.

#

So. For instance:

public class ReloadCommand implements TabExecutor {

    private final JavaPlugin plugin;

    public ReloadCommand(JavaPlugin plugin) {
        this.plugin = plugin;
    }
... // Your other stuff will go here
dense leaf
#

?di

rich fogBOT
digital galleon
#

Yeah

#

Also general practice, try to avoid massive nesting.

#
        // Check arguments
        if (args.length == 1 && args[0].equalsIgnoreCase("reload")) {
            // Reload the configuration
            plugin.reloadConfig();
            // Send confirmation in console
            plugin.getLogger().info(ANSI_GREEN + "Configuration reloaded successfully." + ANSI_RESET);
            // Notify the player
            if (sender instanceof Player) {
                sender.sendMessage(ChatColor.GREEN + "Configuration reloaded successfully.");
            }
            return true;
        }

Could just simply be:

        if (!sender.hasPermission("nocreeperexplosion.reload")) {
            sender.sendMessage(ChatColor.RED + "You do not have permission to reload the configuration.");
            return true;
        }

        // Validate arguments
        if (args.length != 1 || !args[0].equalsIgnoreCase("reload")) {
            sendUsage(sender);
            return true;
        }
hexed heart
#

oooo

hexed heart
dense leaf
#

yes

hexed heart
#

i like guard clauses

dense leaf
#

then why aren't you using them

hexed heart
digital galleon
digital galleon
#

As with most of the improvements you could make, they may not directly impact the performance of your plugin, but they can be as simple as readibility and good habit.

digital galleon
#

In object-oriented programming, the singleton pattern is a software design pattern that restricts the instantiation of a class to a singular instance. It is one of the well-known "Gang of Four" design patterns, which describe how to solve recurring problems in object-oriented software. The pattern is useful when exactly one object is needed to c...

#

Not sending you links to drown you in stuff you cant keep up with, its just because i genuinely cant explain it :)

hexed heart
digital galleon
#

hang on lemme think

#

idr

hexed heart
#

instead of the injection ahh method

digital galleon
#

You're right, it may look cleaner, but theres always reasons why we do things "the right way".

#

its like, using both feet for your car pedals might seem easier than switching, it can cause accidents, theres always reasons for these things :)

hexed heart
#

oh but isnt the static getter method more easier and safer

digital galleon
#

uhm

hexed heart
#

you can just call the getPlugin() method anywhere

digital galleon
#

i dont remember

#

@dense leaf

dense leaf
#

it's not "safer"

hexed heart
#

why not

dense leaf
#

because why would it be safer

hexed heart
#

not safer, but id say simpler

dense leaf
#

not necessarily

#

?di

rich fogBOT
digital galleon
#

Its listed all under * Why not to use the static singleton pattern*

hexed heart
#

okay

#

also any comments about the config.yml?

#

purrrrrfect

#

as an absolute beginner i shouldnt really worry on perfecting everything

#

got my first plugin out

#

feeling happy :)

#

and thats what matters

#

you can check it out now, i changed some stuff just like u said

winged blaze
#

Name your packages lowercase

rancid fern
#

Why are you registering two different instances of the reload command

#

Also no need to send the command usage like that

#

either return false or just send it to the sender

#

Not to the logger

#

Don't hardcode ANSI, not all consoles support it

#

You already seem to have gotten this feedback though

#

Should fix it before asking again

dense pond
#

but i dont want the reload command, shuld i just use the java file wataching api whatever that is?

#

i just came back to that code xD sorry for replying that late

round fossil
#

I mean you can, but prob aint necessary

#

thats like if u wanna monitor all file updates

dense pond
#

i need to have config which player can edit both in file and through minecraft (command etc) so what do i do if not reloading and saving every time?

dense pond
dense pond
hexed heart
#
public class CreeperListeners implements Listener {

    private final NoCreeperExplosion plugin;

    private boolean shouldCreeperGrief;
    private boolean shouldCreeperDamageEntities;
    private boolean shouldCreeperDamagePlayers;
    private boolean shouldCreeperSpawn;
    private boolean shouldCreeperTarget;
    private boolean shouldCreeperDamageTamedAnimals;


    public CreeperListeners(NoCreeperExplosion plugin) {
        this.plugin = plugin;
        loadConfigValues();
    }

    public void loadConfigValues() {
        shouldCreeperGrief = plugin.getConfig().getBoolean("creeper-explosion-grief");
        shouldCreeperDamageEntities = plugin.getConfig().getBoolean("creeper-damage-entities");
        shouldCreeperDamagePlayers = plugin.getConfig().getBoolean("creeper-damage-players");
        shouldCreeperSpawn = plugin.getConfig().getBoolean("disable-creeper-spawning");
        shouldCreeperTarget = plugin.getConfig().getBoolean("disable-creeper-aggression");
        shouldCreeperDamageTamedAnimals = plugin.getConfig().getBoolean("creeper-damage-pets");
    }

    // Disables creeper griefing
    @EventHandler
    public void onCreeperExplode(EntityExplodeEvent event) {

        if (shouldCreeperGrief) {
            return;
        }

        if (event.getEntity().getType() == EntityType.CREEPER) {
            event.setCancelled(true);
        }
    }```
lean tangle
#

is there any error you getting?

digital galleon
#

Why are you loading your config values in the initializer?

lean tangle
#

yeah that's too

hexed heart
#

well i was reading the config values in each event

#

then one guy said, thats resource intensive

#

so i did this

#

load it once

digital galleon
hexed heart
lean tangle
#

i don't know but should be fine... i guess

#

have you tried it?

hexed heart
#

yea everything works fine. But is this more "efficient"?

#

whadoyouthink

lean tangle
#

btw i'm just a intermediate, just started coding a little bit

lean tangle
#

lol

digital galleon
#

When Cloudy introduced themselves, it seemed as though they were in the same boat as you. Not sure what you expect them to review.

lean tangle
#

idk about preformance

hexed heart
#

i suck more

hexed heart
digital galleon
# hexed heart then one guy said, thats resource intensive

This is wrong. Each time you invoke .getConfig() you are getting the state of the config that was initalized in memory when the config was loaded to begin with. It isn't reading the file eachtime, if that were the case it would mean that whenever you updated the config, the values would update in realtime, but as we know that's why plugins require reload commands.

There is no difference in just reading from normal memory. And if anything, if you wanted to "pre-initialize" these variables (regardless if it is required or not) why not do it in Main, instead of every listener or an arbritrary listener.

#

Reading from memory is what you do when you retrieve a variable value irrespective.

hexed heart
digital galleon
hexed heart
#

ooh

digital galleon
#

As I told you, who-ever that dev was, is wrong. There is no performance problem.

hexed heart
#

so that guy who said "its better to just read the values once" is dum-

digital galleon
#

Yes because it is already being read the moment the plugin starts. Everytime you run getConfig you arent re-reading the file, you're simply retrieving values from an existing object YamlConfiguration

lean tangle
#

it seemed fine

digital galleon
lean tangle
#

lol

digital galleon
#

He said some other dev told him to handle configuration values like that to save resources

lean tangle
#

oooh

#

ok

hexed heart
lean tangle
hexed heart
hexed heart
#

you said you are an intermediate

#

so you are still learning right?

lean tangle
hexed heart
#

are you watching a tutorial series?

lean tangle
#

i just watched a Java course on youtube and understood the syntax and that's it

#

and bukkit API stuff i search for

lean tangle
hexed heart
#

ohh so you havent started a spigot course

hexed heart
lean tangle
hexed heart
lean tangle
#

i will check it out ty

#

ohhh i know that guy, i watched him too

hexed heart
#

have you made any projects

lean tangle
#

i learne basic stuff from him like listeners and commands and guis

#

sad thing i haven't made any "official" or a finished project plugin

digital galleon
lean tangle
hexed heart
digital galleon
#

What I mean is, I never actually watched any videos, read any books, courses, or sites about Java OR Kotlin.

dense leaf
#

Learning by doing is always the best way but make sure to get some fundamentals in first

hexed heart
lean tangle
hexed heart
#

i once tried "co-learning" with someone i found on a discord server. Literally 1 day later, he went back to playing hypixel bedwars on feather client 24 hours a day

dense leaf
#

using feather client is crazy

lean tangle
#

if you want to learn from someone, don't learn from me lol

hexed heart
lean tangle
#

i just started

hexed heart
#

and his whole motive to learn spigot development was because he wanted to backdoor in his friend's smp

hexed heart
dense leaf
#

I don't even know when I started

#

like 2021?

#

with spigot at least

night knoll
#

I learnt spigot in 2021 because diamondfire is too expensive

dense leaf
#

what's diamond fire

night knoll
#

Block coding

dense leaf
#

oh 💀

#

i remember doing discord bots with shit like that back in like 2019

digital galleon
# dense leaf Learning by doing is always the best way but make sure to get some fundamentals ...

I know you said this a couple messages up, but I was still thinking about this cus I relate to it. learning by following is pointless. I tried to learn python when i was maybe 11?, but I dont think the inspiration and innovation was fully there. I was just following what a guy was writing on YouTube, no ideas of my own and nothing to help me expand my knowledge.

When I eventually revisited it, for a purpose when I wanted to make a program, I found it easier to learn when I had a drive and purpose.

In terms of Java I never actually bothered learning Java when I picked it up, since I already was proficient in C and thus fundamental programming concepts, Java was easy to pick up with never really reading, just had to practice

dense leaf
#

relatable

just that I do NOT want to touch C/C++ again

#

one of retros projects got this treatmnet

lean tangle
#

do you concider yourself an expert?

digital galleon
lean tangle
#

both lol, cuz i have questions

#

stuff on servers i can't figure out how they do stuff

#

like mcc or any server that is like bedrock servers: fancy animations and models

hexed heart
#

they use blockbench to make the models, and bedrock has a lot of support from mojang for these type of stuff

night knoll
hexed heart
#

like theres a plugin in blockbench callled "Entity Wizard" which will compile everything for you and make an "addon" for you

digital galleon
hexed heart
#

"addon" is like the equivelant to mods in java but worse

digital galleon
#

you can add me if you ever wanna ask about plugins or servers though. Although I haven’t made much I do have a good understanding of textures and models and shit.

hexed heart
#

if you wanna make cool animations and models in java, you gotta use a plugin like modelengine which basically translates your models and animations into java edition

lean tangle
#

i want to figure out how they got the animations from just a file and transformed it into a item display and animated it in minecraft

hexed heart
hexed heart
#

when you put the addon in your server files

#

and use the resourcepack, boom

hexed heart
#

modelengine is sort of a freemium plugin

#

i think you can import upto 12 models for free, then you gotta pay

lean tangle
#

i want to recreate it

hexed heart
#

recreate what

#

model engine?

#

owh hell nawh

dense leaf
#

Well I know a good bit about resourcepacks, font fuckery and shadery

lean tangle
#

it doesn't seem easy but...

hexed heart
night knoll
hexed heart
#

'Animated Java' plugin in blockbench

#

which creates a datapack for you

dense leaf
#

Just use AnimatedJava

hexed heart
#

but its not plugins

lean tangle
dense leaf
#

Because it cannot generate a jar

hexed heart
dense leaf
# lean tangle what's that?

It's a blockbench plugin which you can use to create animations, it generates a datapack which you can add, which will add functions and triggers for those animations

lean tangle
#

Ohhhhh

dense leaf
#

?

hexed heart
#

for once i wanna be the guy who can give the answers

lean tangle
dense leaf
#

Why?

hexed heart
#

cuz fun

dense leaf
#

You can just use it anyway

#

I wasn't talking to you

#

A datapack works fine

hexed heart
dense leaf
#

I've used it a lot

#

We were working on Fabric integration for AJ a bit ago, not sure what the state of that is

hexed heart
#

CloudyHI, you are just like me lol. I had these same questions like a few days ago

lean tangle
#

i see it requiring a lot of math

#

like matrix and stuff like that

hexed heart
#

yeah

dense leaf
#

It requires being good at trigonometry and quaternions in general

lean tangle
dense leaf
#

You can't just decide which vertex goes where lmao

#

unless you're doing some stupid fuckery with shaders

#

like really fucking stupid

lean tangle
#

wait

#

does it require shaders?

dense leaf
#

no

lean tangle
#

oh good

#

cuz i don't want to touch those now

#

seems complicated

dense leaf
#

I mean you CAN use them but that would be a stupid ass unstable fuckery shitshow

hexed heart
night knoll
#

Get back to spigot coding fr

hexed heart
#

and you cant do it alone

dense leaf
#

I mean, you can

hexed heart
#

you need more devs in on it

night knoll
dense leaf
#

Magma did it mostly alone afaik

hexed heart
hexed heart
dense leaf
#

Fuck off IJ, parsing a 650 line kotlin file can't be that hard

lean tangle
#

lol

lean tangle
#

and ;

hexed heart
# lean tangle lol

wanna code a plugin together? something simpler than fricking modelengine itself

dense leaf
lean tangle
#

that shows i didn't use it before lol

dense leaf
#

the only place I actually have a ; is in fonts

lean tangle
#

i use Java for now

desert ore
dense leaf
#

Thanks raydan

lean tangle
#

can i paste links here?

dense leaf
#

yes

desert ore
#

yes

hexed heart
#

yes

dense leaf
#

?img

rich fogBOT
#

Can't send images? That's because you're not verified! Use !verify to complete verification.
Alternatively, you can upload screenshots to any image hosting site and share the link.

Here's some screenshot utilities that you can use to upload images.
Lightshot: https://prnt.sc
Imgur: https://imgur.com/upload
Flameshot: https://flameshot.org

lean tangle
#

embeds don't work

#

lol

#

oh ok

hexed heart
#

Cloudy, have you tried tiramisu before?

hexed heart
#

how th did you make that

lean tangle
#

i don't remember actually lol

lean tangle
#

??? whatttt how?

#

this is what i need exactly

#

well maybe but

#

how do you show your mouse without rotating your head? and interacting

#

and can you tell where is the mouse location?

dense leaf
#

you can change a player's camera regardless of their position

lean tangle
#

btw cool textures

digital galleon
dense leaf
dense leaf
hexed heart
#

im gonna go crazy

digital galleon
dense leaf
#

no thanks

lean tangle
#

did you make the textures and stuff?

dense leaf
#

it's extremely simple

#

you just send some characters every tick

#

colour them

#

boom

lean tangle
#

is it just symbols?

dense leaf
#

I had to make textures for these using my sprite system since unicode block symbols apparently don't have a fixed width

lean tangle
#

oh

dense leaf
#

anyway this should really go to #general

lean tangle
#

can i unverify myself?

#

this account name is so old i hate it

hexed heart
#

hello jana7_gamer

lean tangle
#

stop lol

#

it's cringe

dense leaf
#

?changename

rich fogBOT
#

Name changes on the forums are granted to those who have donated to the project. Donations are processed manually and generally take up to 24 hours. The donation widget can be found on the home page of SpigotMC at: https://www.spigotmc.org/.

lean tangle
#

lol

#

so i have to pay???

lean tangle
#

bro this is tooo cringe

hexed heart
#

thank god i chose a normal name

lean tangle
#

sad

dense leaf
#

I mean, spigot is a FOSS project

#

md needs to make money somehow smh

hexed heart
#

poor md

#

i feel bad for him

dense leaf
#

I thought he was a lawyer

#

@alpine anvil please confirm

lean tangle
#

ik but isn't he taking a precentage of payed plugins?

#

but paying to change a username is crazy

hexed heart
#

whats afaik

dense leaf
#

as far as i know

lean tangle
#

oh

alpine anvil
#

He's an attorney, which is close enough to a lawyer

#

Check his LinkedIn if you want confirmation

dense leaf
#

me when I pull up to wolvereness' lawsuit on sploon with md_5 as my attourney

alpine anvil
#

And md takes no money from spigot that we know of

hexed heart
alpine anvil
#

Don't tell voss u said that

dense leaf
#

real

dense leaf
desert ore
#

do you think he charges much

dense leaf
#

no idea

lean tangle
#

what do servers use?

#

item or an entity or what

hexed heart
lean tangle
#

bedrock or modded or optifine

hexed heart
#

i mean what are you trying to make

lean tangle
#

what do model engine use?

#

when you make an entity

hexed heart
#

oh you wanna use model engine?

#

then just create a generic model i think, and upload the .bbm file to the "blueprints" folder in ModelEngine

lean tangle
#

in plugins folder?

hexed heart
lean tangle
#

oh ok

hexed heart
#

you gotta follow some guidelines while making your model

dense leaf
#

#general

hexed heart
#

so your model won't be messed up

hexed heart
lime gorge
#

can someone review code i totally made and wasnt made by an ai and im asking people here to make sure the code is efficient and ddoesnt ruin my server pleaseandthankyou

topaz bronze
#

Ya sure, let me access the hive mind to get it to review 🧠 ⚡️

#

Ya looks good 👍

woeful pasture
#

otherwise hire someone AI can't replace a software engineer

#

this channel is for code review and I highly doubt anyone here wants to review ChatGPT

lime gorge
#

online and in the minecraft forums and on the discord

#

chat gpt was my last resort 😭

#

i dont really like the use of AI but im kinda on my last straws here ngl

#

but understandable

woeful pasture
#

coding is a beneficial skill anyways

lime gorge
lime gorge
woeful pasture
distant gorge
#

Don't mind the error messages

junior holly
#

Wowzers

dense leaf
#

Sigma sigma boy sigma boy sigma boy

#

oh god I haven't even gotten to the error messages

night knoll
night knoll
#
                } catch (Exception e) {
                    sender.sendMessage("Report this to a sigma");
                    e.printStackTrace();
                }```
dense leaf
#

what does that have to do with this thread

lean tangle
#

i have a question, he said in his video at around 5:55 that servers are able to get inputs directly

lean tangle
dense leaf
lean tangle
#

oh ok

dense leaf
muted sentinel
#
        ConfigurationSection dailyConfig = this.file.getConfig().getConfigurationSection(s);
        String requirement = "";

        //Current types
        String typeName = dailyConfig.getString("Type");
        String entity = dailyConfig.getString("Entity");
        String block = dailyConfig.getString("Block");
        String item = dailyConfig.getString("Material");
        
        
        //Check for different types.
        if (typeName.equalsIgnoreCase(String.valueOf(DailyTypes.KILL_WITH_ITEM))) {
            requirement = entity;
        } else if (typeName.equalsIgnoreCase(String.valueOf(DailyTypes.KILL))) {
            requirement = entity;
        } else if (typeName.equalsIgnoreCase(String.valueOf(DailyTypes.DAMAGE))) {
            requirement = entity;
        } else if (typeName.equalsIgnoreCase(String.valueOf(DailyTypes.MINE))) {
            requirement = block;
        } else if (typeName.equalsIgnoreCase(String.valueOf(DailyTypes.OBTAIN))) {
            requirement = item;
        }

        int amount = dailyConfig.getInt("Amount");
        DailyType type = new DailyType(dailyConfig.getString("Type"));

        return new DailyRequirements(requirement, amount, type);
    }```
jagged rock
#

Eh.. no

muted sentinel
#

eh?

jagged rock
#

Can be better

muted sentinel
#

Learning, whats the problem?

jagged rock
#

Let's say I want to add another type

#

I'll have to duplicate code

#

There's no way to do it via API and there's no need for DailyTypes to be an enum

#

The first, simplest improvement we can do (without fixing a flawed structure) is making the association between daily type and config "string"

#

You can do this with a map or you can embed it in your enum

#

(KILL -> Entity, MINE -> Block)

#

If you want a proper structure you can either have a "TypeRequirement" enum/interface (ENTITY, BLOCK, MATERIAL) or make types abstract and have them load their own values from the config

muted sentinel
#

I forgot about interfaces, I did this before. Let me redo some stuff and come back. I thought it was a bit repetitive thats why i came here

jagged rock
#

Repetition means you can abstract it away

muted sentinel
#

I can never find a good use for enums tbh

jagged rock
#

In short you want to make it so any plugin can add custom requirements / objectives without having to fork

jagged rock
#

Interfaces give the flexibility of enums without the drawbacks

#

Only time you want enums is when you want an inflexible structure

desert ore
jagged rock
#

Like for example, ClickType being limited to LEFT, RIGHT and MIDDLE_CLICK

jagged rock
#

That can be an interface

desert ore
jagged rock
#

yeah

#

BrushMode

desert ore
#

it'd make no sense for it to be

jagged rock
#

and you can have a class of constants

#

like BrushModes that just holds all the builtin modes

#

I want to be able to add a paint bucket via API

sly jackal
#

that looks like a rust enum xD

desert ore
jagged rock
#

someone's gonna fuck with it eventually

#

that someone is often me

desert ore
sly jackal
#

the issue is that this mode is not a closed set of things it could be

jagged rock
#

don't make me use unsafe to modify your manager classes to allow custom tools

sly jackal
#

its pretty easily feasible to just add more stuff

jagged rock
sly jackal
#

but then again I am hypocritical since my message translations are done with an enum

desert ore
jagged rock
#

we have a couple enum classes at work

jagged rock
desert ore
dense leaf
#

Those work a lot differently

sly jackal
#

well

#

it looks more like a match on an enum

dense leaf
#

And they also can't have functions or abstract stuff, you have to use a giant match everytime concern

sly jackal
#

syntactically

#

I mean you cant impl an enum, but you can implement traits on them

dense leaf
#

not for specific entries tho

sly jackal
#

right

dense leaf
#

I feel like I should not store a key as string in PDC

muted sentinel
#

Kotlin scares me

dense pond
#

Kotlet

dense leaf
#

I don't really have any better idea though

#

Item sprites only have the key and custom model data as identifiers

#

and custom model data also depends on what item

#

so can't use that for comparison

digital galleon
#

why dont you create a custom PersistentDataType for NamespacedKey if you want to store the full key?

dense leaf
#

I guess I could use the registry idx of the sprite?

digital galleon
#

You have two issues with this:

persistentDataContainer.set(TYPE_KEY, PersistentDataType.STRING, key.toString())

1: when ur converting the NamespacedKey to a string and back, thats just introducing a potential for errors and loses type safety.
2: I think string comparisions are slower than primitive types or direct references comparisons.

Like I said, mayb make a datatype?

object NamespacedKeyDataType : PersistentDataType<String, NamespacedKey> {
    override fun getPrimitiveType() = String::class.java
    override fun getComplexType() = NamespacedKey::class.java
    
    override fun toPrimitive(complex: NamespacedKey): String = complex.toString()
    override fun fromPrimitive(primitive: String): NamespacedKey = NamespacedKey.fromString(primitive)!!
}
dense leaf
#

Yeah I guess I could, but that would still be somewhat inefficient

#

Also that data type would barely change anything fyi

dense leaf
digital galleon
#
persistentDataContainer.set(TYPE_KEY, PersistentDataType.INTEGER, itemId)

?

dense leaf
#

yea

digital galleon
dense leaf
#

persistentDataContainer.set(TYPE_KEY, PersistentDataType.INTEGER, BlockBrawlItems.indexOf(this@BlockBrawlItem)) feels a bit silly considering it assumes that the current instance is registered

#

eh ig I could make teh function open

muted sentinel
#

Okay, after restarting this code i think i got it. First time using enums like this.

public enum DailyTypeEnum {

    DAMAGE(new DailyType("damage"), "Entity"),
    KILL(new DailyType("kill"),"Entity"),
    KILL_WITH_ITEM(new DailyType("kill_with_item"),"Entity"),
    OBTAIN(new DailyType("obtain"), "Item"),
    MINE(new DailyType("mine"), "Block");

    private final String objective;
    private final DailyType dailyType;

    DailyTypeEnum(DailyType dailyType, String objective) {
        this.dailyType = dailyType;
        this.objective = objective;
    }

    public DailyType dailyType() {
        return this.dailyType;
    }
    public String objective() {
        return this.objective;
    }
}```

```java
    public DailyRequirements getDailyRequirements(String name) {
        ConfigurationSection dailySection = this.getConfig().getConfigurationSection(name);
        int amount = dailySection.getInt("Amount");
        DailyTypeEnum dailyTypeEnum = DailyTypeEnum.valueOf(dailySection.getString("Type").toUpperCase());

        return new DailyRequirements(dailyTypeEnum.objective(), amount, dailyTypeEnum.dailyType());
    }```
#

the yml its grabbing from

KILL_ZOMBIE_WITH_AXE:
  Type: kill_with_item
  Entity: zombie
  Item: iron_axe
  Amount: 10
  Rewards:
    Commands:
      home: "/maxhomes {player} 1"```
#

The idea to the enum is to detect what daily type it is and to select which field it needs: kill > Entity etc

#

and that also makes it easier for if i release the plugin for people to add their own daily objectives. by just making a new constant

HUG(new DailyType("hug"), "Entity")```
winged blaze
#

since we like objects and enums maybe String objective could be replaced

#

no need to call your enum class enum

#

but thats just preference

digital galleon
round fossil
alpine anvil
round fossil
#

CoolPluginEntryMainClassJavaClass.kt

alpine anvil
#

CoolPluginEntryMainClassJavaClassKotlinMainPluginClassKt.kt

digital galleon
hybrid osprey
#

.bak

muted sentinel
muted sentinel
#

I just thought it was better than switch cases or if statements

late smelt
#

Registry!

muted sentinel
#

so just using a model pretty much?

#

probably store it in a hashmap

round fossil
#

I mean what you’re doing can be seen as somewhat advanced data driven parsing where the value of one node influences how the data is parsed and used from other nodes

muted sentinel
#

xD

round fossil
#

Ideally you define some interface and then u map “kill with item” | “obtain” | … | etc to an implementation of that interface dependent on what u need

muted sentinel
#

I kinda started this but didn't get nowhere with it.

public interface Types {

    void setEntity(Daily daily, EntityType entityType);
    void setBlock(Daily daily, Block block);
    void setItemStack(Daily daily, ItemStack itemStack);

}```
round fossil
#

Do you want like a skeleton for how I’d do it (more or less)?

#

Anyway enums are cool, they have nice semantics but they are often somewhat too imperative in Java and a lot of the times you benefit from distancing yourself from those, especially since they don’t support type parameters (generics) and enforce recompilation on modification - worth mentioning a lot of java library devs tend to define an interface on top of an enum (letting the enum implement that interface) as to not troll ur future self

late smelt
#

Material.class

dense pond
#

no

dense leaf
#

you literally can't iirc

dense pond
#

😔

dense leaf
#

since it's a primitive?

#

not sure

dense pond
#

final int int40 = 40

dense pond
dense pond
dense leaf
#

is it an actual keyword tho

dense pond
#

if (boolean == true) {
return true;
} else if (boolean == false) {
return false
}

dense pond
dense leaf
#

as in, hardcoded into the compiler

dense pond
#

what

#

idk what u mean bro

#

🐧

#

i dont know about ints

#

i think its an int

#

my friend is angry at java because he has to write boolean not bool

dense leaf
#

after googling I have come to the conclusion that it looks like a keyword

dense pond
#

llooks like an orange font to me bro

dense leaf
#

imagine having reserved keywords for primitives

#

imagine having primitives

#

this post was made by the kotlin gang

dense pond
#

kotlin does not have primitiveS? what

alpine anvil
#

Imagine boxing

dense pond
#

oh

#

what is actually primitive

#

its all bits

#

:p

alpine anvil
#

Always was always will br

dense pond
#

hat

#

whhy is int primitie

#

if its build from booleans

#

😾

#

what does this mean

dense leaf
dense pond
#

its made of bits

sly jackal
#

well more like a boolean is made of ints

#

its not like a boolean only takes up a single bit

dense leaf
#

yea

#

doesn't mean they#re ints

late smelt
#

Everything is made of bits

#

Or more generally bytes

round fossil
woeful pasture
sharp epoch
#

more like the forever practicality

#

I strongly believe quantum computers aren't going to be the next thing, but something else like photonic computing

#

though there's also photonic quantum computing but we don't talk about that

round fossil
woeful pasture
#

I try not to be super speculative about technology because tech likes to prove us wrong

sharp epoch
#

it's fine to be speculative, it feels good to be proven wrong about something you have no expectations and see it actually succeeded

#

when it comes to quantum computing, it just feels like the next nuclear fusion

#

we're just perpetually 30 years away from it

woeful pasture
sharp epoch
#

quantum computing or nuclear fusion? One's been pushing that deadline for a while now lol

woeful pasture
sharp epoch
#

crosing fingers 🤞

woeful pasture
#

I think a year ago or so we gained energy from the reaction excluding all the energy that was poured in lol

#

I remember seeing it all over the news I looked at the science impressive but not power plant impressive

sharp epoch
#

the science of it always looks impressive, it is the results that leave things to be desired

#

besides with such complex pieces, one starts to wonder just how more complex does it have to get in order for it to be actually usable

#

then again, chip processing got to that point where it is unfathomably complex process and it became economically feasible so I won't completely ditch the idea of it just being that complex

dense pond
#

it doesnt?

sly jackal
#

nope

#

that would mean more overhead for storing a single bool

#

usually variables are just in registers with a set amount of space

dense pond
#

oka

dense leaf
#

a boolean uses 64 bits on an x64 system i believe

hybrid osprey
#

boolean size in Java is VM dependent

#

many booleans may be able to be packed into bytes

#

8 booleans in 1 byte

wintry fern
#

Now granted there is nothing requiring jvms to back booleans by an integer or anything else

#

However as for the stack goes it will always take up 4 bytes

muted sentinel
#

ive completely redone this again

#

no enums just classes

#

?paste

rich fogBOT
muted sentinel
#

now im trying to figure this out.

public interface Types {

    void type(Type type);
    void objective(Objective objective);

}```
#

its doing as i want. im just tired of redoing this now

jagged rock
#

If you're willing to get fancy with your interfaces you can do more than that

#

with abstract objectives :)

#

For example, your damage zombie quest would consist of:

  • Quest metadata (name="damage a zombie?")
  • Quest objectives ([type="mob-damage", target="zombie", amount=1])
  • Quest rewards ([type="item", item=ItemStack{DIAMOND x 100}])
#

might be worth looking into the factory pattern

#

types would go into a factory registry

#

I'd do something like

public interface QuestObjectiveProvider {

  QuestObjective provide(MyPlugin plugin, ConfigurationSection data);

}
public class QuestObjectiveRegistry {
  
  private final Map<String, QuestObjectiveProvider> providers = Map.of(
    "kill-mob", KillMobsObjective::new // add more here or rework the class to be a proper registry, im lazy
  );

  public QuestObjective load(String id, ConfigurationSection data) {
    MyPlugin plugin = ...; // DI this or whatever
    QuestObjectiveProvider provider = this.providers.get(id);

    if (provider == null) {
      return null;
    }

    return provider.provide(plugin, data);
  }
}
#

and you can do your objectives however, a quick an easy way is to make them interfaces that register themselves or whatever

#

another way is to have objective types and dedicated listeners for them

#

up to you

#
public class KillMobsObjective extends AbstractObjective {

  private final Collection<EntityType> targets;
  private final int amount;
  
  public KillMobsObjective(MyPlugin plugin, ConfigurationSection data) {
    // load stuff

    subscribe(EntityDeathEvent.class, this::handleDeath);
  }

  private void handleDeath(EntityDeathEvent event) {
    LivingEntity entity = event.getEntity();
    ...
    Player killer = entity.getKiller();
    ...
    addProgress(killer, 1);
  }
}
#

type deal

#

Adding progress can trigger a chain of events that leads to the quest being complete and rewards being handed out

#

Keep in mind this is just one of the ways of doing it, doesn't mean it's the right one

muted sentinel
#

Thanks for this, im going to look into providers because that confuses me.

jagged rock
#

In short KillMobsObjective::new gets converted to an interface

#

Looks a bit like this

#
public class QuestObjectiveRegistry$1 implements QuestObjectiveProvider {

  @Override 
  public QuestObjective provide(MyPlugin plugin, ConfigurationSection data) {
    return new KillMobsObjective(plugin, data);
  }
}
#

And this only works because the constructor signature matches the interface method's

#

Yeeting all these "provider impls" into a map allows us to basically create an instance of whatever subtype we want based on a string input

#

Meaning
"kill-mobs" -> KillMobsObjective
"mine-blocks" -> MineBlocksObjective

muted sentinel
#

So registery is pretty much your own hashmap system in a sense.

jagged rock
#

It uses a map

#

But it doesn't map "A" to "B"

#

It maps to an interface that creates a new object of a given subtype

#

And it's an interface because we need different parameters for different quests

muted sentinel
#

I took a glimpse at somebodys explanation on youtube and was like huh so a model with a map? xD

jagged rock
#

kinda

#

As long as your interpretation of it makes sense, sure go with it

muted sentinel
#

still very new to to programming. so anything thats not hashmaps and basic stuff is foreign to me

jagged rock
#

Yeah this is a little advanced

#

I do abuse it quite a bit :)

muted sentinel
#

yeah you can explain it like a champ so i guess you know this pattern xD

#

so if i do it this way i gotta restart all this again xD

jagged rock
#

It happens, that's the process of learning

muted sentinel
sly jackal
#

using System.out is -1 point

round fossil
#

It’s barely acceptable

sharp epoch
#
  1. You didn't seem to use a build system either, take a look at maven or gradle, that will help tracking dependencies of your projects so people aren't left wondering what you use on it
muted sentinel
#

Yeah i was using intelij and for some reason its messed up

round fossil
#

He is using maven

muted sentinel
#

im using maven

round fossil
#

the pom is just not at root

sharp epoch
muted sentinel
#

yeah for some reason intelij and github doesn't wanna connect so i just gave up and copied the files over

sharp epoch
#

well other than that, there are some minor things like using sysout for logging and naming a class "File", but it looks fine logic wise

muted sentinel
#

Idk what else to name it lol\

sly jackal
#

dailiesFileReader or something

sharp epoch
#

it seems to manage the dailies configuration so just DailyConfiguration or something

sly jackal
#

though atm the abstraction seems a bit pointless since all the work is being done in DailyFile now anyways

sharp epoch
#

the reason File is a bad name is simply because it isn't descriptive of what the class does at all, and it conflicting with the JDK's File class name only makes that worse

#

but if it is just going to be used for this project, it's eh, not the end of the world either

#

just not a good rule of thumb

#

the comments in the classes also lead me to believe you used AI to some extent to generate code, which is fine if you take the time to understand what it is doing but I strongly recommend not just mindlessly copying the files when learning otherwise you're not going to progress much

sly jackal
#

what comments

sharp epoch
#

the ones in the DailyFile class

sly jackal
#

oh

#

doesnt really look like AI to me

#

I make comments like that all the time

#

maybe I am an AI 💀

sharp epoch
#

it could be either way nowadays honestly, I might be reading too much into it however the advise still applies

sly jackal
#

yeah

muted sentinel
#

I've redone this part 3 times, i first did it in dailyManager and was like that isnt right because DailyFile should know its own contents because i just did stuff like

public String getString(String s) {
this.file.getConfig().getString(s);
}

AI is pointless for beginners. @woeful pasture taught me that awhile back.

#

At this point i've learned almost everything from this discord and by trial and error.. I appreciate everything everyone has taught me. i took that and been redoing my main plugin for awhile

round fossil
#

That’s good, I do think AI can be helpful in explaining concepts etc, but you’re always in for a ride if you go down that route - sometimes AI is just gonna mega troll you no skibidi

random yacht
#

never say that again

muted sentinel
#

wtf is that even a saying...

digital galleon
#

Anything that could be imrpoverd here?

    private void yeetTheOhioCheck(Player frfr) {
        if (frfr.hasPermission("brainrot.ohio")) {
            giveAura(frfr);
        }
    }

    private void giveAura(Player noCapPlayer) {
        noCapPlayer.setGlowing(true);
        getServer().getScheduler().runTaskLater(this, () -> {
            noCapPlayer.setGlowing(false);
            noCapPlayer.sendMessage(ChatColor.AQUA + "skibidi aura just got real quiet");
        }, 200L);
    }

    private void rizzCheck(Player respectfully) {
        if (Math.random() < 0.5) {
            respectfully.sendMessage(ChatColor.GREEN + "NO CAP YOU GOT THE RIZZ FR FR");
            giveSkibidiEffect(respectfully);
        } else {
            respectfully.sendMessage(ChatColor.RED + "NAH BRO YOU GOT NEGATIVE RIZZ, BACK TO OHIO");
        }
    }
    
    private void giveNegativeCanthalEffect(Player canthalPlayer) {
        canthalPlayer.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 400, 1));
        canthalPlayer.sendMessage(ChatColor.GRAY + "That negative canthal tilt got you slowed, bro.");
    }
woeful pasture
# digital galleon Anything that could be imrpoverd here? ```java private void yeetTheOhioChec...

Instead I will now review your 5 month old code from this repository https://github.com/abb3v/Anvil

Overall the project isn't horrible, however I have a couple nitpicks, one the project name makes very little sense. The name "Anvil" Doesn't really tell us what its doing, until I read the code I had no clue this was a silk spawner mod. Pesronally not a huge fan of gradle groovy but that's okay I guess. Another thing is if you're going to have a mod maybe you should update it. your minecraft version is 1.21 things have changed a decent amount. I wonder about the necessity of BlockAttackHandler considering how little is done I really don't see the point of not just making it inline. Also not a huge fan of the hardcoded message I see in there, this really isn't friendly to users who don't speak english. Seeing as you're using the Fabric API why not use their EnchantmentHelper.getLevel(enchantment, itemStack) method which returns 0 if the item isn't present. The appearance of hasSilkTouch and hasFortune really makes no sense you could probably get rid of this entire class too be completely honest.

GitHub

Anvil: Because Some Things Are Just Too Precious to Smash! - abb3v/Anvil

digital galleon
#

screw you 😭

#

Why did you go digging through my profile just for that

#

Anyways, the name & Tagline is AI generated.

woeful pasture
#

okay idc

woeful pasture
# digital galleon THIS IS HORRIFIC

think twice something constructive will be reviewed whether you like it or not, its the way the world works. You come to a code review channel you get a review you don't have to like it

digital galleon
woeful pasture
#

I'm just a troll aqua_salute

digital galleon
#

I'm going to be honest. I never learnt Java. I only learnt java to contribute to Meteor Client. I only really have programmed in C before.

My friend asked me to build a mod that would prevent them from accidentally breaking spawners on an SMP, so I made that shit in under 30mins. I literally NEVER touched Fabric before or after that.

woeful pasture
#

okay back to watching anime I wish you had more recent projects what's with all the forks bro

woeful pasture
#

do you like only do embedded systems

#

and kernel dev??

digital galleon
woeful pasture
#

meanwhile my arduino rots in my drawer :*(

digital galleon
woeful pasture
#

I've not touched fabric in my life lol I'm not fit to like actually review a fabric mod

digital galleon
#

When I made that Mod, I was planning on making an Options UI, where you could set it to prevent or Warn, and change the messages, but I wasnt bothered learning lol.

digital galleon
#

I do have more recent projects

woeful pasture
#

yeah you forked a couple repos the past few weeks

digital galleon
#

Yeah cus I contributed back

#

and also, im not sure, is it safe to delete a repo after the PR is merged?

woeful pasture
#

that's what I usually do unless I frequent contributions

digital galleon
#

gotcha

hybrid osprey
#

gitlab's merge request page even has a 'delete source branch?' option so yes it's fine

dense leaf
#

I usually don't in case I will ever need it anymore

winged blaze
#

Just gotta do bytecode fuckeru

dense leaf
#

eclipse

winged blaze
#

Because obfuscators do that

desert ore
dense leaf
#

they also just rename it fyi

random yacht
dense leaf
#

🙏

alpine anvil
random yacht
#

Been there. Done that

dense leaf
#

You were the person who banned him!?

#

love you

alpine anvil
#

do it again

random yacht
#

Wasn't me. But we are a collective

dense leaf
#

aw

alpine anvil
digital galleon
#

seriously? 😭

random yacht
#

No I tease :p

digital galleon
#

You're edging a ban

sly jackal
#

edge === tease

#

but it sounds edgier

digital galleon
#

You could mayyybeee try to cut down on ARMOR_EFFECTS.put("Blaze", new PotionEffect[]{ by instead making an enum

#
 Map<String, Object[][]> effectsData = Map.of(
            "Blaze", new Object[][]{
                {PotionEffectType.FIRE_RESISTANCE, 0},
                {PotionEffectType.SPEED, 0},
                {PotionEffectType.RESISTANCE, 1}
            },
            "Iron", new Object[][]{
                {PotionEffectType.SPEED, 0},
                {PotionEffectType.REGENERATION, 1},
                {PotionEffectType.STRENGTH, 2}
            },
            "Slime", new Object[][]{
                {PotionEffectType.SLOWNESS, 0},
                {PotionEffectType.JUMP_BOOST, 0},
                {PotionEffectType.JUMP_BOOST, 1}
            },
            "Silverfish", new Object[][]{
                {PotionEffectType.SPEED, 0},
                {PotionEffectType.STRENGTH, 0},
                {PotionEffectType.HEALTH_BOOST, 3}
            },
            "Chicken", new Object[][]{
                {PotionEffectType.SLOW_FALLING, 0},
                {PotionEffectType.SPEED, 0},
                {PotionEffectType.STRENGTH, 1}
            }
        );
hybrid osprey
#

I wouldn't consider this an improvement

digital galleon
hybrid osprey
#

How is it removing anything repeated?

#

It's the same number of lines but with less type safety

#

and more memory

digital galleon
#

I meant, it reduced the time needed to write it

#

You wouldnt have to do:

new PotionEffect(PotionEffectType.xxx, inf, 0, false, false),
                new PotionEffect(PotionEffectType.xxx, inf, 0, false, false),
                new PotionEffect(PotionEffectType.xxx, inf, 3, false, false)
        });

you could have a method do that, which iterates over an object.

#

But you're right about the memory and typesafety and I apolgoize.

hybrid osprey
#

you're taking DRY too far with this

#

I'm sorry to say

digital galleon
#

I understand!

hybrid osprey
#

anytime you see yourself using Object, maybe you're not doing it well

digital galleon
#

lol thanks, I take your feedback

hybrid osprey
#

and also 2D arrays are just ew

#

in general

#

nesting data like that indicates you might want to flatten it

round fossil
dense leaf
#

Records

bronze crag
late smelt
#

Use try-with-resources

#

Also use PreparedStatements

round fossil
#

Lombok ❌

dense leaf
bronze crag
#

Why

#

I get that it's confusing to use lombok for fields access modifiers, but what's the problem with lombok itself? I think getters and setters annotations are very handful sometimes

alpine anvil
#

just use PotionEffect?

gilded gate
novel meteor
#

iirc InventoryHolder should not be used

rancid fern
#

?gui

woeful pasture
#

As The Inventory guy you know I gotta say something. If you want an example on how to NOT implement Inventories in spigot its this. Please leverage the ideas of this thread. If you were on a later version you could use the new MenuType and MenuType builder API, but if you're outdated atleast just do a proper wrap job. If you're interested why InventoryHolder sucks so much look here.

Wouldn't it be smarter to allow players to have the option to do multiple quests at once? This seems awfully limiting.
Further based off the last point this entire manager is kinda limited with what kind of features it allows.

I personally don't love QuestType as an enum. I feel like you could implement some logic in each QuestType to help for example knowing what event each quest type should be handled on more dynamically.

ConfigUtils is a bad name IMHO this is more a config wrapper than anything. Utils, to me, gives the indication there are common static utility methods being used, that's just not the case.

Not sure what Type, is but it either needs to be scrapped or just be given a better more inutitive naming. Maybe NPCType? Also not a huge fan that this is an Enum either this could be dynamic registry loaded from a config file easily

Use components with Minedown / MiniMessage or support hex you're in 1.16.5 we have hex support on that version https://github.com/Psikuvit/BetterQuests/blob/master/src/main/java/me/psikuvit/betterQuests/utils/Utils.java#L17-L22

Overall in my opinion the code you have isn't dynamic enough its very explicit, which is fine if you have no plans to ever release it and only use it for yourself, but the minute you release a plugin I feel like such a design becomes unsatisfactory.

gilded gate
#

tell me what you would do in this situation

novel meteor
gilded gate
rancid fern
#

Then what are you talking about

jagged rock
#

If you're repeating code and it can be a config let the end user repeat themselves

bronze crag
#
Point point = Point.measurement(getName())
    .time(System.currentTimeMillis(), WritePrecision.MS);

Thread.getAllStackTraces().keySet()
    .stream()
    .map(thread -> thread.getState().name())
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
    .forEach(point::addField);```
muted sentinel
dense leaf
#

in your player data, I'd recommend not splitting the getters and setters

#

same applies to the managers

#

MessageHandler should just be a util class

#

in your sendCentredMessage you're hardcoding some magic numbers and assuming the player uses the default font which isn't ideal

#

and don't have SCREAMING_SNAKE_CASE locals pls, that naming is reserved for statics

muted sentinel
muted sentinel
muted sentinel
muted sentinel
muted sentinel
#

Alright i just pushed a lot to that repository. hows it looking?

round fossil
round fossil
muted sentinel
untold jay
#

Should I break this big class into separate classes

#

What I did was have the manager (this class) connect all the other classes and provide high level methods

sly jackal
#

seems fine

#

its not very big

dense leaf
#

i love how hastebin thought that's kotlin

sly jackal
#

hastebin is mentally ill

dense leaf
#

true

red bison
untold jay
junior holly
alpine anvil
#

why are all registries freezeable

junior holly
#

Well you don't have to freeze them

alpine anvil
#

yeah but the option is there

junior holly
#

Yes ofc

alpine anvil
#

what if i dont want someone to freeze my registry

junior holly
#

You should probably make that known

alpine anvil
#

what if they dont care and freeze my registry

junior holly
#

Get fucked ig 🤷

alpine anvil
#

that sounds like design error

junior holly
#

Tell me ebic!

alpine anvil
junior holly
#

You think I should instead make FreezableRegistry type?

alpine anvil
#

yuh

junior holly
#

mmmkay

alpine anvil
#

seperate it out so if you want a freeze able registry it gets defined on the type

#

which means someone cant just break your registries for fun

junior holly
#

sounds better indeed

late smelt
#

I’ll find a way to break them anyway

#

For fun

junior holly
#

How. Rude.

alpine anvil
#

now pull a mojank and force them frozen after creation

junior holly
#

kek

#

was thinking about that actually just cuz I was meme-ing earlier with this design

woeful pasture
junior holly
#

there is

woeful pasture
#

its probably "less good" I usually prefer making some Holder or Option esque object to return because java's base one is trash

#

generally the point is to force you to handle it in some way

junior holly
#

Is there a difference between just using a boolean and making a registryLifecycle object as you did?

woeful pasture
#

and then you have the frozen state

#

I used an enum here, but you could also do this with a singular byte

junior holly
#

Idk I guess I kinda just figure no operations should be allowed when frozen, but in your case it sounds a bit more usecase specific

#

To be fair though, this system I was trying to keep simple

woeful pasture
#

this would happen durring bootstrap for my game files, but during "additions only" for any modifications

junior holly
#

right yeah that makes sense

#

The holder is a sort of object wrapper?

#

Is this for like type safety or what

woeful pasture
#

not for type safety

#

in my case its just a "hey handle this you have to"

junior holly
#

I see

round fossil
#

well from mojangs pov they use the entire holder thing a bit more motivated

#

its in combination with dfu where data transformation optimizations and difference between data is being decoded and encoded

#

then knowing if a certain value persay is registered or not, becomes crucial for both the client and the server

#

iirc there's 2 types of holders mainly, those that are contained in the registry, and those that aren't

random yacht
#

Correct

#

You can have a holder that contains a type that does not exist in the registry

junior holly
#

I was thinking of splitting the RoundQueueManager logic as I'm handling both player and round queues, but the actual round queue isn't heavy in terms of operations performed so I'm not sure if it matters...

#
public RoundQueueManager() {
        this.roundHandler = NDGManager.getInstance().getRoundHandler();
        this.queuedRounds = new HashSet<>();
        this.playerQueue = new HashMap<>();
        for (Division division : Division.values()) {
            this.playerQueue.put(division, new HashMap<>());
        }

      // This wasn't supposed to create a new dataManager instance 
        this.playerDataManager = new PlayerDataManager();
      // Changed to:

        this.playerDataManager = NDGManager.getInstance().getPlayerDataManager():
    }```
hybrid osprey
#

ha ha

bronze crag
#

Is it fine to do that with mongo iterables?

#

I mean to cast like that

bronze crag
dense leaf
#

what kind of fucking theme and font is that

remote kiln
#

uh don't worry about that, people always tell me that

#

I also use fucked theme

#

I guess they just don't understand

#

I use eclipse theme in intellij, it's op

muted sentinel
#

fuck replied to wrong one, oh well

red bison
#

At least he doesn’t use comic sans

earnest cloud
#

heheheheh

#

who want revie my code

woeful pasture
earnest cloud
woeful pasture
#

Git is an important tool

earnest cloud
#

Or what'

#

Btw I will create new repository

#

I was do with this many times

woeful pasture
#

not source files

#

it looks like you maven published your content to github

earnest cloud
#

Alr

desert ore
alpine anvil
#

Doesn't use kotlin gradle and uses jitpack not @dense leaf rep

dense leaf
#

🔫

desert ore
digital galleon
dense leaf