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

1 messages · Page 3 of 1

round fossil
#

I mean create as many as you have to create shrug just dont over create

rough hound
jagged rock
#

404 - Private repo probably

#
  • Missing readme file, lack of documentation
  • You shouldn't post your .idea folder
  • RiddlesFriendMain is a weird class name for your plugin entry point, I'd call it FriendsPlugin or RiddleFriendsPlugin
  • Your plugin class isn't a data class, you shouldn't be tracking friend requests and friend data there
  • You should split your command logic into a separate command class
  • You shouldn't hardcode your messages
  • You should use the player UUID rather than the player name in your maps and operations
  • You should make your sounds configurable
  • On your FriendRequestManager, don't expose a mutable list, rather return an immutable copy, or an immutable empty list (ImmutableList.copyOf, Collections.EMPTY_LIST)
  • You don't use the FriendData or FriendRequestManager classes
  • I'd split your IO in a separate class
pine grail
#

Summed it up perfectly

hexed agate
#

posting .idea is fine for a subset of the files in it, such as just a few IDE settings, but most of the files shouldn't be pushed true

pine grail
#

missed most of that (just generally skimmed trough)

jagged rock
#

For commands, you should further work on a subcommand system, or try out a command framework, but also re-use variables like args[0]

pine grail
#
switch(args[0].toLowerCase(Locale.ROOT)) {
  case "a" -> a();
  case "b" -> b();
  case "c" -> c();
}

reposting here from #general, you can also use switch statements

jagged rock
#

Good points for a first plugin:

  • Decent variable naming
  • Splitting stuff into methods
  • Guard clauses, little nesting
  • No static abuse
  • Good usage of try-with-resources
#

I'll remove a point for using JSON over the industry standard YML

pine grail
jagged rock
#

I'm old-fashioned personally and don't like records but eh

pine grail
#

They are useful for data that won't mutate

#

makes it much easier to not care about boilerplate for immutable dataclasses

jagged rock
#

lombok clown_2

pine grail
#

no

hexed agate
#

that is a lot of fucking modules

pine grail
#

pick one

#

they have all the same quality lmao

hexed agate
#

ill pick a random one and look at it but im not looking at them all

pine grail
#

yeah no

#

do that

#

like pick just one

#

98x java files, 6,652 LOC

hexed agate
#

looks fine to me after just some light looking but i see some system.out.println in there which earns you a kekpoint

pine grail
#

yeah quick debugging

#

which module

pine grail
#

ah yeah I am working on that stuff still

#

It doesn't want to load the markers lmao

hexed agate
#

well looks okay to me but i didn't read it like a book just skimmed around

pine grail
#

yeah

hexed agate
#

i'll look deeper later maybe if i have time

pine grail
#

ye sleep

jagged rock
#

I'll remove points for not making your own classes for built-in annotation processors on your config system

#

and rather using lambdas

pine grail
#

wdym?

#

ah

jagged rock
pine grail
#

Yeah

#

They where one liners and I forgor to move them

#

Currently at -1 points

jagged rock
#

Not a huge fan of reflections so I won't look into this further

pine grail
#

Yep, I realized this system is completely flawed

jagged rock
#

Alright I really hate your debugging module

pine grail
#

Oh yeah that one

#

wanna know why I made it

jagged rock
#

no

pine grail
#

nice

#

Points: -2

jagged rock
#

isn't this technically unsafe

pine grail
#

where is that

jagged rock
#

debug reporter

#

upload to hastebin

pine grail
#

ah yeah

#

I hacked that class together because I needed to get smt out fast

jagged rock
#

like if it just returns a 404

#

or something

pine grail
#

nope

jagged rock
#

invalid urls yada yada

pine grail
#

that's checked above

jagged rock
#

ok ok

#

wtf is this

pine grail
#

It returns the version of spigot core being used (it's shared across all modules)

jagged rock
#

alright spawned entities

#

I hate this already

pine grail
#

The entity module?

jagged rock
#

yeah

#

I'd rename Entity -> AbstractEntity to avoid conflict with bukkit's entity

pine grail
#

fair point

#

I should also rename Item

jagged rock
#

I don't like how often you call getProvidingPlugin so I'd probably just have a variable somewhere and reuse it across the entire module

#

this could be switched with a more functional approach

#

For example, a ClickAction enum

pine grail
#

Hm?

jagged rock
#

and a registerClickAction(ClickType.RIGHT_CLICK, (context) -> {});

#

type deal

pine grail
#

Oh yeah

#

that would work

jagged rock
#

this never makes it clear if you're spawning the entity parts as well

#

Or what

#

I might be tripping

pine grail
#

No no you're right

jagged rock
#

bad naming

#

This system could be adapted for packet entities as well, so this could be named BukkitArmorstandEntityPart

pine grail
#

Yeah should've been ItemEntityPart

jagged rock
#

or something

jagged rock
#

And then a PacketArmorstandEntityPart in the future

#

So you could then do a BukkitDisplayEntityPart

#

etc etc

#

you get the idea

pine grail
#

Yep I agree

jagged rock
#

ItemSelector is a bit nifty

pine grail
#

how so

jagged rock
#

Not a fan of how you're hardcoding next and previous to be final

pine grail
#

yeah those are defaults

#

they can be overridden

jagged rock
#

For example, on some menus I've made, if you were in the first page you don't have a previous button and it is another item

pine grail
#

nvm you can't set them

#

got the wrong class lol

#

oh no you def can, but yeah it should be like an item stack provider

#

and not a final item

jagged rock
#

I'd rather make a MenuElement interface with impls such as Button (itemstack / supplier), Switch (multiple items, each has its element) etc

#

and nuke the itemselector class in favor of switch

pine grail
#

Oh yeah

jagged rock
#

SelectionConverter could be useful for the multiswitch but eh

#

I'd only give menu context to my elements on the getItem function, maybe..

#

ItemSelector shouldn't be responsible for managing its own screen

#

unless your Screen is my MenuLayer

#

even then, icky

pine grail
#

👍

jagged rock
#

ScreenPaginator in every screen? fuck no

pine grail
#

what

jagged rock
#

Just make a layer system with a SimpleLayer and a PaginableLayer

willow bone
jagged rock
#

this is too cursed for me

#

and has nothing to do with skyblock

willow bone
#

Wdym

#

🗿

sly jackal
#

apart from the name, there is nothing in here to make you believe its skyblock

#

could be for any rpg like plugin

#

I think thats what illusion means

#

im not really a fan of the static lists you have for mobs and items, etc

sly jackal
#

I would just use DI if you can

#

you wont be needing those lists in a ton of places I reckon

round fossil
#

Don’t use sysout to log stuff

night knoll
#

Custom async B)

#

After 69420 jvm crashes...

cobalt trellis
#

JVM crashes? What the hell...

#

Ah probably stuff in native space

opaque plover
night knoll
#

Yup

opaque plover
#

I've never seen something so cursed that I also loved so much

surreal peak
#

god dammit is that lua?

night knoll
#

ofc

opaque plover
rough hound
surreal peak
#

return friendData.containsKey(player) && friendData.get(player).contains(friend); ee two lookups

pine grail
cobalt trellis
#
cobalt trellis
pine grail
cobalt trellis
#

However it is still better to use UUIDs over Strings.

surreal peak
cobalt trellis
surreal peak
#

just check for null, youre not reusing it

cobalt trellis
#

Furthermore you may want to replace all mentions of /friend with the respective alias that was used to invoke the command, just in case the server owner defined an alias via the commands.yml file or even overwrote the command (which can be necessary in case of plugin conflicts)

cobalt trellis
#

Well you could still have a null check, but the isEmpty check is still required

rough hound
round fossil
#

3 classes isnt a lot

rough hound
#

huh?

round fossil
#

To what extent do you want feedback?

rough hound
#

at my code, cuz I'm new to programming plugins

round fossil
#

Is there anything in particular you’d like me to look at?

rough hound
#

just the overall structure if theres anything I can improve on, maybe my DatabaseHandler and FriendDataCache, I have 34 warnings and idk why

round fossil
#

Perhaps start by going through then lol

#

Your DataBaseHandler isn’t a handler

#

Its called Database not DataBase btw

#

You can turn it into a record btw

#

Your FriendDataCache isn’t a cache

#

You just directly talk to mysql everytime

rough hound
#

huh? isnt that the point of the cache, to relay to the database

#

and the handler connects to the database while the cache relays info the database?

round fossil
#

Nah, I mean when we talk about cached data, we mean data that’s stored somewhere where its fast and easy to access

#

Database calls take time, a lot of time and are heavily io intensive

#

So if it were a cache, it would be that you store the data accessed from mysql in some sort of Map or List, or other data structure during the runtime of the server

#

In that way its accessible and fast to access

rough hound
#

ahh, so my class names are irrelevant then to what I coded

round fossil
#

Ugh well

#

I’d rename it to MySqlStorage

sleek shard
#

hi concLUBE how are you

round fossil
#

And DatabaseCredentials or sth

round fossil
sleek shard
#

im good just chillin

round fossil
#

nicee

rough hound
#

understood!

#

Overall how is my code?

round fossil
#

Its decent

#

I mean obviously you should probably learn the object oriented paradigm in java if you now code in java

#

That means Object Orientation, read Effective Java, learn SOLID, learn a bit about Functional Programming in Object Oriented Fashion, learn a bit about the Data Oriented Programming paradigm, and learn how to deal with concurrency in Java

#

Now that’s a lot of stuff

#

So don’t go on and learn everything I just mentioned

#

But pick something, and try to implement it in your code (:

rough hound
#

thank you for the feedback

lunar vale
#

the class extending javaplugin should be NamePlugin

cobalt trellis
#

Meh not necessarily

willow bone
round fossil
#

No that’s actually a good point @lunar vale has

jagged rock
#

Yeah I do it all the time

#

better than calling it "Main"

round fossil
#

Since its a derivative of JavaPlugin, where the common term is Plugin (it even appears in the superclasses of JavaPlugin), similarly people do this with different types of exceptions, Exception -> RuntimeException -> IllegalArgumentException etc

jagged rock
#

I'll also add that it should be the only class in that specific package

#

or have its own package

round fossil
#

Good rule of thumb also

jagged rock
#

For example

#
  • Don't name your listeners package "events", that implies that's where the custom events are
  • Don't bury important classes deep into packages, they should be intuitive to find if I'm just skimming through the folders
round fossil
#

There is also a good name convention that packages are to be named singular

#

Just look at the std lib

cobalt trellis
#

My main classes are usually called Name

#

Except for Presence where it is called PresenceBukkit, even though it doesn't run on bukkit.

sly jackal
round fossil
#

That’s extremely abstract

pine grail
#

settings

#

ofc

round fossil
#

But for instance if you have a package of utilities you call the package util, and for commands you call it command etc

night knoll
#

SpigotMC#

#

SpigotMC++

#

SpigotMC

#

‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ A
S
S
E
SpigotMC
B
L
Y

#

Spigot is a multi-language minecraft server 😎

#

Btw, I've made some trashy command execution for a json database engine I've made
https://github.com/KarmaDeb/KarmaAPI2/blob/master/KarmaAPI-Core/src/main/java/es/karmadev/api/database/model/json/JsonConnectionExecutor.java

Any suggestion about improving it?
(other than simplifying and splitting into methods, which I'm currently working on)

GitHub

KarmaAPI2 is the new version of the KarmaAPI. Contribute to KarmaDeb/KarmaAPI2 development by creating an account on GitHub.

jagged rock
#

ow what the fuck

night knoll
#

Yes

jagged rock
#

there's a lot of room for improvement

#

thinking of a Map<String, Predicate<String>> comparators

#

and some other stuff

#

not a fan

night knoll
#

Wait, how could I use predicate instead of patterns for it?

#

No way, I just realised

#

You are right

#

Anyway, there're some things I still need from Pattern, such as grouping

round fossil
#

And use named groups

#

Because you have so many

night knoll
#

Oh, completely forgot naming groups was a featur

#

Anyway, any other recomendation or bad practice that I'm doing?

round fossil
#

There is a convention that a regex should be as strict as possible

#

So that ofc means avoid wildcard matching if possible

#

mainly because regex that matches against a lot is easier to break, since there are plausibly more edge cases around that pattern

#

(Tho this is mostly important if the regex is used to match end user input)

willow bone
#

perfect

round fossil
night knoll
night knoll
#

but I would like some help with organizing this and would like some opinions

woeful pasture
#

public static CharacterWar getInstance() {
return JavaPlugin.getPlugin(CharacterWar.class);
}

#

Don't ever get instance like this

#

If you're going to use q singleton do it properly

private static CharactarWars instance

onEnable()
 instance = this
night knoll
#

that's how I used to do it

#

but idk I think I've seen a forum saying u could do that too

woeful pasture
#

That's how it should be done if you're going to use the main clas sas a singleton

night knoll
#

but what's bad about it

woeful pasture
#

Whoever said that on the forums is an idiot

#

I'd have to pull up source but iirc it uses reflection

#

Forget how that's stored exactly but it'll always be better to do it the way I provided

night knoll
#

What if it's just a map of class and instance

woeful pasture
#

Still would be better to use the way provided above

pine grail
#

it gets the classloader of the provided class, checks if it is a plugin class loader and if it is it gets the stored plugin instance

night knoll
#

ok

woeful pasture
#

public boolean itemIsSimilar(ItemStack itemOne, ItemStack itemTwo) { foe this method in AbstractCharacter don't replace the item with air if it's null if you know either one Is air just return false. The method doesn't seem like it's in the right place to begin with though it should probably be in a utility class

night knoll
#

ok

woeful pasture
#

You also really shouldn't be comparing items with display name you should be using PDC

night knoll
#

I'm not gonna remove the null part

woeful pasture
#

?pdc

night knoll
#

cause bukkit api is inconsistent with AIR and null

woeful pasture
#

That is true but you can remove the assignment to air and still ensure the end method contract is the same

#

public void registerCharacter(Character character) { try { in this method don't try catch class cast exception. You can just do an instance of check. Or better yet if every character will have a listener have interfaceCharacter extend Listener instead of having AbstractCharacter implement it

night knoll
#

it doesn't make sense for Character to extend it tho

woeful pasture
#

It does based on how that method works

#

You're throwing if it's not a listener

#

If it's not unexpected do instanceof and don't throw an exception

night knoll
#

I thought about splitting the Character where Character is like the information class, and then it also had a CharacterItemSet where it implements all the items

night knoll
#

@woeful pasture

#

what do you recommend doing on getting the pdc

#

cause each every will trigger and try to filter the pdc

#

so there's going to be like 50 characters all loading the pdc and only 1 of them does the actual functioning

woeful pasture
#

The change in performance is negligible

night knoll
#

no I mean like

#

lets say I have 50 characters

#

and each one of them is a registered listener that all get the pdc in the event

#

that's getting the pdc 50 times

woeful pasture
#

It's no worse then getting the display name 50 times

#

Though slightly higher memory overhead which is negligible on modern systems

night knoll
#

bro

#

im saying

#

im not comparing the two

#

im saying will my server lag if I do that

woeful pasture
#

You also shouldn't need to grab the PDC for every character it should be done in O(1) operation you need to know which character a given player has equipped

#

That way you're not filtering 50 characters instead your simply doing it once for the character you know it is

night knoll
#

people can mix and match the character item pieces

woeful pasture
#

the way you represent your data is then misleading and not ideal. You'd really want a some data structure of Custom Items rather than doing something like a Character interface.

You can represent this data by making some form of registry.
Map<KeyValue, ItemData>

To further expound. You really should be handling these items like Custom Items rather than a complete set if they can be mixed and matched. Each ItemData can have a handle for an event. Note you really shouldn't register these as event handlers rather call them when they're needed within a core listener for example

public onEquip(PlayerAmrmorEquipEvent event) {
  key = event.getPlayer.getHelmet().geOurSpecialKey();
  OurItemCache.getItem(key).callEvent(event);
}```
#

in this case you could likely get away with only using a String for the KeyValue and just putting the given string in PDC

#

then you have a constant key which holds the item ID

#

e.g. item-id = speedy_boots or item-id = wings

night knoll
#

alr

#

but how should I pass the event over

#

here's what I was thiking

woeful pasture
#

check updated message above

night knoll
#

oh

#

yeah that was how I thought about doing it

woeful pasture
#

just note that the above code is sudo code so it won't work

night knoll
#
class CustomItemEventAdapter {
  public void onDamageEvent(EntityDamageEvent event) {
  }
}

#

and should I just have all the events

#

wait what

#

u can use .callEvent

#

wtf

#

never knew that

woeful pasture
#

no no

#

lol

night knoll
#

oh

woeful pasture
#

Its sudo code it won't work

night knoll
#

I think Java Discord API does that

woeful pasture
night knoll
#

@woeful pasture

#

The CustomItem class should also have a .getItem() right

woeful pasture
#

it should return a copy of whatever your base item would be

#

ItemStacks are mutable so it has to be a copy

night knoll
#

@woeful pasture

#

bruh

#

do I need to dependency inject my namespaced key

#

to all the items

woeful pasture
#

wtf no, what are you even doing you can just create Namespaced keys on the fly

#

tbh I'd save them as static variables

night knoll
#

k

night knoll
#

I use PDCs now, and each item has their own class for their own impl

#

Things I will be doing so dw abt them:

  • Documentation
  • Command API
  • Maybe configurable messages
willow bone
willow bone
sly jackal
#

dependency injection

#

?DI

#

I guess commands dont work here

rancid fern
#

?di

rich fogBOT
sly jackal
#

oof its case sensitive

willow bone
#

I don't really save mobs in a list

#

I save their constructors

#

and same for items

#

The mobs's NMS implementation implement a custom interface to get the SkyblockMob class

#

I don't use mappings of MOBS to UUIDS or any bs

night knoll
#

please

night knoll
#

middle

#
  • depends
jagged rock
#
  • Don't expose mutable collections (CharacterManager#getCharacters should expose an immutable copy)
  • Null validation for getCharacterByReferenceName
  • I'd make a dummy CustomItemImpl rather than returning null.
  • I'd make a ConfigurableCharacter class and load characters from the config, there's no need for them to be hardcoded
  • Messages could be configurable
  • You have a MessageConstants class yet keep your message constants in your command class
  • ItemListenerAdapter could be replaced with a fancy generified subscribe(eventClass, eventConsumer) method
  • I have no idea what's going on the CustomEntityDamageEvent, the class name suggest it's an event class but it's an interface/data class combo
  • Your Commands class doesn't check if the command is registered in the plugin.yml, error prone
#

Bunch more stuff, I'd structure the project in an entirely different way so I don't want to start nitpicking

round fossil
#
  • the name should be instance, not INSTANCE
  • use this whenever possible, it adds readability
  • weird usage of packages, me.skinnynoonie.characterwar.character.impls and me.skinnynoonie.characterwar.character have no relationship, don't treat them as child-parent
  • your character manager class is just a repository class, name it more precisely
  • the term "reference name" is weird, find a better way to convey the meaning behind whatever that is
  • your cooldown manager class has a static method over the constructor, switch order
  • use variables when you know the instance is gonna be called multiple times
        if (cooldowns.get(uuid) == null) {
            return true;
        }
        if (cooldowns.get(uuid).get(key) == null) {
            return false;
        }
        return cooldowns.get(uuid).get(key).expired();
``` very little reason to do this.
- name packages singularly
- ur commands class is not a util class
- you use singletons and dependency injection oddly, go with dependency injection if u feel unsure what to use
- your item listener adapter isnt an adapter class
- your custim item impl class isnt an implementational class
- CMD is a weird acronym suffix for a class, consider writing it out
night knoll
#

holy moly

#

@round fossil

#

JDA did this so i thought to do the same

round fossil
#

that class is not a primary example lmao

#

just because they do it doesnt mean its inherently used correctly

#

anyway, @night knoll i dont know if they use the pattern correctly (but you were not doing it at least)

#

yeah I just read that code

#

it looks like it does something more than just being an interface with a set of abstract methods (the reflection at the very bottom of the source file)

night knoll
#

bruh

round fossil
#

its really a trap, even relatively well known projects at times may have poor naming choices

night knoll
#

Yo I'll be back tmr guys

round fossil
#

yea gl :)

night knoll
#

@round fossil

#

What do I call the class then

#

cause I like it how the method name correlates with the impl

round fossil
#

just name it like ItemListener, ItemObserver, ItemHandler or sth idk

#

just as long as the name is not misleading or irrelevant

night knoll
#

But it deals with abstraction for events

round fossil
#

yes I see that

night knoll
#

ItemListenerMethods.class

round fossil
#

but its not adapter just because of "But it deals with abstraction for events"

#

no no no

#

just ItemListener is fine

night knoll
#

CustomItemListener

round fossil
#

an example from mojang (a bit more... well... correct one) is the nms entity Villager
it implements

public interface ReputationEventHandler {
    public void onReputationEventFrom(ReputationEventType var1, Entity var2);
}
#

which is some type of even listener abstraction

night knoll
#

Is the Mc src good

round fossil
#

not always

night knoll
#

like organized

#

how tho

round fossil
#

they have bombardered their code with design patterns, basically overengineered it

night knoll
#

isn't there professional devs and stuff

round fossil
#

yes, but that doesn't mean you need to overengineer everything

#

iirc at one point they had a singleton for sneaky throwing

night knoll
#

@round fossil

round fossil
#

yea

night knoll
#

So

round fossil
#

like skinnynoonie, let me just get this straight with u

night knoll
#

ImIllusion said my custom event impls are misleading

round fossil
#

there is no src thats good to the very end

night knoll
#

what and how should I call and organize them

#

All they do is send events to the ItemListeners, so I don't spam get the PDC

round fossil
#

yes its misleading

#

because in bukkit you'd basically think its one of those PlayerJoinEvent, PlayerQuitEvent etc

night knoll
#

PlayerInteractItemListenerImpl

round fossil
#

uh sure

round fossil
#

second is to not take code for granted

#

just because its written by a reputable developer doesnt mean its impeccable

#

try to be critical, what would I have done here? what do I not like here? what do I like here? why is this good/bad?

night knoll
#

how should I organize my characters

#

cause character. Is for all the managers and other stuff

#

And impls. I also thought was kinda bad

round fossil
#

ur character class sucks

night knoll
#

But I also thought characters. Would be too long

round fossil
#

u use abstract classes wrongly

night knoll
#

well it is abstract

round fossil
#

and?

#

the abstract there doesn't achieve something meaningful in comparison to other semantic features

#

like

#

you probably just want an interface

#

and an impl

#

w/o the abstract

#

i am gonna get hate for this one @night knoll , but I generally believe abstract classes are one of the easiest tools to make ur code smell in java

#

they allow extremely tightly coupling in the shape of parent-child dependence

#

if possible, use interfaces with default methods and then just concrete implementations

night knoll
round fossil
#
public abstract class Character {

    private final CustomItemImpl helmet;
    private final CustomItemImpl chestplate;
    private final CustomItemImpl leggings;
    private final CustomItemImpl boots;
    private final List<CustomItemImpl> items;

    public Character() {
        helmet = getHelmetImpl();
        chestplate = getChestplateImpl();
        leggings = getLeggingImpl();
        boots = getBootsImpl();
        items = getItemImpls();
    }

    public abstract @NotNull String getReferenceName();

    public abstract @NotNull String getDisplayName();

    public abstract @NotNull String getDescription();

    public abstract @NotNull CharacterVerse getVerse();

    public abstract @Nullable CustomItemImpl getHelmetImpl();

    public abstract @Nullable CustomItemImpl getChestplateImpl();

    public abstract @Nullable CustomItemImpl getLeggingImpl();

    public abstract @Nullable CustomItemImpl getBootsImpl();

    public abstract @NotNull List<@NotNull CustomItemImpl> getItemImpls();
#

this is not an interface

night knoll
#

and the reason I didn't want to use an interface because I didn't think it was worthy to make many instances of an item impl

#

look at the pre-made methods

round fossil
#

but there is more commitment to an abstract class than to an interface tho?

#

you're coping rn

night knoll
#

what

#

I used an interface first

#

Is what I ment

round fossil
#

that was a good choice

#

idk why u switched

night knoll
#

I don't think it makes sense to basically do new SupermanLeggingsImpl().getItem(); every time

#

someone gets a kit

round fossil
#

I mean you would cache SupermanLeggingsImpl surely?

night knoll
#

how

round fossil
#

throw away objects is generally considered an anti pattern

#

i mean just create a repository class

night knoll
#

What's that

round fossil
#

a class whose sole purpose is to allow access to data(-transfers) somehow (often through key-value)

#

for instance

#
class UserRepository {
  Map<String,User> backingMap; //with getters and setters without exposing map
}
class CharacterTypeRepository {
  Map<String,CharacterType> backingMap; // -||-
}
class Character {
  CharacterType type;
  User owner;
}
class User {
  Map<String,Character> userCharacters;
  Character currentCharacter;
}
night knoll
#

or I can use an abstract class

#

Ppl can mix and match character pieces btw

round fossil
#

then sth like

UserRepository userRepo = ...;
CharacterTypeRepository characterTypeRepo = ...;
Storage storage = ...;
User user = userRepo.findUser(uuid);
storage.loadData(user).await();
Character character = user.createNewCharacter("name", characterTypeRepo.getByName("superman"));
user.selectCharacter(character);
storage.saveData(user).await();
night knoll
#

sorry but I ain't doing all that

round fossil
#
interface CharacterType {
  //an optional accessor
  @Nullable public default String description() {
    return null;
  }

  //a required accessor
  public String name();
}```
#

u dont have to do all that

#

but u get the idea

night knoll
#

yes I do

#

Motivated me to use my abstract class more

round fossil
#

you asked for a code interview, I will point out code smells based on where ur code is most likely gonna be an issue in the future or for ppl who read in the future

#

if u wna apply it or not is up to u

night knoll
#

ik how

round fossil
#

as said the issue with abstract classes is that they cause TIGHT COUPLINESS

night knoll
#

Character interface
AbstractCharacter abstract class
BatmanCharacter impl

round fossil
#

and when they dont cause tight coupliness they basically just do what interfaces do already

night knoll
#

boom

round fossil
#

lol why the AbstractCharacter

night knoll
#

Cause u like ur interface so much

round fossil
#

ur character is just a fkn data transfer anyway

#

?

#

no im asking u, its not about me

night knoll
#

It's a data holder

#

and it's just a simple chache

#

cache

round fossil
#

yes so why would u have an abstract class for it

#

there is nothing to make abstract in the first place

night knoll
#

not if I make the interface

round fossil
#

u dont get the point

#

ill re-iterate myself

#

abstract classes are one of the easiest tools to make ur code smell in java

they allow extremely tightly coupling in the shape of parent-child dependence

#

and when they dont cause tight coupliness they basically just do what interfaces do already

night knoll
#

What does tight coupling mean

round fossil
#

it means code is tightly dependent on the components it depends on

night knoll
#

What does it depend on

round fossil
#

for instance if ur code is binded to an instance (like a singleton) then its tightly coupled

night knoll
#

it's not dependent on the abstract class

round fossil
#

Bukkit.getServer().getOnlinePlayers() is a tightly coupled method call, because whatever class that calls this method depends on an instance

round fossil
night knoll
#

No

round fossil
#

which means the maintenance level just increase signficantly

#

yes lol

night knoll
#

How

round fossil
#

quite literally

#

no but the issue with abstract classes is that all subclasses of that abstract class are gonna be extremely dependent on the concretion of the abstract class to work accordingly

night knoll
#

Send me the superman character class

round fossil
#

urs?

night knoll
#

Yes I'm on phone

night knoll
#

Like in dc

round fossil
#

no thats spammy

night knoll
#

Alr hold on

round fossil
#

dont send it

#

just read it instead

night knoll
#

I'm brushing my teeth

round fossil
#

as said again, THE REASON YOU DONT EXPERIENCE THE ISSUES WITH ABSTRACT CLASSES IS:

  • your code is like 500 lines in total, u dont have any issues changing stuff because the project is so small
  • you dont even use the abstract class in a way that it utilizes the way abstract classes are supposed to be used, your implementation sucks, it can be implemented with just interfaces and normal classes
night knoll
#

What issue am I gunna

#

Run into

#

Doing that

round fossil
#

also because you don't really understand the difference between type dependence and unit dependence

#

prob no issues unless u wanna scale ur project

#

but u went here for a code review

#

so here u get one

#

the way u used the abstract class smells, no matter how u try to advert ur eyes, im not trying to insult you, but im just emphasizing there are better ways to do what you did there

#

if you dont care about improving the quality of code there is really no point in asking for a review

night knoll
#

How tho

round fossil
#

with an interface

night knoll
#

bro

round fossil
#

quite literally

#

dont bro me, you know what I mean and what I have been implying all this time

night knoll
#

Buddy

#

the way ur doing it

#

is over engineering it

round fossil
#

its really not

night knoll
#

I don't rly see how ima run into any issues

#

the Character abstract class is just a data holder class

#

There's no impl

#

nothing

#

it's like an artifact at a museum

round fossil
#

you dont even know what impl means

night knoll
#

don't start insulting me

round fossil
#

im not

night knoll
#

the only tight coupling that's gonna happen is between me and u

round fossil
#

you drop this, dont ask for code reviews again if you're going to behave like this

night knoll
#

Explain to me

#

Why doing it your way is better

#

like I still don't get why I can't just use an abstract class for this

round fossil
#

its not like you cant

#

i say it again, there are better ways to do it

#

one is with just an interface

night knoll
#

And then a String, User map

round fossil
#

idk I just made it up

#

my example is irrelevant

night knoll
#

... ok

#

ok so let's say I use an interface

#

What am i gonna do about those throw away objects

round fossil
#

Abstract classes promote what's called implementation inheritance which is when sub classes strictly rely on their parent class structures, the means when the parent class implementation is changed, the subclass has to change accordingly. If this does not apply to your abstract class then you use your abstract class wrongly, which means it can simply be done with an interface and some concrete classes. If this does apply to your abstract class then you have a proper use of the abstract class, but it comes with the cost of this tight sub-super class relationship.

round fossil
night knoll
#

Character - interface
AbstractCharacter - abstract class
SupermanCharacter - impl

round fossil
#

no

#

remove the abstract charcter

#

its not needed

night knoll
#

Character changes, abstractcharcter will too

round fossil
#

yes but if Character changes, the the contract of ur component's functionality is changed

#

so of course the underlying implementation has to adapt to the change

#

im talking about implementation changes

#

the fragile parts of code

#

AbstractMap, AbstractList etc exists because they are skeletal implementations
(no one ever depends on these types, they are just there for convenience without damaging maintainability, structure etc altho it does affect flexibility)

#

yours is not

round fossil
#

yes it does

night knoll
#

how

#

Let's say I get a

round fossil
#

because its an interface

#

an interface is the functionality of something

night knoll
#

ok so I use an abstract class

#

cause it has no functionality

#

Other than displaying sata

#

data

round fossil
#

why?

#

you dont need the fucking abstract class

#

it does nothing

night knoll
#

bro chill out

round fossil
#

this is not getting anywhere

night knoll
#

yeah because what am I gonna do

#

Without the abstract class

round fossil
#

just dont use the abstract class?

#

i m not gonna explain anything further

night knoll
#

Then what do I do about the throw away objects

round fossil
#

you refuse to listen anyway

night knoll
#

u never answered that question

round fossil
#

dont throw them away

#

cache them?

night knoll
#

bruh

#

how

round fossil
#

by mapping them?

#

this is basic data design

night knoll
#

how would that look like

round fossil
#

look at my example for instance lmao

#

u have a map with keys, and then normal plain java classes

night knoll
#

CharacterRegistry - sort manager class?
Character - interface
SupermanCharacter - impl

round fossil
#

yes

night knoll
#

like

round fossil
#

thats good

night knoll
#

bruh

#

And then

#

CharacterRegistry{

getLeggings(Class<? extends Character>)

}

#

?

round fossil
#

you can make it surjective sort of I suppose

#

like

night knoll
#

Like what

round fossil
#

CharacterRegistry {
IdentityHashMap<Type,Character> mapByType;
HashMap<String,Character> mapByName;
HashMap<Integer,Character> mapById;
int id = 0;

void register(Character character) {
mapByType.put(character.getClass(),character);
mapByName.put(character.name(),character);
mapById.put(id++,character);
}

//get by id
Character byId(int id) {
return mapById.get(id);
}

//get by name
Character byName(String name) {
return mapByName.get(name);
}

//get by type
<C extends Character> byType(Class<C> type) {
return (C) mapByType.get(type);
}
}

#

example only

night knoll
#

ok bro what

round fossil
#

im just trying to give u an idea or well inspiration

night knoll
#

I'm tryna get the leggings

#

without making a throw away object

round fossil
#

yea

#

so when u need the leggings u'd just:
registry.byName("superman").getLeggings();

night knoll
#

Not possible

round fossil
#

why?

night knoll
#

cause it won't be .getLeggings

#

The leggings are in the itemimpl class

round fossil
#

?

#

im just basing myself of ur code

#

u need to figure out the design on ur own

night knoll
#

@round fossil

#

Look at the variable

round fossil
#

mhm

night knoll
#

type

#

Ig that's my fault bad naming

#

but that's an impl class

round fossil
#

the ItemStack?

#

or ru referring to CustomItemImpl?

night knoll
#

Yes

#

The ItemStack is stored in the impl

round fossil
#

then it would be just
registry.byName("superman").getLeggingsImpl();

#

no?

#

i mean u get the point i hope

#

reuse the objects

night knoll
#

the getLeggingsImpl() is a throw away object

#

if u just call .getItem() right after

round fossil
#

getItem is not a throw away object

#

because it creates an itemstack which u would most likely do something with ofc

#

itemstacks are also fine to create - use once - and repeat

night knoll
round fossil
#

its not

#

u cache it in Character.java

night knoll
#

bro...

#

That's the purpose of my abstract class

round fossil
#

yes but u dont need abstract for that lol

night knoll
#

yo I'm ngl

#

we are in circles again

round fossil
#

yes because you base yourself around the importance of that the abstract class is useful because its abstract or something

night knoll
#

It is abstract tho

round fossil
#

ru trolling?

night knoll
#

tell me how it's not abstract

#

no I'm being serious

round fossil
#

yes because you base yourself around the importance of that the abstract class is useful because its abstract or something

night knoll
#

Oh

round fossil
#

read my message pls

#

feels like u skip half of my messages

night knoll
#

bro

#

ok so

#

let's say I use the design

#

U gave me

#

How is .getItemImpl not a throw away obj

round fossil
#

i mean ofc u have to tweak it

night knoll
#

I cant

round fossil
#

let me give an example

night knoll
#

Unless I dependency inject the itemstack into the item impl

round fossil
#
interface Character {
  @NotNull String displayName();

  @Nullable public default CustomItemImpl leggings() { return null; }
}

class SupermanCharacter implements Character {
  private final String displayName;
  private final CustomItemImpl leggings;

  public SupermanCharacter(String displayName) {
    this.displayName = displayName;
    this.leggings = new SupermanLeggings();
  }
  
  @Override @NotNull public String displayName() { return this.displayName; }

  @Override @NotNull public CustomItemImpl leggings() { return this.leggings; }
}
#

(last line):
@Nullable @NotNull public CustomItemImpl leggings() { return this.leggings; }

if the impl does not have leggings, u just dont override the method

night knoll
#

ok that's just stupid

round fossil
#

what is?

night knoll
#

instead of letting another class be the cache, the display class has to cache itself

round fossil
#

u cache it in another class if u want lol

night knoll
#

So now I gotta force myself to write a bunch of boiler plate

round fossil
#

no one is restricting u

round fossil
#

u can prob recordify it

night knoll
#

How is it not

#

8+ lines

#

If it has all the armor

round fossil
#

if u dont like the boilerplate, either go with a record, or use lombok or sth like kotlin

#

abstract is not the way

#

you can prob ask any1 here, they'd agree with me (i hope at least)

night knoll
#

@night knoll do u agree with @round fossil

#

nah I dont

round fossil
#

not u

#

stop trolling one last time

night knoll
#

ok here

#

How can I make the abstract class make sense

round fossil
#

so u want it to be abstract?

night knoll
#

yes

round fossil
#

thats another goal, but well, idk, it doesnt really suit to be abstract there let me see

#

if u couple the event handling then maybe it would make sense

#

like let stuff such as
onPlayerDamagedWithArmor(@NotNull EntityDamageEvent event, @NotNull Player victim) be abstract methods in ur abstract class

#

and impl it in SupermanCharacter

#

i still dont like it

night knoll
#

Nooe

#

no

#

I did that

round fossil
#

but having that there would justify it more

night knoll
#

I made the character impl also impl all the items

#

it was a mess

round fossil
#

yeah so instead u resorted to an interface CustomItemImpl and let each item impl it

#

which is good design

#

i like it

night knoll
#

Thx

round fossil
#

the name Impl in the end is questionable since its an abstraction but w/e

#

u got the concept right

#

thats whats important

night knoll
#

bruh rly changed pfps mid convo

round fossil
#

me?

night knoll
#

yes

round fossil
#

prob my gf

#

she does weird things on my acc

#

anyway

night knoll
#

ok well

round fossil
#

as said

#

if u want it be abstract let it be

night knoll
#

I didn't want a compliment

round fossil
#

the world wont end

#

but like as mentioned, it doesnt need to be abstract and shouldnt be

night knoll
#

ok then what should it be

round fossil
#

normal java class

night knoll
#

I remember someone told me

round fossil
#

and interface

#

who?

night knoll
#

dependency platform development

#

Where it's interfaces for everything

#

And then abstract for boiler plate

#

Then the impls

round fossil
#

who said that

#

i will quite literally bonk them in their feet

#

its partially right

#

but its not the whole truth

#

anyway i need to sleep now

#

gn, can continue tmrw

night knoll
round fossil
#

yes but illusion doesnt write a lot of unit tests, and havent really been in that industry, so he uses abstract classes a lot since he hasn't rly experienced the pain they may bring

jagged rock
#

(this structure mostly works for platform-agnostic code)

night knoll
#

ok so

round fossil
#

if u code in mc u prob wont experience issues with abstract classes

night knoll
#

ok so it's fine

round fossil
#

what I gave is an industry standard review

jagged rock
#

(where the difference between each module is about ~10 lines of code)

round fossil
#

i mean its fine to have everything static if u're mentally unstable

night knoll
#

bro

jagged rock
#

(I rarely use abstract classes when working on spigot-only projects)

night knoll
#

abstract class is abstract and has some default methods

#

it's basically an interface

round fossil
#

not not really

#

there is a huge difference

#

fields being one of them

#

second being that interfaces are way easier to mock

#

so when it comes to transparent testing abstract classes become a huge problem

jagged rock
#

Well in my case I make an interface and expose that interface

#

The abstract impl just de-duplicates code :)

#

If you want to mock stuff, you mock the interface

round fossil
#

yeah its just a skeletal implementation ^

#

like AbstractMap, or w/e other abstract thingy u wanna bring up as an example

night knoll
#

ok so lmk why this won't work (ik I've mentioned this so many times)

Character - interface
AbstractCharacter - abstract class
SupermanCharacter - impl

Has an interface so it encapsulates a lot of stuff

Abstract is abstract, has some boiler plate reduction

Impl - the impl

round fossil
#

yes but u have just data

#

so the abstract there is pointless

night knoll
#

since when was abstraction not allowed for data

round fossil
#

didnt say disallowed

#

i said pointless

jagged rock
#

There are use-cases

night knoll
#

@jagged rock how would u do this

jagged rock
#

I'd honestly make the entire Character part just interfaces

#

And config files that point to abstract items

#

but tbh you barely need an abstract class for custom item logic

round fossil
#

^

night knoll
#

its not even the logic

#

it's just for boiler plate

round fossil
#

yes but boilerplate is invalid reason

jagged rock
#

well

#

yes and no

round fossil
#

if u wanna avoid repeating yourself

night knoll
#

I'll try to add the custom configurable items thing

#

See what happens

jagged rock
#

I use abstraction for DRY reasons

round fossil
#

then yes use abstract to skeletally abstract away repetitions

#

yes but boilerplate is something else

#

java has it by nature

#

if u wanna avoid it, use lombok or kotlin ig

night knoll
#

switching to C

#

bye guys

jagged rock
#

(ignore the broken imports)
This is how I do cosmetics

#

but like

#

if I were to make it now this would be an interface

round fossil
#

yeah thats more reasonable

jagged rock
#

I wonder if I can make this an interface

#

prob not

#

this is old by my standards

night knoll
#

yeah but u have the

round fossil
#

anyway
avoiding boilerplate means avoiding writing out stuff like the {}, semicolons, basically unnecessary code thats just in the way and can be reduced but still produce the same semantics

avodiing repetition means you avoid writing out the same variable, the same method again etc

#

abstract class if used as a skeletal class, then it should be due to the latter

#

if u do it due to the former, then there are better tools to think about first like records, lombok, other languages or something else

jagged rock
#

static

round fossil
#

there is also the argument of that you should only ever abstract away if its a useful abstraction, is an abstract class for a data transfer object useful? probably not, at least 99% of the times

jagged rock
#

For example this last class could've been reworked to proxy a Renderer interface and avoid the abstraction

night knoll
#

bro I'm so confused

night knoll
#

ok so

#

nah

#

what do I even do atp

round fossil
#

what u feel is best

jagged rock
#

Bros about to cry in a corner out of confusion

round fossil
#

when u understand object orientation, data orientation and design good enough you'll get it intuitively

jagged rock
#

That's what's best

round fossil
#

:,)

night knoll
#

bruh

#

no

#

@round fossil @jagged rock r u guys telling me I should create the item stacks in the character impl class

jagged rock
#

No

#

We're saying to ditch the abstract class unless there's a real good reason to keep it

round fossil
#

generally speaking, the more responsibility given to the character class, the harder it becomes to maintain it

night knoll
round fossil
#

if u want

#

it makes the impl more complex and harder to maintain

#

there is pros and cons to everything

jagged rock
#

Ever heard of Single Responsibility Principle?

#

It's a bit easy to get it wrong but basically you should write your class to serve a niche purpose

#

And nothing else

#

The more complex your project is, the more niche each class is

night knoll
#

yeah that's what I did tho

#

the item impl is in another class

jagged rock
#

For example, people can say "The admin command class handles everything regarding the admin command"

#

BUT

#

The admin command should only handle the command logic itself

night knoll
#

and the abstract character handles the cache

jagged rock
#

Any data that's manipulated by the command needs to be handled elsewhere

night knoll
#

So I'm following srp

jagged rock
#

depends

#

Your character class shouldn't be responsible for items

round fossil
#

in short, srp says a class should only change its implementation for one major reason, the Database class shouldnt have to be changed because your LoginHandler needed to change for instance

round fossil
#

its up to the developer to define these so called major reasons

night knoll
#

wait

#

Wdym character

#

the impl or abstract

round fossil
#

the abstract one

night knoll
#

Then what should

round fossil
#

its fine if ur character class refers to WHAT items are relevant, but it shouldnt contain HOW those work or their implementations

jagged rock
#

I'm thinking

#
public interface CharacterInventory {

  ItemStack getItem(EquipmentSlot slot);
  Collection<ItemStack> getExtraItems();

}
public interface CharacterInfo {

  String getName();
  String getDescription();

  CharacterVerse getVerse();
}
public interface Character {

  CharacterInventory getInventory();
  CharacterInfo getInfo();

}
round fossil
#

thats really good data structuring as well

#

skinny, this is prob the type of structure u're looking for

night knoll
#

That looks a lot more promising

#

where do I put the impl

#

Eh actually idk

#

that seems like a lot of classes for one character

jagged rock
#

Now, you could do something like

public class BasicCharacterInfo implements CharacterInfo {

  private final String name;
  private final String description;
  private final CharacterVerse verse;

  public BasicCharacterInfo(String name, String description, CharacterVerse verse) {
    this.name = name;
    this.description = description;
    this.verse = verse;
  }

  public BasicCharacterInfo(ConfigurationSection section) {
    this.name = section.getString("name", "FIX YOUR CONFIGURATION - INVALID NAME");
    this.description = section.getString("description", "FIX YOUR CONFIGURATION - INVALID DESCRIPTION");
    this.verse = CharacterVerse.valueOf(section.getString("verse", "DC").toUpperCase(Locale.ROOT));
  }

  @Override
  public String getName() {
    return this.name;
  }

  @Override
  public String getDescription() {
    return this.description;
  }

  @Override
  public CharacterVerse getVerse() {
    return this.verse;
  }
}
night knoll
#

since I'm using pdcs

#

how should I split the key for the actual item

jagged rock
#
public class BasicCharacterInventory implements CharacterInventory {

  private final Map<EquipmentSlot, ItemStack> items = new HashMap<>(); // Use whatever impl you want
  private final Collection<ItemStack> extra = new ArrayList<>(36);

  public void registerEquipment(EquipmentSlot slot, ItemStack item) {
    if(slot == null || item == null) {
      return;
    }

    items.put(slot, item);
  }

  public void addExtraItems(ItemStack first, ItemStack... other) {
    if(first != null) {
      extra.add(first);
    }

    extra.addAll(List.of(other));
  }

  @Override
  public ItemStack getItem(EquipmentSlot slot) {
    ItemStack result = this.items.get(slot);
    return result == null ? null : result.clone(); // ternary, replace with if-else if you want
  }

  @Override
  public Collection<ItemStack> getExtraItems() {
    return List.copyOf(this.extra);
  }
}```
#

bim bim bam bam

#

But tbh I'd rather skip this entire inventory BS

#

Have a registry somewhere

jagged rock
#

I'd probably rename CharacterInventory to just ArmorSet

#

and load and register them separate

#

linking them to a custom item registry

night knoll
#

I mean

#

Ok how is a

#

an item impl gonna look like

jagged rock
#

Up to you

#

You could use an abstract class for this, depending on how you plan for it to work

night knoll
#

yay abstract class

jagged rock
#

My usual item impls look like

public class WhateverItem extends CustomItem {

  public WhateverItem(MyPlugin plugin) {
    super(plugin);

    subscribe(PlayerInteractEvent.class, this::handleClick);
  }

  private void handleClick(PlayerInteractEvent event) {
    if(!event.getAction().isRightClick()) {
      return;
    }

    ItemStack item = event.getItem();

    if(!matches(item)) {
      return;
    }

    ...
  }

  @Getter
  public String getName() {
    return "whatever";
  }
}
#

but it can be replaced with an interface if you adventure enough

night knoll
#

It's just matches part

#

Thats all worried about

jagged rock
#
public interface CustomItem extends Listener {

  default boolean matches(ItemStack item) {
    String name = getName();
    // get pdc string
    return ...
  }

  String getName();
}
#

replace the subscribe with an @EventHandler

#

And register the listener when you register the item in your registry

night knoll
#

ok but the PDC string won't be in the item

jagged rock
#

it will

night knoll
#

where

jagged rock
#

in your ItemStack

#

you get the pdc

#

if it doesn't exist, it doesn't match your item

night knoll
#

no like

#

Where do I set the pdc

jagged rock
#

somewhere

#

here's what I do with uhh

#

abstract classes

#

old impl

#

wrote it a few months ago

night knoll
#

o

#

idk

#

Ima just restart tmr

night knoll
#

@jagged rock what do you use to config items

jagged rock
#

polymorphism

#

I got no clue how to answer your question

night knoll
#

do u use an API

jagged rock
#

I make all my utilities

night knoll
#

wtf

#

@jagged rock do u just paste your past utils into a utils package

jagged rock
#

something like that

night knoll
#

lmao

night knoll
#

@jagged rock yo idk how this gonna work ima be honest

#

My abstract class way makes the most sense to me still

#

maybe I'll rename it to CharacterTemplate or something

night knoll
#

nah nvm

woeful pasture
#

Interfaces are pretty abstract and can be hard to think through especially if your new

#

I'd reccomend sticking with it though maybe do a formal write up for your plan

night knoll
#

@woeful pasture

#

I talked to someone and they said abstract classes managing data is bad

#

and it should manage functionality

#

U agree with that

woeful pasture
#

ofcourse

#

abstract classes exist to manage basic implementations not enforce and manage data

#

ofc this depends on how you define "manage data" abstract classes having some basic set of data they work with isn't inherently bad

#

I'd say its maybe a bit more nuanced than abstract classes managing any set of data is bad. Remember though I'm pretty new to programming (only 2 years with java) so there is always a chance my statement isn't fully accurate

round fossil
#

skinny, have u ever looked at AbstractList, or AbstractMap

#

they are abstract classes, mostly for convenience if u wna implement a custom map or list

night knoll
#

I looked at AbstractList @round fossil

#

and that's what they told me to look at and it's what I noticed

round fossil
#

yeah, so it exposes like one abstract method to minimize the complexity

night knoll
#

Wdym

#

which one I didn't see

#

It's just really confusing for me

round fossil
#

if u try to extend AbstractList

#

u'll see there is only one method u have to override

night knoll
#

Because I don't know how I can check if someone's boots is superman's boots in my item implementation

#

and that also means the character class will define the PDC itself

#

Which idk if that should be done in that class

sly jackal
#

what else should define the pdc

night knoll
#

let's say I have something like

#
public ItemStack getBoots() {

    return new ItemBuilder(Material.LEATHER_BOOTS)
    .setPDCValue(key, "reference-name").build();

}```
#

Idk how to explain

night knoll
#

Factory?

interface ArmorFactory {
  ItemStack head();
  ItemStack chest()
  ItemStack pants();
  ItemStack boots();
}
public class DiamondArmorFactory implements ArmorFactory {
  ItemStack head() { /* Returns new diamond helmet itemstack */ }
  ItemStack chest() { /* Returns new diamond chestplate itemstack */ }
  ItemStack pants() { /* Returns new diamond pants itemstack */ }
  ItemStack boots() { /* Returns new diamond boots itemstack */ }
}
pine grail
#

factory

opaque plover
#

Factories are insanely hot both literally and figuratively

#

If you have a factory in your code, you are one step closer to marrying me

night knoll
#

No sorry.

opaque plover
#

I don't think this was a question 👀

opaque plover
#

Send me 17000$

jagged rock
opaque plover
#

🤤

jagged rock
#
public class ConfigurableEquipmentFactory implements EquipmentFactory {

  private final ConfigurationSection node;

  public ConfigurableEquipmentFactory(ConfigurationSection node) {
    this.node = node;
  }

  @Override
  public ItemStack create(EquipmentSlot slot) {
    String path = slot.name().toLowerCase(Locale.ROOT);
    ConfigurationSection itemSection = node.getConfigurationSection(path);

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

    return ItemBuilder.fromSection(itemSection); // replace with your own util
  }
}
#

is how I'd do it

night knoll
#

the only problem I have rn is the namespaced key

#

i want an easy system to manage it while being abstract with it

#

because every item will use the same namespaced key like this

{"reference_name":"name"}```
woeful pasture
#

@night knoll is your code on github?

night knoll
woeful pasture
#

push your changes and send me a link

night knoll
#

im still tryna figure out how to do this

woeful pasture
#

you can just make your key on the fly using the static methods from namespaced key

night knoll
#

bruh

round fossil
#

I do it without passing my plugin instance. altho thats generally considered a bad approeach, but that way I can create true constants so to speak

woeful pasture
#

you can always do static final fields with the plguin instance if you use static getter

round fossil
#

hence why I avoid it, altho for 99% of users, it wont matter :>

night knoll
#

@round fossil

alpine anvil
#

epic conclube mention

night knoll
#

is it OK if I make an abstract class to help a functionality

alpine anvil
#

what functionallity

night knoll
#

like

public item getItem() {
return getItemBase().setPDCValue(a, a, a);
}

public abstract item getItemBase();

#

What does that mean

alpine anvil
#

i would say if setting the pdc value generates the final item id call it someting like build() so you can do something like Armor#build()

night knoll
#

The main issue I have is setting, then getting the correct PDC key in something like a damage event

#

and I don't wanna directly hardcode those values in

sly jackal
#

then make a class that fills them in for you

night knoll
#

is it ok to nest all that under item

#

or should I put them in a new package called "custom"

sly jackal
#

I think this is fine

night knoll
#

ok thx

spring reef
#

only extra package i would see there is for armor

night knoll
#

@spring reef

#

wait nvm

night knoll
spring reef
night knoll
#

Uh

#

I'm just trying to depend on abstractions

sly jackal
#

but abstractions for no reason just makes things more complicated

night knoll
round fossil
night knoll
#

idk but if I were to do this how i would like it

#

I would delete the CharacterInfo interface

#

And the CustomCharacter interface

#

And obv delete the repository interfaces

round fossil
willow bone
#

also what do you mean by "I've already bought up this once with you"?

round fossil
#

You went off topic in this channel before

night knoll
#

I just kept my interfaces

#

Idk I liked having everything being an interface

round fossil
night knoll
cobalt trellis
#

Everyone thinks of stuff differently

round fossil
civic shell
jagged rock
#

It seems like you're trying to go into enterprise design before mastering the basics

#

The first two things I notice when I open your project are:

  • Static abuse
  • Not following naming conventions
civic shell
#

wdym Static abuse?

#

naming conventions i get, i just can get into the habbit. they arent consistent at all.

#

I just made changes to the static methods.

jagged rock
#

Still not good