#[MEGA THREAD] Get Your Code Reviewed or Review Others
1 messages · Page 11 of 1
You guys would love my father
He's been a project impl manager for like 28 years now
Basically an architect minus being a dev
What is vb
Virtual Basic
Visual Basic
same thing
No clue what that is and I'm already puking
pretty shit
Damn it only made it to 6.0
https://paste.md-5.net/qicuroroqa.java
Do you guys hate this
Visual Basic .NET only made it to 6.0
Visual Basic is still alive, and is on version 17
Oh
depends on the internals
oh you posted internals xD
No I don't like this personally, Is their really a reason to put skills behind an object like that? both of the values you passed can be thrown in a function to cause change.
mmmm
this could much better be done with some sort of registry and more functional approach
Funny you say that cuz last time me and con talked, he said I was doing "too much functional" stuff kek
Tbf no, just trying really hard to follow stricter oop 🤷
I think too much of both is bad, but here it makes sense to just not use objects. The thing about mathmatics is that they can inherently be best be described by functions
if skills apply changes to how the disc flies, why not apply those transformations as functions? It only makes sense
https://paste.md-5.net/yikixibuyu.cs
This is where the skills actually manipulate the physics, I feel like you're probably right tho it feels quite bloated
yeah I feel like not applying the skills as functions makes no sense here 👀 especially since they can be modeled by pretty simple functions
Registries my beloved
I think my biggest thought was keeping serialization separated but then again why put each skill into it's own file, could just toss them all into one call it a day
I need to make a registry system like mojangs
I also liked the thought of individual objects in terms of displaying players skill sets, makes it easier in my opinion to deal with an existing object rather than have to create one from thin air
part of me thinks that you should just have a PlayerData class with a Map<Skill, Integer>. You could make more things customizable this way too e.g. the particels behind the disc of each player etc
just my thoughts, I prefer using functions in this case over objects so just my opinion but ye
I mean I could the same with internal functions within the skill classes
Idk I like the deep encapsulation too
Use pineapples
Mojangs is too overly verbose
I feel like skills aren't something that should ever be messed with outside of their current and max levels
I never saw any utilitiy of it over something like mine which is just a thin map wrapper with utilities prety much
And perhaps creating your own skills too... not sure on that one yet
Yeah but is yours statically accessible
uhm probably? idk what you mean by that
All of mojangs registries are static
Stuff can also be registered to them in static fields
I always have a Registries class so I can do Registries.THING
https://paste.md-5.net/ozawerabet.cs
Back again
The other issue with these is when using them on stuff you cant guarantee wont be null later and then it throws trap errors
Trap if you dont know is a type of error where you stated in your code that it wont be null or is not null and it ends up being null later lol.
Idk, I had relatively few issues with that method. On the other hand I understand what the implications of it are
i honestly use it to suppress ide nullability warnings if i know the object is guaranteed to be not null if that makes sense (sometimes IDE's aren't smart enough to tell)
if it is null then its useful cause it tells me before breaking more stuff
and id just import and use the static method so it would be like
final Player player = requireNonNull(foo.bar());
Just use nullability annotations smh
Or assert if you wanna be really fun
i usually use checker so i dont have to add in the annotations
cuz it adds them in for me at compile
I do actually use asserts for some calls, like to ItemStack#getItemMeta() if I just freshly made the ItemStack. It's never going to be null
And assertions are disabled by default so whatever. I'm only doing it to appease my IDE
i do the same but use requireNonNull, but requireNonNull is basically a useless null check at this point
Objects#requireNonNull, imo, is for streams
implicit null checks do be lovely at times, altho it can get rly anti pattern-like
Muh cpu cycles
as if anyone coding in Java cared about that
nowadays most of algorithms are more memory bound than cpu bound anyway
Muh bytes
https://paste.md-5.net/tijejuyoza.java
Notes, questions, concerns, love you guys
Changed this from player.getUniqueId to the id I pass... I was being dumb lol
its a bit weird
but ehm well for starters
why not depend on Plugin instead of JavaPlugin?
I assume other people might want to use my round objects
and if u use ConcurrentHashMap, your type should be ConcurrentMap right?
since the concurrency becomes a requirement rather
Fair
no i mean
Plugin is the interface of JavaPlugin
so why JavaPlugin over Plugin?
Oh well then because I wasn't aware of that lol
na all good, just curious
What about the handlethrow method, do you feel it's redundant to have multiple handlethrow methods per object?
ie: One in the round as well as the disc object
i mean it becomes ambiguous
like which is the right type to invoke the method on, and which type is just the intermediate one
alternatively name them better
from a library perspective ofc ^^
yea i mean maybe :>
shouldn't the handleStroke call be under the Hospital's ICU object
Haven't even implemented teh ambulances yet kek
considering you're from America you might be best off implementing an Uber class instead
Nah health insurance system is already functional
Just don't be dumb and not have insurance
as far as this method goes it isn't horrible tbh, it def saves repretition so I think its fine
Well I was thinking, from the context of the round I should invoke a player object just for those odd cases a player might log out, since the disc object's handleThrow method actually uses the player object
I just mean handle the nullability case for the player in the round method rather than the disc method
tell me
fair
well u could also ask urself if u perhaps are oversynchronizing rn
cuz just smacking thread safe collections on everything tend to lead to oversynchronization
I just thought most times people like to handle their "rounds"/minigames async so
Thread safety is a concern most times in the data migration innit?
that's a nice thought, but in this code u dont deal with async whatsoever
yeah true
well read writes happening at the same time
and writes that depend on reads
ofc oversynchronizing is better than undersynchronizing, but as said
erm concurrency is gonna take me forever to fully understand
u should primarily focus on writing a structure that follows what you need, you can let your "library consumers" derive your types (<-- open closed principle) and pass their own dependencies to concrete types to allow of modification
i think there's a principle for this
its called open-closed principle if im not mistaken
I will have a read on it for sure
yea its weird stuff
its super fun
Did you mean like this btw?
mmm
and this principle is called liskovs substitution principle i believe xD
well i havent done high level software for some time
but ya
Thinking about it more the only "hardcore" math that occurs is the disc physic modifications, still this has no relation to concurrency needs of the round, any other things that have to deal with this data is simple math and other functions
https://paste.md-5.net/olebedirer.cpp
(it's poorly written cuz I was just trying to figure a flight phase system kek) This is really the only math that could be considered heavy
Well I do certainly appreciate that
backhand and forehand physics are quite similar
Well I do think u should avoid Math.random()
basically just swap the +/- gives it the flight path irl
this is def subject to a rewrite cuz I need to randomly invoke lift factors
either +/- on those too
yea anyway kat
for this kind of code, it can be fine to leave some comments on it
explaining what the math is doing yk
yeah tbf there is a single comment in that whole thing cuz I was trying to explain to a friend (not a coder)
There were more but they are dumbed down lol so I removed them
Also a lot of the math needs to be converted to configurable fields instead of magic numbers
yea
Did you ever see the irl reference compared to how it looks now?
nope
unless I missed something newer here's the comparisson
#general message
#general message
A)
public void handlePlayer(Player player) {
if(player.getHealthPercentage() < 0.50) {
player.setHealthPercentage(0.50); // Sets the health to be at least 50% of the maximum health, convenience method
player.sendMessage(Text.literal("Healed to 50%").color(Color.GREEN));
return;
}
player.sendMessage(Text.literal("You have more than 50% health!").color(Color.GOLD));
}
public void otherMethod(Entity entity) {
this.stopTicking.add(entity.getUniqueId());
this.spin.add(entity.getUniqueId());
}
public void someEventHandler(EntityTickEvent event) {
if(this.stopTicking.contains(event.entityId())) {
event.cancel();
}
if(this.spin.contains(event.entityId())) {
var storage = event.entity().storage();
var plugin = event.context().plugin();
var id = Identifier.plugin(plugin, "ticks");
var ticks = storage.getInt(id, 0) + 1;
if(ticks >= 3) {
spinEntity(event.entity());
ticks = 0;
}
storage.setInt(id, ticks);
}
}
vs
public void handlePlayer(Entity player) {
var health = player.get(Health.class);
if(health == null) return;
var messages = player.get(Messages.class);
if(messages == null) return;
if(health.getPercentage() < 0.50) {
health.setPercentage(0.50); // Sets the health to be at least 50% of the maximum health, convenience method
messages.send(Text.literal("Healed to 50%").color(Color.GREEN));
return;
}
messages.send(Text.literal("You have more than 50% health!").color(Color.GOLD));
}
public void otherMethod(Entity entity) {
entity.remove(Ticking.class);
entity.add(new Spinner(3)); // Every 3 ticks
}
public class SpinSystem extends System {
// Implement this yada yada yada
}
I guess there is also ensureGet, basically Entity#ensureGet throws an exception (with a custom message if provided) if the entity doesn't have that component
Please if you can state the reasoning (cc: @dense leaf)
ECS way better
I suppose I did not ask for a detailed reasoning
Is ECS code real thing in spigot or that was pseudo code?
wym, the bottom and top one will both technically be my API, I am asking how to model it
it's not Spigot-specific, it works as a sort of translator to multiple platforms, I suppose
Ah, pseudo code I suppose, not in spigot
Yup
I don't really find it intuitive to begin with, especially the messages, having an ECS component for messages seems really annoying to me since I'd just like to do a simple sendMessage. Then I also don't really understand what the actual code does in the ECS example, e.g., what is otherMethod used for??
they're all different methods to showcase how you'd do different things, not exactly related
Also it'd be nice if I could just access basic player data like health and saturation in the entity object
The Entity itself is not a Player, nor a zombie nor a wither, it's just Any entity
An entity could very well just be a block
A block is certainly not an entity tho
It's an entity in the sense of a presence in the world, not a mc entity, but I can limit it to be only entity entities for now
Also
regarding what you said
So I'd just rename it to ECSEntity or something then since that can get confusing quickly
I mean why would I do that? You don't depend on any other libraries
a block would also be part of the ecs
I mean do you not have an actual entity entity class then
Entity entity = ...;
entity.sendMessage(Text.empty());
entity.sendMessage(new FireDamageMessage(5));
No, there is no "Entity entity class"
each entity is defined by it's components
example
Entity entity as in actual minecraft entity
var zombie = ...;
zombie.add(new Position());
zombie.add(new Velocity());
zombie.add(new NetworkIdentifier(Identifier.minecraft("zombie")));
zombie.add(new Health());
zombie.add(new Pathfinding()); // or something
var slimeBlock = ...;
slimeBlock.add(new Position());
slimeBlock.add(new NetworkIdentifier(Identifier.minecraft("slime_block")));
slimeBlock.add(new Bounce());
// you can technically now add the block in the world
Obviously this process is not done by hand
Idk looks like library for minestom
Yeah the goal is providing the same flexibility on the vanilla server (ig Spigot / Forge aren't really vanilla but ykwim)
@dense leaf
I saw it yes
What do you have to say about it
idk I'm not really a fan of ECS's
Why so
zombie.get(Health.class).set(20);
plus you can also remove health after that
make the zombie immortal
Make your own health component
Kotlin extension functions 🗿
oh fair yeah rad could just use extension functions 💀
idk if this was pseudo but funny a builder using get and set in the same line
Well because I should stop using Kotlin I shouldn't
oh yeah fair forgot about that
Also why would the builder have a get function
it's not really a builder:
Zombie Entity
get(Health.class) Health or null
set(20); void
oh kek
Looks like some shit Sponge would conjure up
I still think Java's a shit language to do component-based paradigms. Languages with templating and reified generics are way better to do it with.
its actually so great cuz then you don't need inheritance! I'm sure it is not confusing design at all!
Kotlin has reified generics!
Kotlin can eat a dick >:(
what is reified generics exactly?
ahhh
conclure?!
:3?
you mean dynamic dispatch nuclear bomb

I mean not really
think about it
You can have both!
(/hj)
DFU would benefit from templates A LOT
I feel like you could just have an Entity class like this which can represent anything, like, if(entity.get(Type.class) != null && entity.get(Type.class).is(Block.class)) {...} or something along those lines
Ah yeah, so a Type component
which says Entity, Block, etc
skill issue get good
good call @desert ore btw
(also if anyone can further vote I would like a more definite answer)
I'd be interested to see a system that is completely and fully component based, maybe even
var server = context.getServer();
if(server.get(Type.class) == null || !server.get(Type.class).is(Server.class) || server.get(Logger.class) == null) return;
server.get(Logger.class).info("hello world");
``` but that seems annoying
it is very much annoying
the system is component based for the following:
Entities, Blocks, Items
Then
Lifecycles are fully plugin-driven except LOAD, ENABLE, DISABLE, UNLOAD
Events follow in suit
except vanilla events
which are also built in
you can actually server.ensureGet(Type.class).as(Server.class).get(Logger.class) 💀
I mean that is WILD and I won't allow it
mainly because of structural reasons
Only annoyance is that it becomes extremely runtime based, like you don’t really know what types hold true, esp when you start adding, renaming and removing componential keys under a longer span
I took some liberties to make sure no code that runs on this system is capable of affecting anything outside of its own VERY limited area, not even other plugins, it all communicates through events
Yeah ^
Anyways, do I proceed with the component-based approach?
In some way, everything being runtime based is even pretty good
I mean both have different pros and cons
Yeah, I like the component system for it's flexibility and adaptability
I personally would love to see it
Fuck around and find out
but yea, isn’t sponge heavily opinionated this way?
I mean sponge is... interesting
I definitely want something cleaner than THAT
I like the concept of sponge, but I'm not sure whether I like the implementation of it that much
they have different implementations right?
I mean it may make more sense to go with a componential design then
I believe yeah, but today we were talking about sponge and somebody brought up the itemstack builder
That shit is hell
how should I add duplicate component add
return false? return the old component? throw an error? add both?
what if I add an "allowsDuplicate" flag on the component
what is duplicate component add
Make it a seperate type of component
Maybe a seperate component to store a list of a certain component
i dodnt follow the convo, what kind of component is this
That way you don't face issues with get returning an optional list which is ass
Maybe those screenshots will help you understand a bit more
how are those components even stored
Ye, but I think a ComponentListComponent would be interesting
pretty much sounds like you are trying to do nbt with extra steps
It seems so unnecessarily overengineered and complicated
And I love it
I absolutely fucking love it
what are the components even gonna be used for
Lol
inline fun <reified T : Component> Any.get(): T?
frfr
not really! It has huge practical usages on a large scale
It is used for example by Unity DOTS to allow for dozens of thousands of entities ticking at once basically
Yup, and vice versa remove ticking from a ticked entity
Also ECS is pretty much the only way you'll get more than a few thousand entities at once without heavily multi threading or pulling other tricks
It can handle thousands upon thousands of entities (even in the 100k+ range) *if implemented correctly
Right now I won't implement it directly in the game, more or less slowly replace vanilla with it
Roast me 🔥 https://github.com/PulseBeat02/MurderRun
More specifically, this https://github.com/PulseBeat02/MurderRun/blob/main/src/main/java/io/github/pulsebeat02/murderrun/game/gadget/GlobalGadgetRegistry.java. I am loading and instantiating all my Gadget classes which I store in an Enum. I first load them into a registry, where their String identifier and ItemStack item in inventory can be just first used for display purposes. But each Gadget has its own function and utility when the game starts. When the game starts, I create a new instance of all the Gadget to make sure it doesn't conflict with any other games that may be running at the same time.
But does anyone know a way to "lazily" load the Gadget I only need at runtime. The thing is, one of my Gadget is a RandomGadget, which is a gadget that gives you a random gadget, and that means I'd have to load the Gadget class when it's activated. Anyone know a good way to lazily load the Gadget classes so I don't have to load hundreds of them each time the game starts to save resources?
nice code
Bleuh
How does an ECS allow for thousands of ticking entities at once
It doesn't that's the great part
Doesn’t that still compile down to a java bytecode misery eventually?
and java has reified generics, just extremely awkward and uncomfortable to use
I mean it just inlines the function body
isn't it the T... hack
where you can get the Class<T> back from the empty array
I wonder how different things would be if java didn't have type erasure
type erasure is a good thing, people just go bonkers over the type system otherwise
kotlin embeds its own metadata into classes to support this kind of functionality, this is part of why it is hard to relocate some stuff with koltin since some of that metadata might contain class references which one also would have to relocate
well basically, take minecraft: Each entity is processed for something every. single. tick. Even if it can't actually do anything, in an ECS instead each tick there is basically a bunch of queries that are ran (can happen in async), so things that run in tick intervals just get ignored until they should run, and don't count towards any loops (as they are separated by archetypes, basically a set of components)
TL;DR: Just separating entities into buckets and allowing for parallel processing of entities (i.e. all villagers will tick together WHILE all of the zombies are ticking together)
entity <-> entity interactions are scheduled at the end to ensure synchronization
iirc
That's if the ECS you're running is concurrent yeah
I mean yeah I'm doing that
sort of
it will be concurrent
notrn
Right now I'll just do a translation layer (so performance--) but later I'll slowly replace vanilla stuff with it
You are planning to make it non-vanilla and incompatible with everything?
I mean, not really I'll just replace ticking
oh wait
Hm
lol
If you're using something that fundementally changes how plugins/mods are made
Should you really be expecting that everything else works with it
custom entities will work
mods that change vanilla ones won't
Ah that makes sense
I mean just T extends S on a class type parameter (though u may still lose higher ordered types), and then also you got the type token hack with TypeToken<T>{} (subclassing and passing ur type to the superclass type parameter)
But yea varargs can be polluted w non reifiable params
So you want a heavily fucked system?
not really, but if I want to allow changing entities It'll be incompatible with mods that also change the same entity in the same part
Which block do you prefer?
3
4
1
A (Spigot-ish way)
well then it is ECS
?
blud just wanted to talk about ECS
Guys what's an ECS
extra complicated system or something idk i don't do gamedev
Entity component system apparently
yeeah
I wonder if mojang will ever embrace entity components like they do items
it is a pretty standard way to do entities in gamedev, and mojang does seem to be heading in that direction
it wouldn't be exactly in the way Ike demonstrated though, at least I don't think from looking at the current source changes
I would love the system I proposed lol
That is how I did it
you can essentially add any <T> as a component for the entity
and also get it back by giving an entity id
it saves 'em in a sparseset
Tbh that's a neat idea but not for me
What you planning on doing then?
oh wait let me show you my query system too
it's clean as fuck
Entities aren't builders, they are constantly modifiable, replaceable, they can cross universes and are not bound to one system, each entity is given n archetypes depending on how many archetypes it matches, it may match two identical archetypes, each archetype has a priority and a system attached to it
yes ofcoruse
This way you can have THE maximum flexibility
the first image I showed is how to create an entity
let me show you how to query and modify an entity for example
And you rarely interact with the components
me or like in general
Me*
Basically: send a text message to an entity, if it can process it, it will! Otherwise it won't. But you don't know.
Send a damage message
Did it get damaged? Probably
What's the health? Does it even have health?
Zero coupling, even between the things acting on the entity and the entity
The entity also doesn't know which messages it can receive
Each component says what it can receive
what is an 'entity' in your case?
in my case, it's just a usize (u64 / long?)
@pine grail Example of query
the "query" gets all entities that have the player identity + position component
this can be any amount of components and any type
since I need this all to be multithreaded, there cannot be 2 multiple mutable borrows, but infinite immutable ones
this supports 100% multithreading
A class to give convenience methods, otherwise it's always universe. etc
Otherwise it's just a number to a list of components
do you save entity -> Component[] or Component -> entity[]?
arrays of structs or structs of arrays
thats a good idea i should do thatt too. so you can do entity.get::<Position>(state)
I do
ID -> <Type, Component> for lookup
Archetype -> Entity[] for system processing
ID -> Entity (object, stored to avoid re-creating)
Or actually
Yeah there that's it
oh so each entity manages its own components?\
I have HashMap<Type, SparseSet<usize, Component>>
because in systems, you don't care about individual entities
you care about the general population
so it'll be better for CPU cache this way?
Yeah that's fair enough but then the issue arises of accessing speed, in my case each entity is given a unique archetype ID, this ID is then used to instantly know every entity in the universe without doing any further lookups
I.e. the accessing speed to get every player is O(1)
Same for every say zombie or zombie-like entity
Etc
hmmm interesting
You straight up ignore the cache because the arrays are also contiguous in memory, as each component is an ID into the global component table
Act no that was the old one
Current one doesn't have a global table anymore (faster)
But still yeah all of the data is thightly packed together
thanks for the idea :)
Haha np :P
good luck with your idea. you're doing it for minecraft right?
The state is actually in the entity for me, you do entity.get(Health.class)
huh? how?
wont that take way more memory?
even if you have a atomic shit, it still saves it
It's in the universe but the entity knows what it is from an id
Basically an entity is just two IDs
heh
Considering that I could hold 100k entities in around 1MB of ram it's not too bad
Java ram overhead go brrrr
dang how
mine takes WAY more
my rust skills aren't the best
it would be entities with position and maybe another component such as health
yeah no you could store that in 100b per entity
position is around 24 and health around like + another 4, so 28 bytes
do you support multithreading?
no actually, add 32 on top of each comp
actually no I'm dum
That is for arrays
assuming you're on a 64 bit system
entities are 48 bytes, each component is 16 + data, so in this case it would be 32 for position and 20 for health, so exactly 100 bytes
Smh integer health
float better
Fixed precision numbers
I mean yeah I guess
Fair enough sure you can just use a float, doesn't change the memory usage
Though there is a downside
there is inherently some more storage to take into account to hold the archetypes
And to hold the components
it ends up not being 100k entities, it would be 100k entity objects @ 100 bytes per, but then there is collection overhead
12.3 MB for 1 million plain entities
tf
12 bytes per entity?
8 bytes for the entity itself
and 4 bytes for uh
Dayum
let me try with position
mine would be around 46.8kb for 1M plain entities
88 MB with position
Plus collection overhead but idk how to calculate
I can actually lower this by using the entity object itself as the entity ID
because java already gives me a unique ID per object which is part of the 16 bytes
removing 32 bytes ish
around 15.6kb per 1M plain entities if I do that
82 bytes per entity with a position (double*3) = (10 million entities took 808 MB ram)
dang tf
do you support multithread?
Not yet
It would be insanely hard to support multithreading in mc
but it does support regional collisions
and regional entity lookups
So basically entities are ran through the position system, this system basically sorts entities into an octree so that you can access an area extremely quickly and disregard the rest of the universe
octtree takes a shit ton memory no??
last time i tried on a 100k or a million entities and it took almost 16 gb ram
No WHAT?!
An octree is either nullptr or pointer to either another octree or an entity index start - entity index end numbers
each octree element is 16 bytes
i just realized. a million bytes is about a megabyte. how do you get 15.6 kB?
I multiplied size in bytes * 1M / 1kb
basically
16 * 1.000.000 / 1024
hmm
lemme thonk
Ah yeah I'm DUMB
it's 15MB
or 68MB per 1M entities with pos and health
though I can lower this
considering that mc only uses 8 bytes for position
I can do the same and actively edit the number
and then that would bring it down to
60MB
not bad?
also the issue here is using two diff components btw
I FOUND A SOLUTION
@willow bone
I turned 100M entities into just 36MB with pos and health
How does mc use 8 bytes for position
sacrifices the y axis
Eh?
How does that work for stuff at decimal positions tho
¯_(ツ)_/¯
actually
mc uses deltas to signify position
they send 6 bytes per delta
and uses 24 bytes per teleport
so actually
still 12 bytes
40MB
eh
bro what
100m is 100 mb
rn it is 40 bytes per entity with pos and health
wait NO I FORGOT ABOUT JAVA OVERHEAD
KMS
wait no that's not in the entity
poggers
nice nice
here: https://www.pixiv.net/en/artworks/59406498 (this is the original, you can probably find bigger sizes if you put it in google though)
ty
np enjoy
https://github.com/radstevee/readycheck made a silly little plugin for a friend (in java 😨)
is this a fancy way of checking if some number of players are ready before some action can proceed?
what are we getting ready for? 🐈
yea pretty much that
||(we love java ☕️)||
we love kotlin
anyway, the first thing that stood out to me is ChatListener and how it's getting an instance of the plugin just for registration, which could be moved to the main class itself via some dedicated method that accepts registerEvents(Listener... listeners) or something like that ¯_(ツ)_/¯
i love a good plugin class singleton
but I do agree on passing the plugin instance in your chatlistener instead of getting from your main class yourself
which is just coupling that isnt needed
singletons my beloved
yeah that's fair I'm just not a big fan of that
i would just make it a variable passed in the comstructir
idk like maybe in the future you want this listener to check other stuff about a plugin like getting a resource or smth
also really nitpicky but in the ready command I would put the failing conditions at the top, not at the bottom
which in this case would make it an early return
yeah true
I just realised
I named the class RecollectPlayers instead of RecollectPlayersCommand
Pass the instance or use a static field instead
https://github.com/radstevee/readycheck/blob/master/src/main/java/net/radstevee/readycheck/ChatListener.java#L12-L14
Might be worth creating Permission objects instead here so plugins like LP can pick them up automagically.
https://github.com/radstevee/readycheck/blob/master/src/main/java/net/radstevee/readycheck/Permissions.java#L10-L11
Otherwise lgtm
I register perms in my plugin.yml if that's enough for stuff like LP
perms work without needing to be Permissions afaik
call ur main class ReadyCheckPlugin, use real getters (tragedy no kotlin)
fluent getters are real getters
they're great
wtflip
The only real argument I’ve heard against fluent command and queries is that with get/set you can prompt your IDE to list all the “traditional” getters and setters (suggestion+/completion), and that it’s technically stricter by specification than fluent command and queries
it is really not that big of a deal honestly
maybe because I'm used to look at the javadocs instead of depending on the auto-completion I guess, even if I get all the getters by doing get, often times I want to read what the get these do as well
this is the reason I hate bukkit commandexecutors
I'd end up doing this with reflection lmao
I mean it used to be more useful when people were strictly abiding get/set for data encapsulation, now that record components stray away from this, it has become less of a standard so get/set won't net you all getters, setters, data accessors and data mutators anyway.
I was hoping you'd notice the pun in my message lol
umm I think you guys missed this 😭
Why did you suffix it optimized? Out of curiosity
its super asnyc optimized deluxe async perforamce ++
multithreaded
It sounded better lmfao
It's a joke just in case you didn't get it
I am, for the most part
but I do like consistency if anything, so mixing up fluent getters/setters with non-fluent ones is a no-go for me
there are cases where it can't be helped but if you can avoid getting inconsistent naming then better
Do you think Brig is gonna be any better?
I assure you it won't be lol
At least with regards to this specific problem. You still have to specify command arguments and what they execute
If you don't want to be passing through your messagesConfig and messagesManager to these methods, make them fields or something. Or get them in the methods
Oh okay Bukkit is just objectively bad for something Brig does the same
Gotcha
I mean
If you look at a vanilla command implementation, it's pretty similar, only it uses a builder pattern instead of if/elseif
At least you don't need to manually parse with Brig
Yes but here specifically you're complaining about the if/else chain
So >:( Be specific when you complain
hehe
I just hate Bukkit CommandExecutors in general, had to use em recently
Except that I didn't need any argument parsing luckily
Lucky
I usually use Cloud for plugins, but Brig is also amazing
I used to use Brig but I switched to Cloud
I use annotations because I really don’t like writing command argument parsing code or anything
I just want to write the damn function of the plugin, I don’t want to write command argument parsing logic!
Commands.register(literal("idk")
.then(literal("reload")
.executes(this::reload)
)
.then(literal("give")
.executes(this::give)
)
.then(literal("delete")
.executes(this::delete)
)
.then(literal("reset")
.executes(this::reset)
)
.then(literal("migrate")
.executes(this::migrate)
)
.then(literal("open")
.executes(this::open)
)
// help not needed anymore considering the client will suggest proper args ?)
);
it looks horrible no matter how you refactor it, I'll give you that
I'm not sure that is better lol
But yes, Javier gave a good example. You're going to end up with what is essentially an if/else, only it does it with a builder
Command registration is always gonna be a PITA
I believe that can easily be solved by making a DSL
Cloud is eh, I always felt it is overkill for anything simple, just too much engineering going on there
That's true but that's also great for bigger and more complex commands
don't know what their v2 is looking like right now though, has been a while since I looked at it
Hate to break it to ya but that is kinda part of the plugin :p
eh, frameworks like cloud exist for that very reason
Why is everyone so keen on using the wheel instead of reinventing it smh
their annotation-based stuff is essentially for those who just have a very declarative command tree and want to center on the actual command logic
||this is why I just use Skript for commands||
yeah but i'm not spending my coding time handling argument parsing
the frameworks exist to minimize that
the feeling when you write a command abstraction for the fifty-eleventh time
🥲
don't
playerkits 2 is good
ajneb's is better
Umm, I need it for a server so I gotta add some more things to the API
Also, I'm learning so it's a win for me.
mhm
you guys wouldn't mind if I ask you to review my lib which uses both minestom and paper?
Put it here
I will put in a bit I saw some small issues need to patch it up quick
maps:
why are you doing this in the kit manager
"milion" 😭
Looks legit to me
color a && tree /S
wait no
yeah no that's correct
yeah I mean the 1.8 color codes are just default colors on windows cmd
lol
Theyre the CGA colors
Back in like 3rd grade I almost got expelled for doing tree C:\ in a while loop because they thought I was hacking
lmao
that couldn't've happened to me because we don't have computers in 3rd grade kekw
that was like 10 years ago or something, don't remember what age I was in 3rd grade
yeah so around 6yo for me then, which again, we only had computer lab next year?
and it was mainly just scratch
We had to go there for learning how to use a mouse and shit
lmao
my teachers got mad at me when I was 10... because they had this website blocking software... I bypassed it by setting a proxy on the browser and gave it to my friends... I got detention D:
was fun tho
Lol in my hs it seemed like they didn't care it was pretty well known I had remoted linux on my chromebook and never got talked to or anything
ahahah
Like I had IT people walk behind me whole I was coding on Pycharm on an arch OS
in secondary/high school I also managed to bypass their security and got admin on one of the pc's... could do literally anything
shouldn't be saying that but anyway
One of my friends got expelled for hacking his schools mainframe 💀
LOL
literally on the pc I managed to replace the shift lock with cmd (windows 7, back when I was around 13-14), opened up cmd on the logon menu, did net user, and set myself as an admin
that's the pc I got admin on
Tbf you got security problems of the bored autistic kid hacks in on a whim
🤣
You could run a lot on my school computers cuz they had python on em
Anyone with an ounce of knowledge could do a ton
Wasn't secured or anything
wtf
I was able to change env vars and registry access from python
I feel like schools always underestimate the kids who like tech
nah deadass
in my college (a week ago) I literally just made such a simple program into a class, methods with returns, params, and in/out stuff. Literally basic shit. And my programming teacher was impressed 🤣
c++
Think my favorite thing I've made was some stupid project for one of my compsci entry level classes for java but I wrote the entire thing in Java Reflection
I got 100% on it too even though one of the requirements was the code being concise. I will tell you when the class is 500 lines of reflection and the top is like
@Input("Enter One Number")
@While("number", Integer.class)
@Input("Enter A Second Number"_
...
If I were to take a class right now I'd probably write everything in bytecode using ASM lol
i'd just bootstrap my jar so they could run it
honestly one thing is - I've been doing java since I was around 12, but I do say 6 years because I like to keep it humble, as I didn't really start learning proper shit until I was 13-14. 20 now, so the route of programming is going quite well
I didn't start java till 2021 and I kept taking month breaks cuz i was stupid so I kept quitting
I mean even now I can't even tell you every nook and cranny about java
only recently I've gotten good at it
within the past 2-3 years I've actually been trying to get better
I've always been great, guess its my inate talent to make Inventory PRs
😂
I've only been using Kotlin for about a year now but can tell you about I'd say 80% of the languages features
I mean I think I know every java keyword
oh so you know java? name every class name
public - obvious
private - obvious
protected - makes it accessible to sub-classes for inheritance
blank - makes it accessible to package-private, allowing only the classes inside of the package allowed to access it
volatile - make the (primitive) data type visible with updates to all threads
... and some more
InternalFrameInternalFrameTitlePaneInternalFrameTitlePane
ah yes that's every keyword
not every one but yknow
😂
I just don't have time to list them all out
and kinda cba
I meaaan volatile prevents compiler optimizations also
:>
What about strictfp!!!1
native
non-sealed :D
sealed
const!

https://paste.md-5.net/icadokeyez.java
What do we think
Since you're already using paper, they have ItemStack#editMeta
I usually just do something like this so the scope is this and it returns the stack again: ```kt
inline fun ItemStack.editItemMeta(block: ItemMeta.() -> Unit) = apply { editMeta { block(it) } }
inline fun <reified T : ItemMeta> ItemStack.editItemMetaSpecific(crossinline block: T.() -> Unit) = apply { editMeta(T::class.java) { block(it) } }
visually i would choose other particles
i would want to see that disc flying, rather than lots of particles blocking the view
codewise i would trim down the methods, reduce boilerplate and put the complex equations into a descriptive method
driver and disc are a bit misleading. i would not know what that should be without looking at the code
personally i would turn ThrowTechnique into an interface, and then make an abstract BaseTechnique or AbstractTechnique which then is the base for further techniques
There's gonna be a model and shit for that in the future
make them available for combat as well, could be a cool technique
Eh?
Elaborate
This is a disc golf mini game system so I don’t understand what the heck id do with combat
I'm also not sure any of those suggestions are really beneficial lol. You could maybe compact down your switch case with a more generic method to reduce duplication but that's really about it
The terminology of those classes is fine. The "Driver" is a type of disc. Akin to how there's a "driver" type of golf club
I also don't think the throw technique needs to be overcomplicated into an interface. It's just not necessary. Abstract class is fine
I assumed they had no idea what the point of this whole system was for so yeah kek
If you want to get super critical you could maybe argue you could rename Driver to either DiscDriver or DriverDisc, whatever. Some people (myself included) like to link types of objects together by name
That's preference though tbf
private final String technique;
public ThrowTechnique(String technique) {
this.technique = technique;
}
public String getTechnique() {
return this.technique;
}
Also not entirely sure why you're passing a "technique" string to a throw technique. Is this better named as "name"? Or "description"? Or is it something else?
Registry key
Yeah then maybe "id" or "key" would be better imo
Sure sure
Feels weird passing something called "technique" to a technique object :p
Yeah no for sure lol
Other than that, code looks fine. Like I said, you could maybe compact down your switch so that each block just calls a more generic method, but I wouldn't even stress too much about that
Mmm maybe, there’s a lot of techniques so that switch is gonna be duplicated a lot
Though the physic manipulations will be different
kek
Visually speaking, what do we think?
(I pinged you in general with the irl reference)
Looks good
Why thank you
Past what like 2 weeks or something, been doing so much god damn math
Really happy with how this looks currently
Please, opinion on the idea if it's worth or stupid (the impl is not finished ofc, just wondering if making this makes any sense)
public class CacheWrapper<T> {
private static final ScheduledExecutorService SCHEDULED_EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor();
// Some weak key based cache which is going to remove the entry after 5 minutes if the object hasn't been used for all that time
private static final Map<Object, CacheWrapper<?>> cachedObjectsMap = new HashMap<>();
private final WeakReference<T> storedObject;
public CacheWrapper(T object, Consumer<T> cacheAction) {
this.storedObject = new WeakReference<>(object);
cacheAction.accept(object);
SCHEDULED_EXECUTOR_SERVICE.scheduleAtFixedRate(() -> cacheAction.accept(object), 0, 1, TimeUnit.SECONDS);
}
public T getStoredObject() {
return storedObject.get();
}
@SuppressWarnings("unchecked")
public static <T> CacheWrapper<T> of(T object, Consumer<T> cacheAction) {
return (CacheWrapper<T>) cachedObjectsMap.computeIfAbsent(object, wrapper -> new CacheWrapper<>(object, cacheAction));
}
}```
Methods which return CompletableFuture aren't not easy to work with, especially when you have too many of them nested
```java
networkInstance.getNetworkPlayerMap().sizeAsync().thenAccept(size ->
networkInstance.getNetworkMemoryUsage().thenAccept(memoryUsed -> {
sout(size + " " + memoryUsed)
})
);
Turns into
val playersOnline = CacheWrapper.of(new AtomicInteger(0), value -> value.set(networkInstance.getNetworkPlayerMap().size()));
val memoryUsed = CacheWrapper.of(new AtomicInteger(0), value -> value.set(networkInstance.getMemoryUsage().join()));
sout(playersOnline + " " + memoryUsed)
Essentially, this is about objects which can be cached. I was thinking about Hypixel at the moment of writing this.
For example, they have a scoreboard which displays amount of online players on the whole server, let's say that the values on the scoreboard are updated every second and there are 50k players on the server seeing this scoreboard. This would mean, that 50k queries are being processed to the network every second, that's a bit of overkill (I was imagining they use redis and maybe keep players in some RMap).
So, instead of 50k queries/sec to redis, with CacheWrapper we do 1 query/sec instead. I wanted to think of something reusable for other cases and not just one that specific problem, otherwise it could have been done differently
but why
if there is anything heavy what is called frequently, then it can be used with CacheWrapper to decrease load to the servers. Pretty much the example with Hypixel which he's provided
I believe that's what he meant
CacheWrapper is to cache objects whose values change over time
so just react useState
wdym
what is the benefit of this over using something like Caffeine with an expiry after access eviction rule
then again, I'm not sure whether there's worth in caching the cache
well, I retract that, since when dealing with distributed caches, there's some worth in having a local one. I just don't usually go for that approach since it makes things unnecessarily complex
Cache<Cache<
Is it a concern? https://gyazo.com/58c124acacc47c813f1828a704a79628
I mean, if you are using Redis, it gives you all the leeway to go for more shards if necessary
CacheWrapper is supposed to use Caffeine (instead the map it uses), this way you don't need to create a separate class which is scheduled to update amount of players every second, CacheWrapper does it for you in a convenient way
but CacheWrapper would effectively be a single method to abstract out the getting from the cache
I don't find that particularly useful, however there might be more of the picture I'm not seeing here
What I should add to my gui library? https://github.com/NazarbekAld/XeXeGui/
There's examples of existing features: https://github.com/NazarbekAld/XeXeGui/tree/main/tests/src/main/kotlin
If you are willing to go for a change of focus: in general, if I want to do a non-trivial multi-tiered cache I'd use something like Spring's CA however using it outside of the Spring ecosystem is not really intuitive, so if I have a Redis cache layer then I'd end up using LocalCachedMap, or if I use other distributed cache options (i.e., hazelcast I believe provides a similar abstraction to what you're proposing now). Maybe a way to orchestrate all of that outside of Spring would propose more value, as nobody likes dealing with multi-tiered cache and making that more easier would definitely be a great scope
that said, it is infinitely harder to get that right, so be it as you will
like my plugin
Thanks for an advice, I use LocalCachedMap but that's for statistics mostly, things like player count what is an integer and can't be easily cached in caffeine since it always changes require a little work around, that's why I thought CacheWrapper might be a solution for this problem
https://github.com/NormalManV2/NormalDiscGolf
Any advice for any area appreciated ❤️
- Missing Readme
- Package name should be lowercase
- NDGApi has no real reason to exist? Everything is already present and accessible in the NormalDiscGolf class.
- Separate api from impl and place it in it's own module ^^
- Put test in it's own module (if you plan to keep those commands instead of using unit tests, otherwise move to src/test/java and use something like MockBukkit)
- Optional: Make a builder for your discs, record + record builder recommended :)
- The I prefix in the ITeam class is reduntant
- ITeam interface is not in api package
- DiscThrowEvent and GoalScoreEvent should be part of api
For project structure I recommend looking at LuckPerms
Any syntax issues if you read that much into anything?
Didn't look too much at the code itself
Ah nw
wheres @woeful pasture when we need him
centralize services around one api singleton
unless u're working with a really pedantic and complex system, keep it simple and minimalistic when u utilize static state
Fair enough ❤️
Pointless Abstraction https://github.com/NormalManV2/NormalDiscGolf/blob/master/src/main/java/normalmanv2/normalDiscGolf/impl/team/ITeam.java
Another Pointless Abstraction
https://github.com/NormalManV2/NormalDiscGolf/blob/master/src/main/java/normalmanv2/normalDiscGolf/impl/skill/ISkill.java
Is there even a point in skills sharing a common parent. It seems like literally every single skill is just inherited for some reason, but no actual extension is added. Is their even a benefit in a shared ancestor here?? I feel like a lot of these abstractions are just for the sake of "because OOP" versus actual intelligent abstractions. This entire skill thing could be done with a Map<String, Skill> If you ever wanted to add some form of modifiers to the skills you can literally just compose functions within the skills.
I feel like the whole "ThrowTechnique" Stuff could technically be implemented better but honestly its good enough as is
don't worry I'm here now
as soon as you start with "I" for your interface you know you have too much abstraction
or you are using C# 🔫
c# is not an excuse to have bad naming conventions
Having I for interfaces is part of the C# convention
^
All of their interfaces have it
in java we have extends and implements to tell them apart
than C# is a bad excuse
one could say :>
but in any case my point was more paired with teh fact that in java if you use I it means you probably have a class that implements it without the I, as in these cases. Which makes it kinda awkward to have any other implementation
since then the naming is weird by default
like if you have a ExtraSkill, why would it implement ISkill if it can just extend Skill
well I mean its been proven often that having an over-abstracted system is preferred to an under-abstracted system, especially long term and when you start writing internal library modules and components
in fact thats what all the skills are doing anyways
yes, but I would pick your names better
100%
Well I moved all the interfaces to the api file anyway, I don’t understand why it’s considered a useless abstraction in terms of the skill objects, I feel like I was being lazy and didn’t want to actually write the getter/setters for each
Renamed the interfaces as well (without the I)
But if I could have a better explanation of why the abstraction is considered useless?
tbh
i didnt read into ur infrastructure
but writing apis is hard
cuz every class can be considered an api to its consumers/users
every module may have a set of classes that are interfacing the module's functionality to the rest of the system etc
there's the literal interface in java, but api can mean a lot less, and a lot more
for example luckperms
they have an api module, but thats for other plugin devs
then they have their own module apis, that is internal abstractions to make the development within the project easier
So do a lot of people design in a way that’s like “internal api” versus an external if you will
esp when u have a lot of contributors and collaborators and you have to meet certain standards etc
yea
on a package level, module level, system level, project level etc
Mmm I see
this is also something programming languages usually dont provide any semantics to us
meaning there's for example no built in annotation to communicate if a package, or class is an internal or external api and to what audience said api appeals to
@ApiStatus.Internal iirc exists in jetbrains annots library
but thats 3rd party
however, prefixing an interface with I is goofy
esp in Java
kotlin internal:
(just public to the JVM)
ah w for kotlin
Tbf that’s only because they were in the same place, moved now and naming conventions are fixed
It wasn’t meant to be permanent naming, just for the sake of the ide not yelling at me
All the interfaces were moved to the api package, though I feel GameRound could have remained where it was... not too sure on the semantics of api design obviously so
alr so ur api sucks
Yeha
Honestly could not give you a reason... I just moved all the references there because I felt like main was getting bloated kek
Eventually the goal was to make things accessible to other devs yes
okay well, u probably completely wanna hide internals then
that is anything in the impl package
from 3rd party devs
So in other words, the api I have is useless
i guess you mean api for programmers that wanna hook into your plugin from theirs?
More so from an "extension" standpoint but yeah
or is this api intended to just extend your plugin directly
That was the idea at first, but now that I'm hearing all this, it seems that's not a very uh supported way I guess lol
Like I said eventually the goal was to allow 3rd parties to make their own extensions/adjustments kinda thing
the point of having an api module/package for other devs is that u can change the implementation of ur plugin without forcing plugins that depend on ur plugin to change
primarily
there are some other nieche things about it also
but else, its not so common to centralize interfaces in one package
usually u put classes in package by functionality or something like purpose
I was thinking the only 2 interfaces that really make sense to stay in the api is skill and team, but then again the children are internal impl obviously, so does that even make sense?
barely
I guess I just don't really understand what should be considered internal/external
the api should probably be created separately from the rest of the code
and not also be the core of the implementation
you should be able to compile the api code without having the rest of ur code on the classpath
So then again, my api is useless right now kek
little bit
it just looks like u were doing something for the sake of it
with no real goal in mind
Don't sugarcoat it, I can take it man... I'm here to learn lol
Correct lol
My idea of an api was to provide the accessibility to whatever I needed so perhaps I just don't understand what should be put where
public class Team implements normalmanv2.normalDiscGolf.api.Team {
private final UUID ownerId;
private final Set<UUID> teamMembers;
public Team(UUID ownerId) {
this.ownerId = ownerId;
this.teamMembers = new HashSet<>();
}
@Override
public void addPlayer(UUID player) {
this.teamMembers.add(player);
}
@Override
public void removePlayer(UUID player) {
this.teamMembers.remove(player);
}
@Override
public Set<UUID> getPlayers() {
return Collections.unmodifiableSet(this.teamMembers);
}
@Override
public UUID getOwner() {
return this.ownerId;
}
}```
So when it comes to the "pointless abstraction" bit that miles mentioned, the team object is meant to be used as a disposable object if you will. As for the skills like I already mentioned, I was being lazy and didn't want to write out those bits in each skill
why not import Team
I could see how the team object doesn't need to implement a parent considering the usage goal... still though am a bit confused on the skills aspect
ide did that automatically when I refactored 🤷
i mean sure it could be considered pointless
it just depends on what ur appeal of the situation is
I generally abstract over almost anything because I often write unit tests, and Ive found that having interfaces can be really nieche long term for maintainability and reusability
^in the domain of object orientation
I generally try to avoid abstracting anything when starting out a project
just prototype till I get the idea right, then start abstracting
it doesn't have to look pretty from the get-go, it just has to work
very true
hard to predict what the ideal structure is gonna look like before u write it
then again, everyone has their methods and it doesn't apply for every situation, but it usually helps harnessing the scope of the project, whether it'll be a time sink or not basically lol
public class Skill implements normalmanv2.normalDiscGolf.api.Skill {
private int level;
private int maxLevel;
public Skill(int level, int maxLevel) {
this.level = level;
this.maxLevel = maxLevel;
}
@Override
public int getLevel() {
return this.level;
}
@Override
public int getMaxLevel() {
return this.maxLevel;
}
@Override
public void setLevel(int level) {
this.level = level;
}
@Override
public void setMaxLevel(int maxLevel) {
this.maxLevel = maxLevel;
}
}
...
public class Backhand extends Skill {
public Backhand(int level, int maxLevel) {
super(level, maxLevel);
}
}```
My thought in terms of the skills was to enforce the structure by parent... though internally I only use the skill object to determine what skill and what the current level is, perhaps someone else wants to make a skill differing from my impl
Jeez man writing clean code is hard kek
man use actual names that don't conflict with each other 😭
I know thinking of names is hard but just adding Impl or I at the start should do lol
BETTER THAN IMPLEMENT my.long.ass.fully.qualified.name.bc.im.lazy.Skill
I'm still confused what the rational for having a skill interface is
same with Team
if you just abstracted it because why not that's probably not a great reason. There is such a thing as too much abstraction. Its not like the interface is good API either
so I'm confused
I think laziness is the biggest reason
I just thought it'd be best to enforce the structure, but even then I can't find a reason to keep it how it is
then dont
Actually, I feel it just makes me try to think about how the structure of the object should go so to be fair, I think you could consider those interfaces as placeholders if you will. I guess I just like to think of what an object should look like and designing an interface for said object just makes that easier for me
It's changed lol
yeah thats fair
there are also other options like making silly diagrams that arent part of the code
Yeah it'd probably be a good idea to take to pen and paper before writing the code
Idk it seems like I love to write something out (whether its shite or not) get it reviewed and bum off others experience to make it better kek
Should I think about interfaces like this? An interface provides a concrete class structure in which the implementations may differ method to method
And a superclass like: A superclass provides default implementations and variables for it's subclasses
An interface is a sort of "contract" that defines a structure of its implementing class. One of its main purposes is to create a strict boundary between "how it works" and "how you use it"
Check out dev branch
This guy dm spammed me this api
Same lol
Yeah he likes to do that
this my friends is why you have your DMs off
knowing this though I will probably not be incentivized to actually review this lol
hold up the real play here is for him to use Pineapple
the ultimate spigot library soon to be paper exclusive
kek
My DMs are just open for wor.
BRO SAID WOW 💀
Indeed he did
Why do ppl use 362 APIs?
Oh, NBTAPI...
I mean just use NMS
You're not gonna need all NBTAPI methods
Saves time
Yeah but uses a lot of reflection
on methods that you are probably not gonna use
Idk, that's my opinion
Reflection is pretty well optimized now
True but if you're modifying so much NBT that the performance matters you're doing smth wrong
And this
I mean to people just forget about how its backed by Method Handles which can, in some cases, achieve native call performance?
Yeah, i know, but why do you need NBTAPI?
pre PDC type shit
or if you need to modify some non exposed field
You are gonna learn a lot more if you do it by yourself
Yeah the JVM can inline handles
praise lynx 🙏
Also, i started reading other people code and i think my plugins is absolute GARBAGE right now
That's why im recoding it
probably because it is garbage right now, but for ever garbage line of code you write you learn a little bit more 💯
I personally like to spend the time figuring out how to do something myself, not only then do I better understand the underlying concepts but also I feel it helps me connect other dots perhaps when it comes to another system
It's also hard to say that what someone else has made will work for my specific goal
Yup, i think this is a signal to say "psst! you're starting to learn"
