#[MEGA THREAD] Get Your Code Reviewed or Review Others
1 messages · Page 17 of 1
it gets annoying when it comes to arguments in the message
Yeah
well, if you want named arguments and not just %s in your string
what's with all the functional interfaces
NullComponent, UniComponent, BiComponent and TriComponent
For number of arguments
Then you just do
Message.HELLO.build(arguments)
And get your component
<certain "fork" that shall not be named> has i18n support + adventure has an MM translator now
I would just have made it a bunch of static methods in the Message interface which take a Function/BiFunction, etc
and make Message an enum instead of an interface, but either approach is fine
yeah, that sounds fine to me
I'd make a plugin template from it and you'd be good
I always meant to make a cli tool for that which would allow me to generate them easily but I never get to it lol
not that I make much plugins nowadays anyway
Yeah
I don’t really make many
I only do like maybe one or two at once
Nothing more or less
Things just kinda get boring after some time
yea I prefer working on other things ngl
MethodHandles generally fix that, iirc their speed is nearly the same as invoking the method directly, and the lookups should be faster, too
Discord placing me 200 messages back will never not be funny
If you're using method handles as static variables and just calling invoke repeatedly on a psf it's the same speed as direct invocation
Measurably so*
ok but that isn't all of reflection
Well yeah
But realistically you should use reflection for few purposes other than that
Main one is probably proxy instances
yea reflection now "dynamically generates bytecode for ::newInstance and ::invoke"
Or registering events like spigot does
and VarHandle/Unsafe access for Field::set/get
MethodHandles iirc just straight up use the actual method handles java uses for lambdas
depends how u define ur method handles
lambdametafactory does that tho
but its complicated to use iirc, gets pretty damn verbose
No kidding! Verbose is surely an understatement
🥲
I mean yea, you'll usually use reflection for configs
Yes, I can't find any other use.
reflection has a lot of use cases
Like?
you don't need to ping me for every single message
accessing private declarations is one that many people use it for
Oh, I'm not really looking to use the ping thing, just really reply to the message
Ah yeah that is ok
In general, reflection is nice for scanning classes dynamically at runtime
HI guys, I was trying to use reflection for a config stuff
class LunarisSpawnerPickaxe : JavaPlugin() {
companion object {
lateinit var instance: LunarisSpawnerPickaxe
private set
val configContainer: ConfigContainer
get() = ConfigManager.get(ConfigContainer::class) ?: error("ConfigContainer not loaded")
}
override fun onEnable() {
instance = this
AdapterRegistry.register(ItemStack::class, ItemStackAdapter)
ConfigManager.initialize(this, ConfigContainer::class)
}
override fun onDisable() {
// Plugin shutdown logic
}
}
for this class it works, but it takes 8000ms (8 seconds, sometimes more seconds) to load, is it a normal behaviour of using reflection or can i optimize something
@Config("config")
data class ConfigContainer(
val host: String = "localhost",
val mySubConfig: MySubConfig = MySubConfig()
)
data class MySubConfig(
val port : Component = color("asad"),
)
i reduced it 2s load time, now is 6s, but yeah, is still high
should i make a Node system like configurate
this is a bit excessive and jank at the same time but take a look at this as some example https://github.com/PineappleDevelopmentGroup/Pineapple/tree/dev/pineapple-core/src/main/java/sh/miles/pineapple/config cache the fields, wherever you physically dont loop. the only time you basically need to loop is once on the classes fields on save/load
so my code is trash
i need to recode it again, for third time
The life of a developer
in mc terms, hooking into internals
oh sorry
i was readin old messages lol
that's still ridiculously slow
probably wanna profile that
mine loads pretty quickly: https://github.com/radstevee/axi/tree/feat%2Fconfigurations/core%2Fsrc%2Fmain%2Fkotlin%2Fnet%2Fradsteve%2Faxi%2Fconfig
public object ExampleConfig : Configuration("toml", "config") {
public val string: String by string() or "hello world"
public object NestedSection : Section("section") {
public val num: Int by int() or -1
}
}
Yeah that’s certainly something, mine usually loads fast enough I don’t even notice
So my code sucks
I'll recode it later
Guys, do you think my code is well optimized? What can I do to make it work better? It's designed for a large client server. It works well, but I don't know if it's the most optimal way to manage regions. I want regions that can't be accessed under certain conditions.
Main: https://pastes.dev/PyqvaKYbQn
ZoneManager: https://pastes.dev/OWUwuPxx6P
ProtectedZone: https://pastes.dev/yEryBCS5Vz
You probably want some sort of spatial data structure to handle regions
R-Tree, Octree, etc
is that region forms?
No they're tree data structures
idk what is that actually
seems like you should go learn these things
otherwise you will never know if your code could benifit from using those things and making it perform better
however though generally you shouldn't be trying to optimize something if there is currently no problems
mmm probably
https://paste.md-5.net/obugohemel.java
https://paste.md-5.net/rowokozipi.java
https://paste.md-5.net/gozirohume.java
It's certainly not as straightforward as I'd like it to be, a lot of mashup generation algos in here but is returning a somewhat decent result (apart from worldedit paste bugs on my end), still have to work on chunk meshing and what not
https://paste.md-5.net/sogewoloda.java
Updated, implemented better boundary validations, generation attempt cycle, and changed some of the weight factors to make it more balanced in terms of obstacle variety
is this for your like throwing game
Disc golf
Yes
I'm sure this idea has been implemented in several other places. I'm developing a library, and I don't want my users to interact with an internal component (in my case, it's a native matrix). But within my library, I want to be able to access it in other classes, because using the native matrix would be very fast. Since my classes are in a different package from the internal component, it's not like I simply put it as protected and call it a day
Dependency Inversion
My idea is to use some examinable interface where there are properties. For my internal component, I will assign my native matrix to like some key that can be accessed
Put the methods behind an interface but the native matrix as a public variable that's only accessible by explicit typing
You can find an example in my pinned good habits post
they are behind an interface
But the issue is my interface has like a 1000 lines of code because of the amount of impl possible
its not ideal
I can't because my filters interact with the interface
you can split it up and make an interface that extends a dozen other, no?
So you want the filters to have access to fast shit but not the extending classes hm
That way no direct access
But i can access via my own api
and maybe some very dedicated users if they rlly wanted to
could get it
normally i would stuff them into the same package, but with the possibility of tens or even a hundred different impl, thats not really ideal
https://github.com/dbrighthd/gendermodspigot @jagged rock spent some time to refactor and clean, what u think now
Before I berate you for a million things ask yourself
Can you notice something, anything I'd complain about?
possibly the enormous constructor signature for ModConfiguration
maybe how i could create other classes to move certain logic outside of the main plugin class (for cleanliness sake)
debatably i shouldve used getters for the fields inside of the main plugin class
im still lacking added documentation in a few of the classes
Let's worry about actual code rather than javadoc
Before actually understanding any of the logic the first thing that stood out to me, in the main class was the lack of consistency and purpose
The styling across these is inconsistent
would u prefer early-return when target != null?
I'd prefer if your if statements had braces
ah
I'd also prefer for it to be a separate method so you can reuse some code
something like trySendModData(player, ModConstants.SYNC, fabricData) where it does a null check
and maybe just maybe a sendModData(player, fabricData, forgeData)
that you then call in your loop or whatever
If you get fancy you can do some abstractions with things like PacketAudience that can be a single player or every player in the server
PacketAudience audience = target != null ? PacketAudience.player(target) : PacketAudience.allPlayers();
audience.sendModData(ModConstants.SYNC, whatever);
audience.sendModData(ModConstants.WHATEVER, whateverElse);
but that's overengineering
Regardless
This should be a separate class with some kind of registry with lambdas
As a freelance developer the thing I most hate is having to fork a plugin because they're doing something stiff like this
at least in this case I can hack into it using reflection but still
i did actually think about that, and reminds me of using Photon Unity Networking (where it has either PhotonTargets), but i just opted to not for reasons unknown [laziness]
You have a logger, ex.printStackTrace instead of something more robust is at minimum an IDE warning (you chose to ignore)
I'd also prefer for a traditional entrySet for loop for modConfigurations instead of the glorified .forEach
Avoid repeating these calls a million times
Something like Sonarlint would've yelled at you that the logger can do this kind of formatting, which might save 2 clock cycles if the logger decides your message is irrelevant
Realistically broadcastModData should be in a separate class anyways
So should modConfigurations as an encapsulated map
welp I think that's enough for the main class
ModConstants lacks a private constructor
a, ur gonna yell at me for this at least 2 more times i think
ModConfigurationBuilder should do sanity checks before allowing you to build without any params set
private constructor, public static factory method expected
ModConfiguration having a million constructor params is icky and it should be split up into several classes
ModSyncPacket#getModRange should return some kind of custom class that facilitates with checks
such as .isApplicable or whatever, using strings is icky imo
This could realistically be a private constructor that takes an InputStream and a million static factory methods that take all sorts of inputs like bytes
more ifs without braces
no event priority?
is this particularly a necessity?
at most id put MONITOR, i guess
id be stating that i only intend to react to the event, and not mutate it
i dont mean to nitpick your nitpick, im just genuinely interested in the significance of actually specifying a priority
you want to be the first to know when whatever fires
On your PlayerQuitEvent if you have some other listener that depends on your plugin and you unload the data before them you're just causing an inconvenience
i suppose
something like this?
im not too sure what u mean by this, theyre called only in onDisable, and the ones to enable them are only called once (per channel) in onEnable
there is no vararg method in Logger
plugins use the java.util Logger, not log4j Logger
otherwise i would be using varargs, lol
installed sonarqube... it doesnt complain about something that looks equally as autistic
lets goo
guys i was working on this package, https://github.com/system32developer/SystemCore/tree/master/src/main/kotlin/com/system32/systemCore/managers/regions, could you review it and give me a feedback (it is a false rtree somehow)
Rewrite it in Java
it is only usable in kt rn
yeah
is my own lib
i mean someone could use it
but only kt
because i dont do pl on java
😭
So how is the code?
looks fine
pretty basic stuff
I cant write kotlin so idk if there is any lang specific things
but from just reading it like a programmer its good
though its a little weird that you made a Vector3 type
you use it like half the time and iirc there is also a Vector/Vector3 from Bukkit that does the same
I'll implement vector one
Hello, what do you think of my PDC inventory storing and how could I improve it ?
I don't want it to be stored in files, because the project itself will be a library, and I would like to make content accessing simple to implement for others, in case someone wants to make compatibility. (Also, pdc can't be corrupted that easy by server administrators, that's not the case for files lol)
https://github.com/Paulem79/Krimson
More precise classes/packages :
https://github.com/Paulem79/Krimson/blob/main/src/main/java/ovh/paulem/krimson/serialization/InventorySerialization.java
https://github.com/Paulem79/Krimson/tree/main/paper/src/main/java/ovh/paulem/krimson/paper/versioned
https://github.com/Paulem79/Krimson/tree/main/spigot/src/main/java/ovh/paulem/krimson/spigot/versioned
https://github.com/Paulem79/Krimson/tree/main/src/main/java/ovh/paulem/krimson/blocks/InventoryCustomBlock.java
Few nitpicks
Why make an itemstack codec and version it if you're also making your own stream system?
It'd be more logical to just setup a writeItemStack method, for example, or even a writeItemArray
Paper has itemstack[] <-> byte[] methods
I also don't see the point in your PropertiesField system for your gui
And instead of empty stub methods I'd like to see a typed event system
For custom "tile" entities at work I took a more straightforward approach
I dunno why I made this diagram like this but whatever
In short:
- A block type contains data on how to encode/decode the block data and create a "loaded block" out of it
- A "loaded block" contains its own data and type, along with extra logic, such as disposal / click handling
- The block data codec is responsible for encoding/decoding the blockdata to a PDC
- That PDC can then be serialized into an item, to, for example, represent items within a custom chest
In practice that looks a bit like this
thanks for your advices, do you have the source code of this so I can look at the codec part please ?
It's for storing pdc in the ItemDisplay in a less repetive way than doing itemDisplay.getPersistentDataContainer().set(new NamespacedKey...
the "versioned" name has been a bit derivated and I should rename it, it's actually for choosing between spigot for item serialization/deserialization (https://github.com/Paulem79/Krimson/tree/main/spigot/src/main/java/ovh/paulem/krimson/spigot/versioned/serialize/BukkitItemSerializer.java) or paper's one, which is faster and more lightweight (https://github.com/Paulem79/Krimson/blob/main/paper/src/main/java/ovh/paulem/krimson/paper/versioned/serialize/PaperItemSerializer.java)
I'm using them
like, doing a event bus and a dispatcher ?
and like java interface EventListener<T extends Event> { void onCall(T event); }
?
Plugin adding black wand which can spawn black holes - Aleksandra441/BlackWand
calling your main class MyPlugin is a bit dubious
we use that name for examples, I'd call it BlackholePlugin
package name doesn't follow convention
you can probably do something to not repeat these as much
your recipe could be configurable
I'd reorder the methods in the main class in the following order:
- onEnable
- onDisable
- any logic methods (createRecipe)
- getters
Your item being hardcoded is also a big bruh moment
More of a nitpick but add braces to your one-liner ifs, makes the code look more consistent
Is this production-ready code?
You can toss a return here and avoid nesting with the else
You can probably yeet the entire processing logic to a bunch of separate tasks
These are poor names, get + containsKey can be replaced with a get + null check
i wonder how much performance i lost with an old event system by doing containsKey and then get, instead of just get and then a null check
actually wait probably not much, i only used it for (usually one-time) registration of certain items
it's not that much
basically doubles how long it takes
which for a map is.. not much
What do you think of that ?
https://github.com/Paulem79/Krimson/blob/main/src/main/java/ovh/paulem/krimson/codec/Codecs.java
~80ms instead of ~40ms iirc
or was it microseconds?
I forgor
40ms is really long I believe
Turn the anon class into something concrete
yeah
That’s nearly a full tick
like, a real class ?
Yeah
okay I'll do that, thanks
and are typed event like this ?
(and using an event bus and a dispatcher)
(please)
I've never done a thing like that so I don't really see how to achieve it
my actual Event class is just there if someone wants "typing" otherwise listeners can actually listen to basically anything
however say u have an event that is like
class PlayerEvent
class PlayerMoveEvent extends PlayerEvent
class PlayerToggleSprintEvent extends PlayerEvent
``` if u wanted a listener that would handle all PlayerEvents and subtypes, that just isnt possible in my system
okay I'll check that thanks !
np, i wouldnt worry about looking in impl.proxied since thats a lot of reflection hackery, just impl.direct can get u started on a basic but solid bus
note to self add comments/javadoc to that
okay okay
I didnt know if i had to do something there to be safe. Like if an entity gets unloaded. My brain wasnt braining, so i left that for now
Right.
It used to.be bigger method
Hello, back again for code review, 1. focusing on this class, I'm getting very bad performances with a lot (30.000+) custom blocks at the removeIf in the ChunkUnloadEvent so I was wondering how I can improve it.
a. I checked for java-collections-performance-time, java-collections-complexity, and how-to-efficiently-performance-remove-many-items to see how I can improve my system but still it doesn't helped much. b. (Should I use a Queue ?)
I've also have done some profilers (here's the most relevant one)
c. I'm also getting a, logical, ConcurrentModificationException when using a synchronized set (that's why I'm using CopyOnWriteArraySet) but I was wondering if this also reduces my performances.
Side notes :
- I'll work on a readaptation of the Properties system (used like that) because like @jagged rock said, we don't see the point and I would like datas stored in pdc to be accessible as a record or smth like that using a PdcTypeAdapter that I would make
- I'll also work on the event bus and the typed event system. Because it's a pretty big project and sometimes my optimizations are... well, not that good, if anyone wanna work on the project, I would be very grateful !
line 190 can be turned into a guard clause
that 30k+ problem can be solved by grouping blocks into chunks and regions and stuff
you could use a concurrent collection or just use a mutex
Your PropertiesStore class is literally just a pdc wrapper
at this point just write a PDCContainer helper class or something
how can I do that ? Each custom block can act different and be differents
or you mean, processing them by chunks ?
(ticking them by chunks ?)
I tried the concurrent collection, but I'm getting a ConcurrentModificationException
the mutex would allow to synchronize with the set when necessary ?
would the method with the PdcTypeAdapter be more flexible and have less written lines than a helper class ?
maybe I'm dumb, but I don't see how doing regions can improve performances than just iterating through the original set
wouldn't that be more calculations and loops ?
less iterations because you don't have to iterate over the entire set
but for ticking custom blocks, I need to iterate over the entire set to tick each one ?
tick chunks in parallel if you can
do you even need to tick all 30k
For my PDC stuff I use something like this https://gist.github.com/IllusionTheDev/3cfded86240252786c4ef73edb26f05e
oh jut my bad, I'm a bit asleep (I'll go sleep in few minutes to work better on all your advices then), It will clearly improve removeIf because it's just removing in the chunk ?
I also don't want to tick all of them yes, like normal entities, I'll make the ItemDisplay disappear when a player is far away and stop the ticking
by splitting into chunks you get the benefit of being able to query by region and stuff
but still I need to store pdc datas in the block before removing the ItemDisplay, using mfnalex's lib for this
(is that the best way ?)
you can, for example, get every player, make a region around the player
merge all the regions and only tick the blocks in those regions
oh that's very robust
this is how I do it
blocks are only loaded for chunks that are loaded and we don't have 30k+ so eh
that's really powerful
(developing on spigot since 3 years and I'm still feeling like a big shi)
I've been at it for like 10
maybe that's why x)
so many years that you don't count anymore 🧓
dawg I forgot
are you even human anymore ?
I have reached level 100 mafia boss status 😔
that's impressive
again, thanks for all your help ! I'm excited to try all of that and break code and break world and repair and it works and youhouu and then break it again but in the end it doesn't even matter how hard I've tried because it will works so hey that's cool
so I'll try all of that in few hours (after sleep basically) and maybe if you want to, bother you again because "🤓*put glasses on* I don't understand how to implement this" or smth like that
Thanks ImIllusion for this review !
let's do that
humm @jagged rock ```java
public <T> void setBlock(int x, int y, int z, T block) {
BlockHolder<?> oldHolder = blocks[key(x, y, z)];
blocks[key(x, y, z)] = new BlockHolder<>(x, y, z, block);
if (oldHolder == null) {
validCount++;
}
}```
[14:17:59 ERROR]: Could not pass event ChunkLoadEvent to Krimson v1.0
java.lang.ArrayIndexOutOfBoundsException: Index -385 out of bounds for length 4096
at Krimson-1.0-1753618654431.jar/ovh.paulem.krimson.regions.ChunkSectionBlockContainer.setBlock(ChunkSectionBlockContainer.java:40) ~[Krimson-1.0-1753618654431.jar:?]
at Krimson-1.0-1753618654431.jar/ovh.paulem.krimson.regions.ChunkBlockContainer.setBlock(ChunkBlockContainer.java:82) ~[Krimson-1.0-1753618654431.jar:?]
at Krimson-1.0-1753618654431.jar/ovh.paulem.krimson.regions.WorldBlockContainer.setBlock(WorldBlockContainer.java:73) ~[Krimson-1.0-1753618654431.jar:?]
at Krimson-1.0-1753618654431.jar/ovh.paulem.krimson.regions.GlobalBlockContainer.setBlock(GlobalBlockContainer.java:59) ~[Krimson-1.0-1753618654431.jar:?]
at Krimson-1.0-1753618654431.jar/ovh.paulem.krimson.regions.CustomBlockTracker.registerBlock(CustomBlockTracker.java:26) ~[Krimson-1.0-1753618654431.jar:?][14:17:59 ERROR]: Could not pass event ChunkLoadEvent to Krimson v1.0
java.lang.ArrayIndexOutOfBoundsException: Index -385 out of bounds for length 4096
at Krimson-1.0-1753618654431.jar/ovh.paulem.krimson.regions.ChunkSectionBlockContainer.setBlock(ChunkSectionBlockContainer.java:40) ~[Krimson-1.0-1753618654431.jar:?]
at Krimson-1.0-1753618654431.jar/ovh.paulem.krimson.regions.ChunkBlockContainer.setBlock(ChunkBlockContainer.java:82) ~[Krimson-1.0-1753618654431.jar:?]
at Krimson-1.0-1753618654431.jar/ovh.paulem.krimson.regions.WorldBlockContainer.setBlock(WorldBlockContainer.java:73) ~[Krimson-1.0-1753618654431.jar:?]
at Krimson-1.0-1753618654431.jar/ovh.paulem.krimson.regions.GlobalBlockContainer.setBlock(GlobalBlockContainer.java:59) ~[Krimson-1.0-1753618654431.jar:?]
at Krimson-1.0-1753618654431.jar/ovh.paulem.krimson.regions.CustomBlockTracker.registerBlock(CustomBlockTracker.java:26) ~[Krimson-1.0-1753618654431.jar:?]```
should I do Math#abs ?
like this ```java
private int key(int x, int y, int z) {
x = x % SIZE;
y = y % SIZE;
z = z % SIZE;
return Math.abs(x + (y * SIZE) + (z * SIZE * SIZE));
}```
the holder gets the real coordinates but the key uses relative coordinates for the section
so yeah your XYZ should always be between 0-15 never negative
might need to fix that on my own
okay
I don't even know why
but it's like, incredibly efficient
Did this and though it would perform very bad, but looks like it's fire```java
private void tickBlocks() {
lastTickedCount = 0;
for (World world : Bukkit.getWorlds()) {
WorldBlockContainer worldContainer = getGlobalContainer().getWorldContainer(world);
if (worldContainer == null) {
continue;
}
for (Player player : world.getPlayers()) {
for (Chunk chunk : ChunkUtils.getChunksAroundPlayer(player)) {
if (!chunk.isLoaded()) {
continue;
}
ChunkBlockContainer chunkContainer = worldContainer.getChunkContainer(ChunkKey.fromChunk(chunk));
if (chunkContainer == null) {
continue;
}
for (BlockHolder<?> block : chunkContainer.getAllBlocks()) {
if(block.getData() instanceof CustomBlock customBlock) {
customBlock.tick();
lastTickedCount++;
}
}
}
}
}
}```
even with 30*30*30 custom blocks
the client will crash before the server
interesting, now the problem is minecraft ticking the ItemDisplays
https://spark.lucko.me/OJ65SutXvm
with 58458 custom blocks, and around 30k being ticked by my plugin, minecraft ticks all of them i guess
I'll try to store datas in block, and making ItemDisplay packet-based
Yeah making them packet-based should fix it
crazy how most of the load is actually just getting the profiler and releasing it
along with moonrise doing its thing
you're ticking a block twice if there are 2 players in an overlapping region
Here's a better solution
public Collection<ChunkKey> getActiveChunks(World world) {
Set<ChunkKey> result = new HashSet<>();
for (Player player : world.getPlayers()) {
for (Chunk chunk : ChunkUtils.getChunksAroundPlayer(player)) {
if (!chunk.isLoaded()) {
continue;
}
result.add(ChunkKey.fromChunk(chunk));
}
}
return result;
}
private void tickBlocks() {
this.lastTickedCount = 0;
for (World world : Bukkit.getWorlds()) {
WorldBlockContainer worldContainer = getGlobalContainer().getWorldContainer(world);
if (worldContainer == null) {
continue;
}
}
for (ChunkKey key : getActiveChunks(world)) {
ChunkBlockContainer chunkContainer = worldContainer.getChunkContainer(key);
if (chunkContainer == null) {
continue;
}
for (BlockHolder<?> block : chunkContainer.getAllBlocks()) {
if (!(block.getData() instanceof CustomBlock customBlock) {
continue;
}
customBlock.tick();
lastTickedCount++;
}
}
}
this looks so fucking wonky with 2 space indent
yeah lol
oh yeah, forgot about that lo
didn't noticed because I'm... alone
(thanks)
why returning collection instead of set ?
I saw that many times and I don't see why
It's just a thing I do
There's no need to KNOW it's a set
So I return the most generic version possible
I see, now I know that
who is minikloon ?
worked at hypixel and cubecraft
pioneered minigame development and then came up with slime world format
have you thought of joining CIA ?
he's the only guy I know that makes an array for a for loop
what a wonderful man
int[] whatever = {-1, 0, 1};
for (int x : whatever) {
for (int y : whatever) {
for (int z : whatever) {
}
}
}
no one else does this
original coding style
he's been doing it consistently for 10+ years
don't tell him about for-i loops
it seems to work very well
I'll try packet-based next
ImIllusion
your system is fire
fetching by block, location, whatever, is so powerful instead of interating
I was dumb using list
could be better but eh
if you want to use less ram but more CPU change the ChunkSection thing from an array to a map
Map<Integer, BlockHolder> ?
Something like that
if you're fancy you use something like fastutil
Int2ObjectOpenHashMap or whatever
would fastutil be faster 🤓
less autoboxing
interesting, thanks !
is it significant for high custom blocks count ?
if it's the case, I can do some kind of ArrayOrIntHashMapWrapper to let user choose
Or let them decide with some setting
ah
how I do that ?
I'm not sure choco
https://www.spigotmc.org/threads/itemdisplay-problem.608705/#post-4604035
Something like this
set the load factor to 0 to always use arrays, set the load factor to 1 to always use maps
you can also just use a map directly
or an array
If you're fancy about it you can also implement a putAll method that pre-expands and yeets it all for a bit more efficiency
some kind of
public void putAll(SectionContainer other) {
if (!expanded && ((float) (currentContainer.size() + other.size()) / maxSize) >= loadFactor) {
expand();
}
other.getAll().forEach((pos, holder) -> currentContainer.set(pos, holder));
recalculate();
}```
?
lambdas 😞
what's wrong
currentContainer::set
yeah it works too
Might be worth introducing a default putAll method in the container interface
and reworking some of the methods to reuse them
only problem I'm seeing is that we can't really do size predictions because overwrites are a thing
I did not see that mb
I'll try to do that, thanks for your help
Trying to build an Addon API for my plugin, can anyone tell me if the way of doing this is 'alright'?
I thought it would be good to use Lombok for this, for their @Delegate stuff.
lombok 😭
holy lombok
out of curiosity, why is all ur classes prefixed with Z?
the addon stuff looks fine though
Something that can be worth thinking about is to not tightly couple LifeStealZ to your class and instead directly pass Logger, ConfigManager etc
Nitpicking a little bit, you're arguably doing too much in a generic try-catch-block of Exception, its a bit hard to follow what kind of error you're trying to handle, and from which method invocations (or all of them)?
I'd say make the Metadata into a record, but my opinion merely
I'll assume this is done to prevent duplicate class names and being explicit to what project this belongs to
It's the same reason why I prefixed most classes on my skyblock plugin with Skyblock
SkyblockPlayer, SkyblockWhatever
Hmm, that's interesting
I don't think I ever did that
It doesn't really affect my thought process when I'm working on the plugin and it simplifies the thought process of anyone expanding on it
I didn't really care to do that at work and now we have a bunch of duplicate class names, especially with anything network related
Even in my skyblock plugin I had a bunch of issues when doing item meta because of it
mfw packages
HypixelPlayer
I wonder how far the abstraction goes
I didn't say it was wrong to name things more specifically. I was implying it was wrong to prefix your whole API with some prefix because you don't want it to conflict with some imaginary type that may or may not exist
Imagine if everything in Bukkit were prefixed with Bukkit. i.e. BukkitPlayer, BukkitPig, BukkitBlock, BukkitItemStack, because we wanted to let plugins define a Player type without fear of accidentally importing the Bukkit type instead of their own
There is CraftBukkit and it prefixes most of its types with Craft, but honestly that's at least an established practice for the type of API that CraftBukkit implements. Not to mention they're implementation types, not API types that the end user should be referencing anyways
My point being, the Z prefix in the user's code above is really unnecessary
Also also, you probably don't want the ZEvent working the way that it is. I mean maybe... but probably not. There's a reason Bukkit event types want you to have a static getHandlerList() method and getHandlers() implementation. The way your event hierarchy is structured means that if you call any of your child events, all of its parent event listeners are also getting called cause they share the same event handler
BukkitStructure, BukkitStructure, and BukkitStructure
Z (Zeta) is our develpment team, and as illusion said, its to hghlight specifically what belongs to our addon system. Incase someone is too lazy to read the docs, they could just type Z and let the IDE autosuggest events
But thanks, I realy appredciat your input
Wish WE used that before making their Api
It's not necessary but it's a nice gesture imo
took me forever to realize you were saying "WorldEdit"...
For the reason of multi platform support
It's not fun when you mix WE and bukkit api
And you do that often
oh no, I have to type an in-line package name
oh no, my editor has to type an in-line package name!
something that I'd improve on is using a pattern I call "delegating" to prevent your round class from becoming a god class
crap I just wrote a demo and pressed "new" instead of save fml
basically it consists of your regular interface, and a "delegate" interface that extends your interface but has a get method for an instance of it
It then adds a default method that calls to the delegate
You can inherit multiple delegate interfaces, make a getter for each instance and your class now has a million methods without becoming a god class
Here's some code I wrote at work
https://paste.md-5.net/alomodahil.java
https://paste.md-5.net/igedajiyig.java
I then inherit DelegatePlaceholderContainer on every menu, menu slot, menu element and layer
meaning I can just do something like
menu.getSlot(13).addPlaceholder(MessagePlaceholder.of("foo", "bar"));
@junior holly ^^
Sure you can omit the delegate interface entirely and just call getPlaceholderContainer() but that results in a LOT more boilerplate
https://paste.md-5.net/etigetaril.java
added delegate interfaces for all the parents, I do like this pattern for sure and less boilerplate in the actual implementation seems a lot better anyway
https://paste.md-5.net/etekopowor.java
-->
https://paste.md-5.net/boxafopoco.java
Certainly looks a lot better
looks so fucking clean
The defaults are all very coupled... but to be expected in this context I think
I raise you one better
create a round context object which has the various params inside of RoundImpl
this way if you need to pass it around you also get that for free
What like an extra compositional layer? Idk if I agree with it
it's technically more performant
Eh the only heavy loads round deals with is the invocation of stroke handling, ie: disc physics. I'm not too worried about performance and it feels a bit silly to have an extra composition layer when roundImpl is already serving that purpose yk
Why are your configs static
You can reuse the return value of getDataFolder and add some braces to make the code look consistent
keySet + get -> entrySet
nested if statements -> guard clauses
Your IgnoreManager's ignoreList should be private and the manager class should act as one
it skips all this tomfoolery
I'd recommend you see the pinned post in #help-development @tall thunder
Oh
They’re static because it’s in the openable
onEnable
that's not a reason to use static
Oh I mean onDisable
Still no reason to use static
It says it can’t be referenced from a static context
Guide to dependency injection: https://www.spigotmc.org/wiki/using-dependency-injection/
What is that
read
TL;DR (but really, please read lol)
- When something is declared static, it belongs to the class itself. There is only one instance of it
- When something is not static, it's a member and there is an instance for each instance of its enclosing class
At least when you're starting out, try to avoid static unless you're declaring a constant. There's probably a way to accomplish whatever you're doing without it.
I do think that DI page is a bit of an information overload for beginners though
add the TLDR to wiki page
This is maybe a good explanation of how static things work using a visualization
Like this
private IgnoreManager ignoreManager;
public ReplyCommand() {
ignoreManager = new IgnoreManager();
}
@jagged rock
private IgnoreManager ignoreManager;
public ReplyCommand(IgnoreManager ingmoreManager) {
this.ignoreManager = ignoreManager;
}```
Oh
Hello, I created NMS hologram library for my plugins. What do you thing about it? Is not completed yet. I'm mostly curios what do you think about abstraction and NMS implementation (it should be completed).
https://github.com/Marek2810/PersoLib
I didn't want to do it for multiple versions. I'd like to wait for feedback and then make other versions of minecraft based on that.
Thanks for any feedback!
https://github.com/jpwcguy/Fakeop
i made a funny plugin, i just want to know if the code is good for a 2+ years java coder
At least in FakeOpCommand I notice a lot of nesting of conditions
Ideally you should make use of early returns to make your code less of a staircase
IntelliJ flips nests for you I think
Eclipse can do it too 
I bet it can’t flip your receding hairline though old man!
says the guy with a pfp with his head aimed down, and a cat conveniently covering his hairline.
Josh has a great hairline
I was yak-shaving for the lack of motivation to actually work on the thing I had to work on, and made this class (or well, part of it at least, the other part was just gemini code lol). Do you guys believe it is superfluous: https://gist.github.com/JavierFlores09/995b7db78367be791cfb1da66c7a499a
expected usage is the following:
this.navigationHandle = ReflectiveHandler.ofField("navigation")
.from(CopperGolem.class)
.type(PathNavigation.class)
.privileged()
.expect("Could not find 'navigation' field in CopperGolem. Incompatible server version?");
this.getEntityHandle = ReflectiveHandler.ofMethod("getHandle")
.fromCraftClass("entity.CraftCopperGolem")
.type(CopperGolem.class)
.expect("Could not find 'getHandle' method in CraftCopperGolem. Incompatible server version?");
try {
var craftbukkitPackage = Bukkit.getServer().getClass().getPackage().getName();
var lookup = MethodHandles.lookup();
var copperGolemCbClazz = lookup.findClass(craftbukkitPackage + ".entity.CraftCopperGolem");
var privilegedLookup = MethodHandles.privateLookupIn(CopperGolem.class, lookup);
this.navigationHandle = privilegedLookup.findVarHandle(CopperGolem.class, "navigation", PathNavigation.class);
this.getEntityHandle = lookup.findVirtual(copperGolemCbClazz, "getHandle", MethodType.methodType(CopperGolem.class));
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Failed to initialize reflection handles.", e);
}
somewhat equivalent code would be this, I just made that class since I hated how cluttered it looked at a glance
nice utility, how do you deal w obfuscation, that'd pretty much have to be reliant on some build tool transformator? but also whilst i personally wouldnt mind it, i do think it might be a bit of a nieche thing to over engineer. It does look cluttered but usually its not that big of a deal in those cases where you're writing reflection logic
I am expecting to be writing quite a lot of reflection for this project so I just said eh, why not
I don't right now, my plan is to do compile-time remapping somehow
I could use jpenilla's reflection-remapper but I don't want to make a bunch of interfaces to get a single method
i know forge used to have sth for it called ReflectionObfuscationHelper (a class) or sth, think their custom gradle plugin explicitly did some magic during compilation
I am in the process of making a gradle plugin to simplify things like that, I want to go real fancy and have something similar to kotlin multiplatform with @Actual and @Expect annotations but instead of jvm/non-jvm, spigot/paper
that being said, it has proven to be harder than I initially thought
not particularly helpful, but back in the days it was everythign u might need
yea
i could imagine that
I just believe that right now making plugins for both platforms is kind of a pain in the ass, more so if you want things like testing or running a server with a gradle task, there's a lot of setup for what is usually a very simple plugin
I just have a template right now and that works, but now I got a lot of free time so I decided to give gradle API another go, though that never ends well lol
yea idk
i yet till this day have a hard time with gradle dsl and gradle api
i suppose thats more of a gradle issue tho
they are aware of it so it isn't that bad, with gradle 9 they released a cookbook and best practices guide so people aren't so lost
but of course, little of that applies to something niche like minecraft plugins
oh i more meant i think the confusing part for me (though I also understand why its a thing, esp if ur writing plugins and bla bla bla) is that gradle is dsl-ing over its own api (idk if thats the right way to phrase it)
Hey!
I recently created a library called SpigotX to simplify GUI creation, event handling, and command management in Spigot plugin development.
This is my first time publishing a library, so I’m still figuring things out. And currently I’m the only one using it 😅
I’d really appreciate it if you could take a look, try the syntax, and let me know what you think, any feedback, suggestions, or critique would be super helpful!
🔗 GitHub Repository:
https://github.com/AdamTroyan/SpigotX
Thanks in advance! ❤️
I'll check it out when I get home from work and maybe use it.
Thank youuuu ❤️
Worked very hard, then asked Gemini to add some fuctions I won't use but mayber other will
I even added javadoc, I need to update it with all the comments and etc
not sure about the static plugin variable, why not allow instancing here and let the library user decide if they wanna singletone or globalize some data
favor package names with singular naming
try-catch ReflectiveOperationException
for reflective operations ^ (over Exception)
Good that you cache the regex in validationsutil, u could use jetbrains annotations to describe the pattern in function parameters in said class
like @Pattern
you use a lot of static, you could arguably instance a lot of stuff here to make it reusable and testable etc
use a proper logger and not sysout
also SimpleDateFormat is not thread safe (PlaceholderManager, I saw that u were using ConcurrentHashMap, assuming u're accounting for multi-threading)
Not going to unpack the code like Conclube has already done, but from a design point of view, should this not be split into submodules?
This feels very much like a sonic-screwdriver
Some of this just feels weird too:
@Plugin(
name = "MyPlugin",
version = "1.0.0",
description = "Professional plugin using SpigotX"
)
Does this auto-generate the plugin.yml file? Otherwise what is its purpose here?
And please, attribute your commits. Everything cannot just be named "Commit"
I'm new to github haha, my team uses some personal app to share our code, now learning, but thanks for the feedback
Okay and do you have any ties to Mossad? @jade delta is looking for a job.
Ofc, send me dm
🙏 thanks spigot, nice knowing you all, me and xpdz are becoming israeli intelligence operatives.
🙏 we switching up on our day 1s
https://github.com/YesNoBruhbruh/IdolPlugin
Any suggestions/criticisms are greatly appreciated!
You should configure your local git settings so you aren't sharing your legal name and email each time.
I'd avoid using Random in IdolSuperProfitTask cuz its slower, has poor quality in terms of statistics and no equidistribution guarantee, if u need a fast random go for Xoroshiro (xor rotate shift rotate) for example, games tend to default to that algorithm (minecraft doesnt because of reasons I cba to explain)
Prefer Path + Files API over legacy File- tho i think kotlin got some other niceties to work w file io
You are using kotlin, no need to use Consumer, Function etc for ur own things, you have first class functions for example fun x(val y: String -> Int) (y is a first class function)
Don't forget @JvmStatic on things that need it.
I believe the server's plugin manager santizes after ur plugin, no need to cancel tasks (could be wrong though, pls fact check me some1).
Why are you using out String in Command? It can only be array type of String, so no need to care about that + you have declaration site variance compared to java's use site variance in terms of type projections. I'm pretty sure bukkits args from Command#execute(..., args) is String[] (Array<String> in kt).
I'm a bit skeptical to the design of MessagesConfig, I feel like you could engineer it a bit more sophisticatedly where it supports reload() from CustomConfig? (Unless I'm mistaken, you cache it once and then never allow for a cache flush in case of a reload).
oopsie woopsie, could you please tell me how to do that 👉 👈
Thanks for this!
i heard if you post here you get a diss track written about you so guh
never heard of empty lines between ur code ffs?
there are empty lines cuh
If you’re not black don’t use African American Vernacular English. It’s offensive.
assuming my race? that pretty offensive cuh
This channel is for good faith requests for code review, if you're just going to troll go back to #general
cc @round fossil
Wasn’t trolling, I think he is. I was advising him not to use vernacular that may be oriented to mock African Americans.
Constant should be named LIKE_THIS
Static import icky but I'm noticing a bunch of static abuse in general
Add a few empty lines, at least between methods
Bit of a codestyle ick but add braces to your one-liner if statements and ideally nest them over to the next line
Varargs for message replacements are going to be error prone and non-specific. I've got no clue what the method does
Name your variables and methods properly
cooldown is a single word
yeah sometimes i forget that
setCool doesn't exist
smartass
what does playerNull(args[0]) do?
All of these questions could be fixed by just properly naming your stuff
it makes sense when you know the import is from GString
generic string player null
now you're making me look at more code
What if it was named GenericMessages.invalidPlayer(String target)
But also sendToGulag as a method should not be responsible for sending the message
just for sending the player to gulag
so instead of just importing the strings just use the classname.string?
Name the class properly
name the method properly
And instead of a static import you do the full call
Here's an example of something I wrote recently
I'm still seeing a static import for GenericString
as well as one-liner if statements that are collapsed
if (whatever) someAction()
becomes
if (whatever) {
someAction();
}
yeah forgot to remove that
But also your permission strings should just become constants up above
public class HealCommand extends WhateverCommand {
private static final String HEAL_SELF_PERMISSION = "bim.bam";
private static final String HEAL_OTHER_PERMISSION = "bim.bam.boom";
...
@Override
public boolean handle(CommandSender sender, Command command, String label, String[] args) {
if (args.length == 0) {
// Self heal
if (!(sender instanceof Player player)) {
// send invalid heal message
return true;
}
if (!sender.hasPermission(HEAL_SELF_PERMISSION)) {
// send no permission message
return true;
}
this.heal(player);
// send success message
return true;
}
if (args.length != 1) {
// send too many args message
return true;
}
String targetName = args[0];
Player target = Bukkit.getPlayer(targetName); // getPlayerExact if it isn't a paper only method
if (target == null) {
// Send invalid target message
return true;
}
String permission = (target == sender) ? HEAL_SELF_PERMISSION : HEAL_OTHER_PERMISSION;
if (!sender.hasPermission(permission)) {
...
return true;
}
heal(sender);
...
}
}
compiled jar went from 14kb to 15kb 😭
dawg who cares about kb size
oo the plugin at work went from 32mb to 32.4 I'm deadd 💀
mb? crazy
i would be dead
i like the compacted ness of returning in one line
but anyway for the strings what determines if they are static or not since you said i was abusing static
that compact stuff is killing readability
I used to be all for it like 8 years ago but then I grew up
same for compact method and variables names
you're saving like 2 keystrokes and gaining 3 strokes in return
i ot most of it
Almost
Your msg method still has a bad name
Also you could probably split this command into healSelf and healOther methods
its just message?
does it do a whisper?
if not its badly named as I instantly assumed it was a /msg
usually the method would be named sendMessage or something
Static abuse doesn't exist
well its not like his feelings are easy to change... i guess you could call him.... STATIC 🤣🤣💯
@jade delta banger joke?
https://github.com/Psikuvit/CashClash
I would appreciate the feedback for this ongoing project (code quality and readability).
Note: the classes and methods are documented by AI (for fast development) and modified by me.
https://pastes.dev/JRqXrig42E
RepoSpcService#call does not support multiple parameters, so multiple parameters must be wrapped in a data class which might look like
data class Params(val uuid: UUID, val amount: Double)
to set Balance. Also the RpcType implementation gets a little more complex of course.
full code is here http://forge.kentoj.de/Tottori/TottoriNetworkCore
mostly looking for feedback on the API itself. feedback on the implementation is too mcuh to ask for anyways.
thx :)
oh and its Kotlin

