#help-development
1 messages · Page 1338 of 1
lmfao
are you using the shaded jar though
I would jjust have:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>org.pircbotx</pattern>
<shadedPattern>com.mrnategeek.libs.pircbotx</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
and then use mvn package, and then use the shaded jar, not the original or anything
also for the love of God, stop naming your entrypoint class "Main"
i hate april fools
half the guilds in my list have the dumb red fake "unread pings" circle in their icons
cue the fucking shelf of identical buzz lightyear figures
I not in the mood to deal with drama. I just cannot get this working, I tried ChatGPT and everything possible. Not everyone is the same
the more things change the more they stay the same
are you sure you're using the shaded jar?
its not fucking drama dude
naming ur classes Main is such a dogshit practice
They are my plugins, I not planning on releasing them so why does it matter?
it's like wearing a clean pair of underwear
i don't expect you to showcase it to me and i'm definitely not going to use it
but you probably do want to wash them once or twice a year just for your own sake
Just wow
that is the best analogy i have EVER heard and im using it
how should i efficiently find a random place for a mob to spawn. should i just do a random Vector and check until i find a place i can spawn a mob?
I wonder how Mojang does it
My guess is they just pick a random position and check up/down a few blocks to see if any are valid
Is there a way to modify compostable items, iirc no tag exists for those right? You would have to hardcode the interactions yourself?
wdym
you mean like, the ability to make an item compostable?
then yeah, no tag
Ah
Probably, yea
Pick a random godemiche
If you already picked one, then stick to it
I changed how I handle my block plugin any ideas for refinement?
@EventHandler
public void onAsyncPreLogin(AsyncPlayerPreLoginEvent event) {
String ip = event.getAddress().getHostAddress();
if (authorizedUuids.contains(event.getUniqueId().toString())) return;
if (isCalifornia(ip)) {
getLogger().log(Level.WARNING, "[BLOCK] CA Rejection: " + event.getName() + " [" + ip + "]");
event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_BANNED, getLegalNotice());
}
}
private boolean isCalifornia(String ip) {
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://ip-api.com/json/" + ip + "?fields=region"))
.GET().build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
return response.body().contains("\"region\":\"CA\"");
} catch (Exception e) {
return false;
}
not a fan of ignoring the log-ips server property
that contains call is a bit iffy but i guess it probably works
i'd probably use json.simple or gson or something to parse the body
probably has to do with age verification in california
myes
the UK is encroaching on US soil again
this time on the west coast
we're long overdue for a second round
ahhh
ligma
still whats the point
its not like you face any consequences
some random country region law doesnt apply to everyone in the world
i have a multi-module plugin and i want to be able to use PAPI placeholders if the player has the plugin on all of their backend servers but my plugin on the proxy (PAPI isnt for bungee/velocity servers), is there anyway to use the PAPI api from my bungee module?
not super cleanly
you'll probably want to parse the placeholders on the backends and then send them to the proxy
whats the best way to do that
what are you trying to do specifically
e.g. what placeholders are you trying to parse and why
any, i want people to be able to use PAPI placeholders in my plugin
you can do what TAB does and have the placeholders and message strings defined in each backend's config, parse them there (you'll need a bukkit module of your plugin that gets deployed on the backend) and send the formatted strings to the proxy
at that point however it might just be easier to move your entire plugin to work on just the backends
currently its js install the jar on either a backend or proxy, not proxy and all backends
so what would be tje best way to parse from bukkit to then send to bungee
im assuming a database is a bit inefficient
presumably you will be parsing the placeholders on the backend the player is on, so plugin messaging should work
send a plugin message from your proxy plugin to the backend the player is on; receive it with your backend plugin, pass it to papi with the appropriate player as context, and respond with a plugin message
this is going to incur arbitrarily high latency though, depending on how far away the proxy and backend are from each other
so id need to make it so my plugin works with a jar on the proxy and each backend?
alr thanks
and while you can send plugin messages to the backend from the proxy, you still need some of your code to be there to interpret them and act on them
idk ive been messing around with it for a bit and you need to have a player to transmit data between servers...? if thats the case it wont work, is there some other way?
Is there a way to hide the Dynamic Tag or make the skull not dynamic? I want to use the texture of the player when created the head does not need to stay dynamic but idk how to make that. I use the UUID to get the PlayerProfile.
You also need a player to resolve most papi placeholders
That's why I made this presumption
If you need to resolve offline placeholders, you need a messaging service like rabbitmq, or if you are already using redis, that also has a (pretty lacklustre) messaging system
nah not reallyyy
most placeholders would be offline players
if no one is online the feature js wouldnt work
Most placeholder resolver implementations require an online player; offline placeholders have a separate contract and are optional
It does depend on the specific placeholders of course
msot placeholders i expect people to be using are like:
%leaderboard_1% etc
and still, if no one is online, it wont work which isnt an option
But if your goal is "all" or "any", you do need the player to be online
.
so my best opiton is to use a db then?
well i was going to do requests through db and i might still need to
Your backend already stores the data, the problem is the proxy needs access to it
i dont understand any other way to do it
never used a messaging system and i dont know what it is
a db would still work no?
Plugin messaging is a messaging system, but it requires a player to be online to work
You can do poll based messaging over a database but it is a really terrible way of going about it
To be clear, are you trying to parse any arbitrary papi placeholder from any plugin, or just placeholders from your own plugin?
yeah
That was not a yes or no question
my plugin can be installed on bungee/spigot and i have a way to parse on spigot since papi is spigot but no way on bungee
any plugin
Then you need messaging between the backend and the proxy
If it was just your own placeholders, you could use a database and just do the placeholder replacements yourself by querying the db
you mean the one that requires a player to be on?
No, that is a requirement specifically for plugin messaging
Which is a kind of messaging system; it delivers messages between the proxy and a backend, allowing them to communicate
What you need is a messaging system that works without a player online
Such as redis messaging, rabbitmq, raw sockets, any number of other approaches
alr ill try thanks
but i dont think it would be any more efficeint than just taking a random one each time. it might seem like its more efficient around level 60-70, but its way less efficient at levels like 250 etc. so overally its equal
Don’t know if relevant but I remember hearing that mobs spawn more or leas at different height levels (I think they spawn faster lower iirc?) so I think it’s more complicated than just picking a random pos
There is a wiki page on it but I don't remember what it says
https://minecraft.wiki/w/Mob_spawning
Short recal for what you are doing:
Packs of up to 4 mobs are spawned in a chunk. 3 are attempted per tick and if one ends up in an opaque block, every other is cancelled.
Each mob is spread out by +-5 blocks on XZ.
XZ are chosen at random, Y is between -64 and the highest sky accrssible block (which is why spawning is more likely underground).
Its a whole lot more complicated if you go into more detail and theres like a gazillion special rules for specific mobs etc, but generally i think it sums it up quite okay
and yet the game always manages to only ever spawn a creeper or a gang of skeletons on my exact location at the most inconvenient times
of course 
hey chat, rn im trying to summon dragons breath on arrow land, ill post my entire file below, how do i summon all of the changes where the to cloud ive made, and also define cloud as an areaofeffectcloud above it? sorry if this is a dumb question, thank you in advance. (it detects the bow its just the summoning I need help with)
if (event.getEntity() instanceof Arrow) {
NamespacedKey bowkey = new NamespacedKey(this, "bowkey");
Arrow arrow = (Arrow) event.getEntity();
Player player = (Player) arrow.getShooter();
if (!(arrow.getShooter() instanceof Player)) return;
Location location = arrow.getLocation();
ItemMeta meta = player.getInventory().getItemInMainHand().getItemMeta();
PersistentDataContainer bowpdc = meta.getPersistentDataContainer();
String value = bowpdc.getOrDefault(bowkey, PersistentDataType.STRING, "<null>");
World world = player.getWorld();
if (value.equals("bowpass")) {
Bukkit.broadcastMessage("Detected bow");
cloud.setParticle(Particle.DRAGON_BREATH);
cloud.setRadius(3.0F);
cloud.setDuration(200);
cloud.setWaitTime(0);
cloud.setReapplicationDelay(20);
cloud.addCustomEffect(new PotionEffect(PotionEffectType.INSTANT_DAMAGE, 1, 1), true);
});
}
}
}```
Am I blind? Where did you define cloud variable
i didnt, im asking how to define then summon after i edited it
because idk how im new sry
ook sooooooooooo when trying to code my server in Eclipse IDE and i add the External Jar file to the code it dosent load it either
i even refreshed the project but didnt load can someone help
AreaEffectCloud cloud = player.getWorld().spawn(location, AreaEffectCloud.class)
?/
but wouldnt that also spawn it? i need to define then edit it then spawn after
ook sooooooooooo when trying to code my server in Eclipse IDE and i add the External Jar file to the code it dosent load it either
i even refreshed the project but didnt load can someone help
Then use a consumer as the third argument and edit in the consumer
?bootstrap
Bootstrap Jar
The main spigot-1.18.jar is now a bootstrap jar which contains all libraries. You cannot directly depend on this jar. You should depend on Spigot/Spigot-API/target/spigot-api-1.18-R0.1-SNAPSHOT-shaded.jar, or the entire contents of the bundler directory from your server, or use a dependency manager such as Maven or Gradle to handle this automatically.
Please read the release notes for further information: https://www.spigotmc.org/threads/9-years-of-spigotmc-spigot-bungeecord-1-18-1-18-1-release.534760/#post-4305163
location.getWorld().spawn(location, AreaEffectCloud.class, cloud -> {
cloud.setParticle(Particle.DRAGON_BREATH);
cloud.setRadius(3.0f);
cloud.setDuration(600);
cloud.setWaitTime(0);
cloud.addCustomEffect(new PotionEffect(PotionEffectType.INSTANT_DAMAGE, 1, 1), true);
});
ok so I did this and it doesnt summon the cloud, what did i do wrong lol probably a lot
let me put a braodcast inside of the thing, give me a sec
yep, it is running the code inside of the spawn thing, but I dont think it is spawning
yea, earlier on it states:
Location location = arrow.getLocation(); (arrow is get entity)
eww
ok thats cool except that the opinions of chatgpt dont matter
Does anyone know how to make those nice End portals in the new versions that type a command for you when you enter?
idk how to explain
bros a java Pharisee
man
im sorry you're right all hail openai and mighty chatgpt
knower of all things
haver of objectively correct opinions
possessor of biggest dong
praise be
btw the particle part of making it dragons breath is whats breaking it, idk why. the rest works fine
there's probably nothing more annoying in java than having to convert autoboxed array to primitive one
does guava have something for me
Nice
is this what you are needing to convert?
Looks like it @wet breach
import org.apache.commons.lang3.ArrayUtils;
public class ConversionExample {
public static void main(String[] args) {
Character[] wrappedArray = {'A', 'B', 'C', 'D'};
// Convert Character[] to char[]
char[] primitiveArray = ArrayUtils.toPrimitive(wrappedArray);
// Result: ['A', 'B', 'C', 'D']
}
}
Arrays.stream(wrappedArray).map(c -> (char) c).toArray()
last one if you just don't want to use any libs
Pretty cool apache commons have this for arrays
hi
Only issue is it's lang3
pretty sure it exists in the updated stuff too
?services
If you wish to request or offer development/art/building/administration services, please do so at https://www.spigotmc.org/forums/services-recruitment-v2.54/
wants make minecraft servers 🔥🇵🇰
guess you can't read
https://imgur.com/a/ab9eJw1 is this resourcepack?
@loud jasper im interested in buying a property in egypt
https://imgur.com/a/22oOfsM How do I add my custom recipe to the left side?
https://imgur.com/a/MUXjown amount is being ignored. idk what should i do too
@quaint basin I think from this, https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/HumanEntity.html , it appears like you can discover a recipe.
declaration: package: org.bukkit.entity, interface: HumanEntity
#discoverRecipe(NamespacedKey recipe)
in theory, you just, on player join, and discover it
Amount is always ignored on ingredients
The Minecraft recipe system doesn’t support that
isn't there like a mapTo<primitive> or smth like that?
Idk if it exists for char but I think I saw mapToInt recently
how can i do that then?
need remove on player quit?
ArmorStand armorStand = location.getWorld().spawn(location, ArmorStand.class, (a) -> {
a.setGravity(false);
a.setInvisible(true);
a.setGravity(false);
a.setInvulnerable(true);
a.setMarker(true);
a.setSilent(true);
});
Guardian guardian = location.getWorld().spawn(location, Guardian.class, (g) -> {
g.setAI(false);
g.setInvulnerable(true);
g.setInvisible(true);
g.setSilent(true);
g.setCollidable(false);
g.setLaser(true);
});
guardian.setTarget(armorStand);```
the guardian isnt targeting the armorstand, it doesnt have a visible beam
hey so im making a dragons breath particle, rn down below everything works, but when you add:
cloud.setParticle(Particle.DRAGON_BREATH);
it breaks and doesnt summon at all, this is my code excluding the line above:
location.getWorld().spawn(location, AreaEffectCloud.class, cloud -> { cloud.setRadius(4.5F); cloud.setDuration(200); cloud.setWaitTime(0); cloud.setRadiusPerTick(0.01F); cloud.setDurationOnUse(0); cloud.setRadiusOnUse(0); cloud.setReapplicationDelay(20); cloud.addCustomEffect( new PotionEffect(PotionEffectType.INSTANT_DAMAGE, 1, 1), true ); });
Certain particles have extra data that need to be passed along.
In this case, it's just a float. Of which the internal usage is just 1.
cloud.setParticle(Particle.DRAGON_BREATH, 1F);
oh alright thank you
They're more trouble than they're worth
no lib
lol
JFX in shambles
jay
public class Food extends CommandBranch {
public Food(String name) {
super(name, null);
registerChildren();
}
@Override
protected void registerChildren() {
}
``` is there any way for me to ensure that each subclass (like this one) calls registerChildren? the problem is that it the method has to access "this"
and i cannot just put it in super constructor which i would if not that problem
this is something i've wanted in java for a long time
how could that work?
the way I imagine it'd work is we add a new keyword like inherited or whatever on methods that enforces similar behavior as in constructors, where they must call super
it is a massive reliability issue that there is no way to force inheritors to propagate calls up to superclass code
oh, I somewhat misread your question
if you need some logic to be run after the ctor runs, the best place to do that is in the registry where you're registering these commands
e.g. in this case you'd move registerChildren out of the Food constructor and instead move it to the CommandRegistry, which would call it on any CommandBranch instance passed to it
uhm, but each command has its own children and these children have their own
another pattern that might work is
private registerChildren0() {
registerChildren();
getChildren().forEach(child -> child.registerChildren0())
}
protected registerChildren() { }
and then only the top-most node must have registerChildren called on it, and it will recurse it through all its children
oh
what about a builder? could something like this work?
Branch.of("food")
.leaf("give", new Give())
.branch(branch.of("set")
.leaf("amount", new SetAmount())
.leaf("type", new SetType()))
.leaf("info", new Info())
.build();
i guess it would have to pass the "this" refference after the creation of these instances then
very difficult to say without knowing what you're going for
when i do hierarchical commands, I don't have a registerChildren(); i have at best a registerChild(), and each parent node will call it for each child node it wants to register
registerChild() would take the child node as a parameter, so the parent node is responsible for constructing it; so it can pass this to it if it needs it
Or a more general solution could be to just implement a visitior for all nodes in ur tree
then if u wna perform some sort of registration, thats entirely possible
what is a visitor in this case
interface Visitor {
void visitLeaf(Leaf l);
void visitBranch(Branch b);
}
for example
class FoodCommand extends RootCommand {
FoodCommand(Plugin plugin) {
plugin.register(this);
leaf(new Give(this));
leaf(new Info(this));
}
class Give extends BranchCommand {
Give(FoodCommand parent) {
branch("set").withChild(new SetAmount(...))
branch("type").withChild(new SetType(...))
}
}
class Info extends SimpleCommand { ... }
you can also inline them into less verbose anonymous classes, if you don't require extra ctor parameters
then again we are basically reinventing ACF and brigadier and every other command framework under the sky
its a little hard to understand since you kind of swapped the names , but isnt this just what i did but without the forcing subclasses to do that
i usually just nest CommandExecutors in maps
in principle kind of, but this way it's easier to inject e.g. this into the children
with the builder approach, you will need to accept a Function<ParentNode,ChildNode> instead of just a ChildNode
and then pass the parent node to the function
and for every "injected dependency" of the child node, you end up convoluting your functions more
that's gonna be nightmarish to put in use
does anyone know how or have a doc or smth on how to pull people into a specific location?
u can just like
teleport people
or probably calculate a vector to a location and apply velocity towards it if u want to "pull" them
does this looks right?
I wanna grab luck perms prefix in chat using vault
String vaultPrefix = plugin.getChat().getPlayerPrefix(source);
Component prefix = LegacyComponentSerializer.legacyAmpersand().deserialize(vaultPrefix != null ? vaultPrefix : "");```
here is where it actually gets injected into the final chat line right before the players name..
// Final Output
return Component.text()
.append(prefix)
.append(nameWithHover)
.append(customTitle)
.append(mm.deserialize("<dark_gray> » <white>"))
.append(finalMessage)
.build();
So it should be like...
(RANK) Sam_0X [TITLE] -> xyz message
so what is it actually?
when you say "should", do you mean it isnt?
ur last line could be compressed to just:
Component prefix = LegacyComponentSerializer.legacyAmpersand()
.deserialize(Objects.requireNonNullElse(vaultPrefix, ""));
In chat listerner using Papers AsyncChatEvent and the Adventure API to build the message as a Component... It handles lp prefixes via Vault, pulls player titles from DeluxeTags via PAPI...
ty on requireNonNullElse, definitely cleaner for the null check... swapping that in rnI was seeing some inconsistent returns from the provider earlier, so this hardens the logic finalizing the listener now
I usually throw down a ternary for the initial prototype to keep the logic visible while Im wiring up the renderer...
you know whats fucking crazy?
this server is called SpigotMC
yk what spigot is?
Lmao yeah.. We run a custom paper fork.. so Im leveraging Papers API for the renderer since its vastly superior for handling components.... just hang in the Spigot discord because the general plugin dev community is a lot more active here..
yeah anyways i got that, but whats ur point?
you said: "So it should be like... ", so what do you need help with? is it not providing the output you expect?
yeah..
Title is missing
although lp prefix is good now
you dont even show the code for that
customTitle, where is thgis?
Jackson2ObjectMapperBuilderCustomizer ah yes object mapper builder customizer
java moment
Become the dev you want to find 🧠
does anyone know how to register a jackson module in java to forbid certain type from serializing to json?
nvm solved it, i expose a jacksonmodule java bean in spring and spring picked it up and registered for me
@Configuration
public class JacksonConfiguration {
private static final ValueSerializer<?> SENSITIVE_TYPE_SERIALIZER = new ValueSerializer<>() {
@Override
public void serialize(final Object value, final JsonGenerator generator, final SerializationContext context) throws JacksonException {
throw InvalidDefinitionException.from(
generator,
"Serialization of sensitive type [" + value.getClass().getName() + "] is forbidden"
);
}
};
private static final Set<Class<?>> FORBIDDEN_SERIALIZATION_CLASSES = HashSet.of(
Password.class
);
@Bean
public JacksonModule createForbiddenSerializationModule() {
SimpleModule module = new SimpleModule();
module.setSerializerModifier(new ValueSerializerModifier() {
@Override
public ValueSerializer<?> modifySerializer(final SerializationConfig config, final BeanDescription.Supplier description, final ValueSerializer<?> serializer) {
if (JacksonConfiguration.FORBIDDEN_SERIALIZATION_CLASSES.exists(forbidden -> forbidden.isAssignableFrom(description.getBeanClass()))) {
return JacksonConfiguration.SENSITIVE_TYPE_SERIALIZER;
}
return serializer;
}
});
return module;
}
}
this works for me
can someone help me out, willing to pay via paypal
?ask
If you have a question, please just ask it. Don't look for staff or topic experts. Don't ask to ask or ask if people are awake or available. Just ask the question to the channel straight out, and wait patiently for a reply. Make sure you use the right channel regarding the topic of your question. Create a thread in case the channel is already in use!
Yo im new to plugin development and java coding language does anyone have any tips on how to get started?
id certainly suggest getting a good understanding of Java down pat
Yeah I did some today but it's late but I will practice more tomorrow. I did manage to make a custom command with my friend on a call tho.
is it just me or whenver i use something like jspecify i always keep fighting the nullability problems
especially with functional programming part of the java
fp
java
theres ur first issue /j
I totally understand everything you just said :3
welcome to the rabbit hole
I can already tell my brain will never stop hurting from this point foreward
its like stockholm syndrome, once you start hating, you'll start loving it
well its not jspecify issue but still
Oo wut u coding?
its thesis project which i fail miserably right now due to bullshit issues like these
Damn
that code smells wrong
the moment you start using Optional just to chain some operations, you already fell into a hole
normal procedural code won't hurt you
that depends imo
streams are my guilty pleasure
it just feels so nice to write a for loop in one line
I am a strong believer that Optional is only really good as a return type, and even there it kinda falls flat if your whole program doesn't use them
Does anyone have ProtocolLib experience? I'm genuinely pulling my hair out and I need help
yea you just have to remember any kinf of functional java programming sucks ass cuz its java, miserable
may as well just write Scala, functional feels right in it
don't people nowadays use PacketEvents
and doing that with jspecify sounds terrible, esp if u run that preprocessor nullaway? or whatever its called 😅
If you have a question, please just ask it. Don't look for staff or topic experts. Don't ask to ask or ask if people are awake or available. Just ask the question to the channel straight out, and wait patiently for a reply. Make sure you use the right channel regarding the topic of your question. Create a thread in case the channel is already in use!
Uhhh I'm not sure? I haven't worked with packets in years and I can't stand NMS so I just immediately thought about ProtocolLib
I mean yea, there are issues w spreading optional everywhere as its just a nullable wrapper and is a relatively weak way of representing nullable types if you look at it from a fp perspective
no issue with using ProtocolLib, it just doesn't keep up as well anymore
but sometimes you kinda have to, let's say you're a modder, you're likely gonna have to touch at least some dfu codec
I'm not sure how to go about PacketEvents in that case. I'm trying to just change a player's pitch and I'm struggling to figure out which packet specifically I'm supposed to use and what fields to change
I wanted to create a recoil kind of effect without using player.teleport
why
though I think people use the consumable component with some fancy resource pack shenanigans for things like that in modern versions
How would I go about using the API there? Doesn't changing the players rotation require you to use teleport?
yes, but why are you avoiding teleport to begin with
Because its janky and I would need to be constantly calling it
For what I'm trying to do at least
what is janky about it
I think you're digging yourself into a problem for no reason honestly, teleporting sounds just fine for this purpose
but do look into this as well
you will be using a resource pack for the gun models I imagine so it shouldn't be much of an issue
I mean I can try it but I've read that teleports are somewhat resource intensive idk if thats true thats just what I've seen while researching this
At least contantly calling it
it can be if done for chunks that aren't loaded
but that wouldn't be the case in your scenario, so I don't think it should be that performance intensive
I'll try it and see what happens
Well after a few hours or working on it, I think I got something I really like. Using Player#teleport showed to be really janky as I figured it would be. It was choppy looking and would reset the players velocity so that wasn't ideal for the feel of the game. I ended up just using NMS because I learned Mojang de-obfuscated the code in 26.1 (I was still on 1.21.11). I just created a new PositionMoveRotation and passed in Vec3.ZERO for position and deltaMovement and passed in the new pitch. Set all the Relative flags and sent a ClientboundPlayerPositionPacket. Was initially a little jittery looking but I decided to smooth it out using a linear interpolation function and running a TaskTimer to send the packets. Even tried scaling the iterations of the lerp function and the period of the task to have bigger recoil effects feel a little smoother. Seems to work really well and it maintains the players velocity so it flows nicely.
Man, I've been finding so many bugs lately. It's weird.
For instance, I have just found out that calling Player#getRespawnLocation() will use a respawn anchor charge.
Just by calling the method. (A read method) 😭
Oh well, time for another bug fix PR I suppose.
Now that I'm thinking about it. I wonder how long that bug has gone unnoticed for.
all 27,101 members come quick, this guy needs help
Pls
I don't understand anything about developing a server
as i said in general, #help-server and instead of "can anyone help", simply ask what you need help with directly
Can anyone help me setup my server bc idk how to and I wanna turn it into a survival server where u die you will be banned for 5 mins
and again, you need to be more specific, "can anyone help me setup my server" is incredibly vague, where are you stuck?
Oh sorry mb
mb for not replying.. Its working now
it takes lp prefix here:
String vaultPrefix = plugin.getChat().getPlayerPrefix(source);
then converted into component
Component prefix = LegacyComponentSerializer.legacyAmpersand().deserialize(vaultPrefix != null ? vaultPrefix : "");
here deluxe tag is taken
customTitleRaw = PlaceholderAPI.setPlaceholders(source, "%deluxetags_tag%");
if player has no tag dont show anything :
customTitleRaw = "";
}```
here converted:
```Component customTitle = LegacyComponentSerializer.legacyAmpersand().deserialize(customTitleRaw);```
and here it gets combined
```return Component.text()
.append(prefix)
.append(nameWithHover)
.append(customTitle)
.append(mm.deserialize("<dark_gray> » <white>"))
.append(finalMessage)
.build();```
ty 

Welp, every day I seem to be learning more and more about how minecraft works.
-# and the jank that goes along with it. :cries:
Turns out that thunder is a server side thing for some reason.
You would think that weather rendering would include lightning bolts, but they are actually entities. .-.
Hm? You didn't know that?
oh yeah
lightning bolts are entities
well the idea behind is you can get struck by one
altho they could just make an explosion and send a lighning packet
they interact with the world and other entities
i'm sure they had a reason to use entities for this
Making them an entity just saves time
true
since it interacts with the world, it must be server-side
only things that don't interact with, or more specifically modify, the world, can be clientside; like particles
it also would not make sense for lightning to be a block
so the remaining bucket to put it in is entity
Could be a really big particle I guess
mojank
except it didnt need to be an entity still... each time it strikes, the server has to add the lightning bolt to entity list, give it a uuid and a plethora of other things for something that exists for 0.1 seconds, this isn't about it "modifying the world" this is Mojang was lazy at the time and already had the packets set up so they went with it being an entity
I mean do you really want them wasting time on that
There are a lot of other things to do
and it's perfectly fine for all of those things to happen
if spawning a lightning bolt brings your server to its knees then you have way bigger problems to worry about
does client send cookies before joining?
no, it is the server that can request a cookie from the client
So In scoreboard and chat it shows Prefix of a Rank
But it doesnt show the luckperm prefix with username and in TAB
Does anyone know why? And this is only for specific ranks Like Guest, And some media ranks
while other works alright
Does anyone know why maven isn't downloading ProtectionStones? <repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
<repository>
<id>spigotmc-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.github.espidev</groupId>
<artifactId>ProtectionStones</artifactId>
<version>v2.10.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.20.6-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
i just love how AI is scared about how i store salts inside strings due to how they're immutable and cant be zeroed out until GC deletes it (heap dump attack), but when it comes to basic security it ignores likes its nothing
in all fairness how likely that you can get raw passwords and hashes from dumping heap in java
is there any way to completely protect from this
i mean if you retrieve values from db you usually get these in a form of string
i feel like if you're so paranoid about gc not deleting things on time you shouldnt use garbage collected language in a first place
you might be able to store them off heap
not sure to what degree thatd help, but maybe?
if you can dump the heap you can probably worm your way into the runtime and just print out your char[] contents as well, all it does is makes the window of opportunity a bit shorter
you have no idea how many heapdumps are out there on git with all their credentials inside
what are -infinity, infinity, NaN, -0.0 like things for? are they really used for anything
?
the best is if you make tab by yourself and everything xD
i cant rely anymore on already made plugins, i prefer my plugins over anything
yo guys is buildtool installation really takes time?
I did "wget https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar -O BuildTools.jar && java -jar BuildTools.jar" on wsl and it's been almost 2 hours and still downloading it
i remember having to build paper on my low end laptop
it was always a case of "go out and touch grass"
it would of course always also fail an hour and a half in
What is it stuck on downloading?
not stuck, just downloading stuff
and this is a gaming laptop (predator asus)
2h is a very long time
which vexes me
rogress (1): 401/588 kB
Progress (1): 417/588 kB
Progress (1): 434/588 kB
Progress (1): 450/588 kB
Progress (1): 466/588 kB
Progress (1): 483/588 kB
Progress (1): 499/588 kB
Progress (1): 516/588 kB
Progress (1): 532/588 kB
Progress (1): 548/588 kB
Progress (1): 565/588 kB
Progress (1): 581/588 kB
Progress (1): 588 kB
Downloaded from central: https://repo.maven.apache.org/maven2/commons-collections/commons-collections/3.2.2/commons-collections-3.2.2.jar (588 kB at 889 kB/s)
[INFO] Attaching remapped artifact.
[INFO]
[INFO] --- specialsource:2.0.4:remap (remap-spigot) @ spigot ---
It took like 15m on my 3470
currently
the speeds look like that a bit
Anyone have an idea of why some living players are returning #isDead true?
nope, I use fiber
hmm I see
I guess I'll terminate this one
probably the wsl
where did you get the player object? they are not stable or persistent, exactly; they're liable to change when players die, relog, or change worlds
in which case an old stale player might be dead or invalid
^
is there other ways of downloading build tools? I was trying to get rid of this issue where some libraries are missing
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Dynamic;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.profiling.Profiler;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.util.valueproviders.UniformInt;
import net.minecraft.world.entity.Entity;
Cannot resolve symbol 'datafixers',
Cannot resolve symbol 'serialization',
Cannot resolve symbol 'ProfilerFiller', etc
Just let it run
add those dependencies into your whatever build script
the DFU and authlib are public artifacts
if that one doesn't resolve with what you have, yeah, you just have to build it
there is some guy serving patched paper jars on github i think where i occasionally go to get my nms deps, but i don't remember what the repo name was
[ERROR] Failed to execute goal on project MC_1_21_10: Could not resolve dependencies for project su.nightexpress.dungeonarena:MC_1_21_10🫙8.5.1
[ERROR] dependency: org.spigotmc:spigot🫙remapped-mojang:1.21.10-R0.1-SNAPSHOT (compile)
[ERROR] Could not find artifact org.spigotmc:spigot🫙remapped-mojang:1.21.10-R0.1-SNAPSHOT in spigot-repo (https://hub.spigotmc.org/nexus/content/repositories/snapshots/)
[ERROR] Could not find artifact org.spigotmc:spigot🫙remapped-mojang:1.21.10-R0.1-SNAPSHOT in nightexpress-releases (https://repo.nightexpressdev.com/releases)
[ERROR] dependency: su.nightexpress.dungeonarena:NMS🫙8.5.1 (compile)
[ERROR] Could not find artifact su.nightexpress.dungeonarena:NMS🫙8.5.1 in spigot-repo (https://hub.spigotmc.org/nexus/content/repositories/snapshots/)
[ERROR] Could not find artifact su.nightexpress.dungeonarena:NMS🫙8.5.1 in nightexpress-releases (https://repo.nightexpressdev.com/releases)
[ERROR] Could not find artifact su.nightexpress.dungeonarena:NMS🫙8.5.1 in central (https://repo.maven.apache.org/maven2)
[ERROR]
this what happenes when I try to install it (maven, I hate maven)
also I have no experience with nms
just bias cause I use gradle mostly
i'm actually genuinely considering going back to maven from gradle now that we no longer need to reobf plugin jars
i used gradle for a while because it became a necessity for paper nms builds
but i feel like the more bells and whistles and unholy things like cached build scripts they add to it, the more fragile and more difficult to reason about it gets
not to mention that my build pipeline keeps exploding every month because somebody figured they need gradle 9.x.x for their gradle plugin that just maps an annotation into a resources .json
maven is dumb as a rock but it's also simple
i just want my paper nms jar to be on the org repo where my build tool can do exactly what build tools are meant to do; grab the dependency, shove it on the compile classpath, and compile
no nonsense, no bullshit, it just works
yup there's beauty in simplicity
btw why does spigot build tool exe is blocked in my pc
www.spigotmc.org/wiki/buildtools
this the correct page right?
meanwhile with gradle i have to fight for half an hour with some fucked locks because the daemon crashed and oops your cached build script doesn't work because you're using references in it and oopsy poopsy it's time to spend 20 minutes rebuilding the paper nms jar because they pushed a new snapshot
You can just run the jar if you want instead
Exe is just a wrapper and probably got false flagged because of that
it's self signed or something probably
where?
this is weird, it also included 3 files called scoped_dir
the other day i was cleaning up my machine because i ran out of disk space; i looked at the usual suspect, .m2, and found it to be a few gigabytes, but for whatever reason .gradle was 60-something gigs
perhaps because there were like 5 caches_fucked_123 dirs under it because it keeps fucking itself over and getting stuck
I think the blocked exe is the jar itself?
Wdym?
click the linux button
sent u a message on dm (can't send pic here)
I use wsl not linux
doesn't matter
a jar is a jar
the only difference between the linux and mac buttons is the color
this is damn weird, the window gives .exe while the linux gives a jar
yeah because windows users are generally clowns and won't know what java is or how to install it to run the jar with
or they have some legacyware java 1.2 install that came with whatever "lenovo games" from the chop shop they got the $100 laptop from
Or the classic 32bit Java install
btw just to be sure; this issue of mine can be solved by build tools right?
Yeah BuildTools can grab the required stuff
Don't recall if .10 was superseeded by .11
If so just change it in the pom
if i made a plugin with x config infos but in a new update of the plugin i add new feature in the config how can i make who used the old plugin adapt to the new config without removing their old edit?
Load the old config add the new value then save it
like how becuase i cam with the idea of doing getConfig().addDefault("test.enabled", true); with all the config stuff but i don't think it's the right method
You just set with the setters
but like in the update 1.0 i have this config
enabled: true
text: "test test"```
in the update 2.0 i have this config:
```test:
item: Material.DIAMOND
enabled: true
text: "test test"
hello:
enabled: true
text: "test test"```
how can i make that the user that had the 1.0 and make the update to the 2.0 have his edited config + the new part?
If feel like the type of user who is looking to run buildtools knows what java is
Not really as it's the only (legal) way to obtain a Spigot jar
config.set("hello", myNewConfigSection)
however iirc snakeyaml as set up by bukkit still kind of mangles configs when saving them
in particular it has configured line splits every 100 chars or something
There are definitely jars floating around, and server hosting websites install it for you
and if the config doesn't contains it?
Yeah but I feel like most people (especially a hypothetical nontechnical person who doesn't know what java is) don't really care
??
A config doesn't need to contain a value for you to set a value
like how do i push an entire config section if it doens't exist to the new version?
i should do something like this?
public void setupConfig() {
getConfig().addDefault("firstjoin_message.enabled", true);
getConfig().addDefault("firstjoin_message.text", "&cweclome for the first time in the server! %player%");
getConfig().addDefault("join_message.enabled", true);
getConfig().addDefault("join_message.text", "&5Welcome %player%!");
getConfig().addDefault("leave_message.enabled", true);
getConfig().addDefault("leave_message.text", "&5Goodbye %player%! We hope to see you again.");
}
vcs2 just told you how
but should i do this each time o start the plugin?
If it's already in the config you don't need to
but if i had an old version and i added new feature how can i implement that with the 2.0?
Your code looks good I think. I don't know the config api super well. It's fine to run code you don't need to if it's on startup
defaults won't help with config migration and defining them explicitly is redundant for the main config
the bundled comfig.yml resource in your jar is already used as defaults
setting defaults won't make entries appear in the file on disk; what defaults do is they provide a default value for config.get(...) when the on-disk config is missing that entry
so if i edit it, someone upload the new version with new config info it will be his config with the new values?
so it's useless to have something like that? i just need the config.yml
i have no idea what that means
did you try this yet?
i'm using it with all the values i've already in the config, but if i implement something new and there was already the config.yml in the server files generated with old info how it will work? like i've added a new variable will it be implemented? how can i implement it? idk if you understood what i mean
okay so
you have a config.yml on disk, yes?
you implemented a new feature in your plugin, and now you need to add more options to the config, yes?
you want to add these options to the config that's already on disk in the plugin folder, yes?
i do
yes
yes i want to add the new options in the config but i don't want to delete the one that the user already edited
- load the config
- check if your new things are in the config
- if they aren't, add them with
config.set(newThingPath, newThing), callconfig.save()
since you are loading the existing config, any changes the user has made will still be in the changed config
how can i load the config? saveDefaultConfig();?
how can i check for new things? idk
okay so if i have done "saveDefaultConfig();" i should be good with the loading
should i do a check before making the action or onn plugin startup?
what saveDefaultConfig does is it checks if the file is on disk, extracting the defaults from the jar if it isn't, and then loads the file on disk
so if the config is already on disk, it behaves exactly like loadConfig
presumably before you would access those new values, yes
okay so i should be good without further edit just saveDefaultConfig(); and i'm good
if i want to be 100% sure i make if (!config.has(newThingPath)) config.set(str, obj) right?
saveDefaultConfig will not add anything
if your goal is to change an existing config an user already has, no, you won't be good with just saveDefaultConfig
you need to manually add the missing entries with config.set
so i've wasted all of my day trying to reimplement argon2 wrapper without spring, but realized that i was doing it wrong (it works, but it just doesnt fit for me architecturally)
fml
so i should do a check like this with each of my options for prevent anything missing if (!config.has(newThingPath)) config.set(str, obj)?
yes, and remember to save it
you're welcome to use my
https://github.com/devspexx/ConfigurationAPI
i will check it out ty
thank you :D
i'm getting this warning from decades what can i do to fix it?
[23:29:00 WARN]: Exception in thread "Craft Scheduler Thread - 6" java.lang.UnsupportedOperationException: Not supported.
[23:29:00 WARN]: at org.purpurmc.purpur.util.MinecraftInternalPlugin.getServer(MinecraftInternalPlugin.java:92)
[23:29:00 WARN]: at com.destroystokyo.paper.ServerSchedulerReportingWrapper.run(ServerSchedulerReportingWrapper.java:24)
[23:29:00 WARN]: at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
[23:29:00 WARN]: at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
[23:29:00 WARN]: at java.base/java.lang.Thread.run(Thread.java:1570)```
?whereami
oof mb xd
hi, i have two 1.8.8 servers that are nearly identical with the exception of the plugins installed. I have a weird issue where guardian beams appear on one server, but not the other (although damage is still done on that server). I have already looked through all the source code for the plugins, and none of them involve anything packet related or nms related, so i have no idea why im having the issue i am having. i don't know if this is the right channel to ask this, but since the server files are almost identical (with the exception of the plugins and worlds), i figured it was something to be fixed with code and not a server file
Are you using bungee? Does it depend on which server you join first?
I am not using bungee. It doesn't matter the order, either
That's strange, they appear for me on a 1.8.8 server, it is most likely a plugin causing the issue, what plugins is the server using?
Is there a way to easily work on plugins and test them without having to maven install, stop server, overwrite .jar, start server again every time?
well building the plugin is pretty mandatory, which you can quicken by building directly in your plugins folder. in terms of server testing you can usually get away with a dirty reload. this all removes the need to manually replace your jar and to restart your server
reloading is rarely recommended but for simple plugin testing it's fine
Alright, ty for informing! :)
if your project takes a long time to build as well, likely if you have several modules to build, you can involve several threads in your mvn install command to speed up that process too
I don't think it'll be that big but thanks for letting me know, might use it in the future :)
Hotswap
yeah hotswap (works good with JBR) is useful
unless you modify some manager class (especially a map) or modify db schema
for messing with listeners particles etc. its great
and once it fails you just restart
Is there a method in Bukkit that allows me to see all player deaths and return Map<Player, Integer> or something similar?
Maybe there's a statistic that track those
If not you might have to impl such a system yourself
It exists, but getting it from all the players is the hard part
Maybe I'll have to read it from the disk
if you're returning a Player map, loop over Bukkit.getOnlinePlayers
if you need offline players, you can getOfflinePlayers and use paper's offline player statistic api
not sure if that's async safe though, it probably isn't; i'd probably stagger it so you sync get 100 players' stats per tick or something
if you don't need backwards compatibility, i.e. it's fine for deaths to start at 0 when the plugin is installed, a database is ideal for this
Bukkit.getOfflinePlayers() is this thread-safe?
i don't know if it's thread safe but everybody definitely uses it async already
If so it's not thread safe
e.g. every voting plugin ever
If you have to ask the answer is almost always no
Doesn't stop people from using it that way though
i don't think i've ever seen it throw a cme but it might not be strictly "safe"
I need to show a leaderboard of all the players
Get the stats once and put them in a database of your choice
You can just read your own data in a thread safe way?
And then continue with that
basically every vote plugin uses it under the hood to map usernames to uuid's, since the bukkit getter by name only uses the usercache, and i think there was some case sensitivity problem
I'd just like to know if had any Bukkit method for this
but yes, a database is probably better for this
The offline player statistic api is part of spigot btw
neat
But supposedly Bukkit # getOfflinePlayers should be thread-safe if it only reads from disk
maybe the offline pdc api is the paper one?
I don't understand how this can't be thread-safe
It accesses the online players too
OfflinePlayers + checking if he's online
it's not a pure disk read
it seems to be backed purely by the filenames in the player data dir
It is?
the method itself doesn't really do IO other than querying for files list in playerdata dir
it's the methods in OfflinePlayer that read from the player .dat
looks like it does get from server.offlinePlayers
but that's a read, so it's "fine"
no, i'm wrong again, it does have a branch that put's into the map
oh well
hasn't blown up for me yet 🤡
But you also probably didn't work with 1k offline players for the issue to arise
Concurency is also annoying cause it's silent most of the times
oh i have like tens of thousands of offline players
mostly because i run an offline server and occasionally some pythonoid realizes he can mineflayer 1000 bots onto the server to flex his skript kiddie skills
public OfflinePlayer[] getOfflinePlayers() {
PlayerDataStorage storage = this.console.playerDataStorage;
String[] files = storage.getPlayerDir().list((dir, name) -> name.endsWith(".dat"));
Set<OfflinePlayer> players = new HashSet();
for(String file : files) {
try {
players.add(this.getOfflinePlayer(UUID.fromString(file.substring(0, file.length() - 4))));
} catch (IllegalArgumentException var9) {
}
}
players.addAll(this.getOnlinePlayers());
return (OfflinePlayer[])players.toArray(new OfflinePlayer[players.size()]);
}
yea this is not thread safe bc getOnlinePlayers call
getOnlinePlayers is fine, it's a read
the worst you'll get is a cme, you won't end up breaking the server internals
But I have no guarantee that it represents the updated list
what is not fine is getOfflinePlayer, since that will write to the offlinePlayers map
which could fuck it over completely
which is not destructive
the worst that'll happen is you get a cme, or your player list is like 5 milliseconds out of date
however fucking the server internals is destructive
Yes, but that's one of the requirements for the method to be considered thread-safe
there are several degrees of thread safe
Theoretically, I could get a list from years ago xd
getting potentially stale data can be considered thread safe, it depends on the contract
But yeah, that's not going to happen ig
weak consistency and whatnot; basically every database does this
what's the bigger not-thread-safe red flag is the CME
and what's even bigger is fucking the server internals
the latter is generally where i draw the line with bukkit async shenanigans
How can a CME occur here?
String[] files = storage.getPlayerDir().list((dir, name) -> name.endsWith(".dat"));
and this too prob
oh ok
filesystem access all-bets-off threading wise unless you use explicit locking anyway
as long as only my own state will get fucked, i can just e.g. catch the CME and clean up and retry; but if the server state gets fucked, there's no way I can recover from it
But is a get safe if a player joins and the hashmap array changes size and the bucket you're trying to read is null now?
it's safe in the sense that it might blow up (for you) but it won't destroy the map
put is unsafe because it could potentially permanently brick the map
so now everyone accessing any offline player gets some arcane NPE or IOOB error
goes back to this
i see
historically hashmaps have also had a race condition where two put's could deadlock if rehashing triggers in a certain way, potentially stalling either your thread or the main thread and crashing the server
Hmm, what about reflections to get the offline players only?
but that's some google map i think which is a different impl, and iirc the race has been fixed in the stdlib hashmap as well
What does get offline player do?
if you wanted to do it thread safely, you could just get the player dir yourself, do the same UUID parsing as this does, but then resolve those uuid's to offlineplayers on the main thread in staggered batches
@Override
public OfflinePlayer getOfflinePlayer(UUID id) {
Preconditions.checkArgument(id != null, "UUID id cannot be null");
OfflinePlayer result = this.getPlayer(id);
if (result == null) {
result = this.offlinePlayers.get(id);
if (result == null) {
result = new CraftOfflinePlayer(this, new NameAndId(id, ""));
this.offlinePlayers.put(id, result);
}
} else {
this.offlinePlayers.remove(id);
}
return result;
}
pretty write-heavy
But I don't think I can do that because I have two servers. If a player joins server X but not server Y, then that player will never appear on the leaderboard on server Y
use a database
all roads lead to database
is there any way to make a horizontal line without spaces?
p.sendMessage(
Component.text("§7§m--------------------------------", NamedTextColor.GRAY)
);
something like that, but the - sticks out of the strikethrough here
that's what &m does no?
you just use spaces
just spaces
not dashes
"§7§m ",
like this
let me see
that will create a horizontal line without any gaps, yes
&n or whatever the underline code is will also create a horizontal line a few pixels lower
thought there has to be some text
protip: you can also make space bold
me finding out u can ~~ ~~ strikethrough space on discord
yeah, it supports a lot of cool stuff
MySQL & Oracle: These perform an implicit commit the moment they see a DDL command (like CREATE, DROP, or ALTER).
is this true?
doesnt this break transactions?
No idea but wouldn't surprise me if you couldn't transact commands to structure
using § in a kyori component is one of the funnier things I've seen tbh
yeah like
I can kind of see doing it for the decorations cus sometimes I forget how to add decorations to a kyori component (idk man, I'm stupid sometimes), but I also don't get it
kyori is kind of a pain to add different decorations (i love the components tho),
First you have your normal text, give em a decoration. But now you have a TextComponent which you can only append new components too and not just chain the builder together
and that gets messy real fast
as an alternative kyori offers minimessage but that reads more like html and feels kinda weird to use especially because you always have to yank it through the serializer
that actually is a feature tho so u dont need to use the builder if its just one specific decoration
i think in java, it might be hard to find a design that minimizes verbosity entirely whilst leveraging high customizability (and ergonomics) per say
true, but tbf, a way to instantly append text to a TextComponent instead of having to append a whole nother Component, isnt all that complicated and would benefit to the design (in my opinion)
i'm pretty sure they had an overload for that at one point
Component::append(String text)
but i guess it was too easy so they had to remove it

I just use textOfChildren + static imports
player.sendMessage(textOfChildren(text("Something ", GRAY), text("else")))
I don't think I remember there being one, but even if there was, it'd feed into a bad pattern so I think it is the right choice to not have it
like, when you have that you have to ask yourself, at what point it stops being convenient and just boilerplate
i shouldn't have to wrap my text (String) in another text wrapper (TextComponent) just to append it to another component
if you allow yourself a handy append(String) method, then why not an append(String, TextDecoration...), may as well also add appendTranslatable(String) for translatable components
what actually IS boilerplate is me having more text(str) boilerplate in my builders than actual text being appended
i'd say plaintext is the special case because it is so ubiquitous
if i also have to pass a text decoration, there are already enough characters in play for a TextComponent wrapper to not be, relatively, as much more boilerplate
is it though? I don't think I find myself appending text that often like that, because I could just text("text" + otherText)
when you're appending a component, it means you want to modify style as well, so it ends being moot to have such a method
it mostly happens because adventure basically forces you to be passing components around instead of strings
so you don't have a "text" to append to
one just has to come to terms with the fact that it isn't just a String but a String with style definition, and that needs its own object
I think it'd be fine if you were to do it for personal purposes, but for a library you do have to consider how to avoid falling into these patterns in order to have a clean design
well, i think you're wrong and that it's ass and they should bring it back
which I know, "clean" being such a loaded term and all, most people think it is bs until you have to write a library and people end up writing henious shit because of these "convenient" patterns you added
If people want to write heinous shit with my library that’s their right
people often don't want to do that, they just do because your thing is badly designed and leans into patterns which are easy to fall for the unexperienced
then they end up blaming you for their unmaintainable code
appending text to text is my right also
idc if it's kinda shitty, I just have a bunch of constants with placeholders in a messages enum that I can use so I can have all my messages in one place and use them freely
is it the best solution? nah probably not, but it works for me and lets me edit things all in one place without going around like say in the future if I change my theming around I can just change the tone/theme and wham it's done
the only issue with this is that it is all in source code
should just make a translations file and use the TranslationStore API
i hate magic string translation keys
sure you can get some ide plugin to make them navigable psi references and whatever, but i'd infinitely prefer it to be in source code
you can do both; defaults and enum identifiers in source code, but load overrides from disk
you don't need an IDE plugin for it, IntelliJ automatically infers it most of the time
these aren't ever going to change outside of plugin updates so that's a needless addition tbh
if it is a public plugin you'd want localization, if it is a private plugin and you're working with a team then they may want to edit messages without editing the source code
this is for one specific server and isn't a public plugin
the messages genuinely will have no reason to be changed outside of plugin updates
often enough a localization system pays itself off
i have never once localized a message in my life
if u dont speak my language u dont speak my software .
are you an english native?
yeah
makes sense then
i'm not english native and i agree that if you don't speak english you have no business dealing with my software
this server is a very specific type of server where everyone on it young or old knows english because you can't even get on the server without a decent capability to read and write
there's a reason every UI library ever offers some kind of first party i18n system, it just ends up biting you in the ass if you don't consider it from the get go in the long run
I understand the reasons for choosing just not to care are plenty, but it really doesn't hurt to just use it for good measure
You underestimate me
oh but it definitely does
rather, it definitely can
only time I see it being hurtful would be when people want too much from it
keep it simple, stupid
"just for good measure" is the path to hell
and it's paved with large libraries
the moment you introduce templating into your localization files is the moment you know you've gone down the wrong path lol
unrelated but I love how there's these little boxes for colors on the side, idk if it's a plugin or what but it's yumyum
ik intellij does it for java.awt.Color thats about it tho
yeah you can change the colors in here it's cool
it's pretty nice indeed
but no uhhh yeah localization is neat when you have use for it, but I don't like building for something where I absolutely have no need. If it's needed in the future, then sure I've built this in a way it wouldn't be difficult to implement it. But until then, nobody would ever use it because the people who make changes to these are also the same people who can make changes to the plugin (which we have CI to do building and repo updates etc etc automatically).
So it's unnecessary bloating for a feature that wouldn't ever get used
I build with intent for expandability, but do not include bloat until otherwise necessary
I keep my localization pretty loose with just a sendMessage(audience, key) kind of thing
messages.loadMessage("give-invalid-target")
.withPlaceholder(MessagePlaceholder.of("target", targetName))
.play(sender);
keeping my localization minimal (non existent)
remove the key from the config if you don't want the message to be sent (links to a dummy class)
real men localize all strings on the protocol layer
eh sure
i do this for player chat already but i've yet to figure out a way how to do it sensibly for system messages
all fun and games until you want to send unformatted text
nexo had that issue for a lil while where I couldn't send unformatted text and it introduced attack vectors
by regular ppl injecting <click:run_command:/op myself> tags
e.g. someone is going to name their town "mushroom" in some language and now all command feedback and teleport commands and shit are going to be fucked because it tells you to /t spawn sieni instead of t spawn mushroom
does run command click stuff like that not run from the player's permission group
depends on how you format it
well what if an admin clicks it
yeah i've seen this going around relatively recently
fair enough
there's a replaceText function that doesn't replace command tags
I'd say "Well admins clicking stuff willy nilly is a security problem" but well
there are a million other tags you don't want to parse as well
you can brick a client by including 1000 <head> tags
since it has to fetch all the skins
can't trust anyone to know what they're doing tbf
That’s a lot of head
didn't pictogram do that to show custom motd images
woah there he is
yeees
then mojang changed motd to not render heads in the very next version
except they only scan components like 32 layers of nesting deep, so they nested them 33 levels deep
and then mojang put a 32 level nesting limit on components
wild
or maybe it's 64
NO FUN ALLOWED
if i have player data in a db that is only in-use when said player is online, should i wait for when they join to load it? or load all on server startup
Probably wait for when they join to load? You can load the player data into memory and then just read and write from that so you don’t need to keep making calls to your db. Save to db then flush from memory when they log out.
Loading everyone at startup is not optimal, but could work if you don’t have a huge player base? I guess just depends on your scenario.
this is what i decided on ultimately
load on join, save&delete from mem on quit, flush dangling on server stop
eventually ill do periodic save also
Nice hope it works well!
Load it on async prelogin so you don't stall the main thread on join and don't need to deal with potentially incomplete data when the player is online
Hi, I’m trying to implement a feature in my plugin that allows loading custom Blockbench models, similar to how ModelEngine works.
I’ve looked around but haven’t found much documentation. The only reference I found is a plugin written in Kotlin, but I don’t fully understand what it’s doing, and I’d prefer not to copy code without understanding it.
If anyone has experience with this or knows good resources (articles, repos, or explanations) that could help me understand how to approach this, I’d really appreciate it.
(I’m not sure if this is the best place to ask, but I’m not sure where else to look.)
Thanks!
it's an "industry secret"
for a minecraft specific example, the best chance you have at it is probably that kotlin plugin
however the principles employed are very general and you can find many tutorials and guides online for model transformations, matrices, and everything involved
the difficulty is in getting those to work with minecraft's fucked coordinate and transform system, which is entirely nonstandard in just about every way
what exactly are you trying to do?
ME replica?
for transformations, this is a good resource, i relied on this for my game engine
either way if u're trying to achieve some sort of "model engine", to lay the ground work:
- convert the bbmodel file into however you want to represent it in java, u prob wna check that its a valid model also here
- a model is usually a hiearchy of groups and bones, usually represent each group as its own display entity, (i think item displays is what ME uses)
- you'll have to learn (as vcs pointed out) how transformations with with a 4 by 4 matrix, but you may wna explore linear algebra concepts like quaternions, vectors etc
- you'll also need to use a bit of resource pack magic, id strongly suggest using a lib like creative for this
Im making a vehicles plugin and wanted to make vehicles animated and add the possibily to swap parts or other similar stuff, and wanted auto resourcepack generation
that's a tall order
a strategy I did in the past was just having all the bones in at once and selectively hide them with MEG
for the resource pack i've already written my own generator and i've already written the bbmodel file reader to convert the json into objects. Its actually converting everything into model files and putting it together the hard part for me
i don't want to make my plugin depend on Meg, because its going to be a premium resource and making it depend on an another paid plugin just makes it too expensive to get
There are free model engine like plugins
^
Some might be outdated but they'd be good to learn from
perhaps abstract the dependency into its own modules so you can depend on e.g. the free BetterModels or ModelEngine both
i found one written in kotlin, but didn't undrestand much on how it works
people who have ModelEngine won't want to install BetterModels because it isn't exactly a drop-in replacement
but people who don't have ModelEngine won't want to buy it because mythic is shit
so supporting both might be a pretty doable option
or whatever free model plugin you pick
Free Minecraft Models is pretty good from what I remember
knowing magmaguy it's probably also written in kotlin
iirc it doesn't even try to attempt mythic/ME compatibility, which is fine, but not ideal if you also want to optionally hook into ME
Looks java to me
At some point I considered making a compat layer between all of these
i'll look into them, i didn't want to depend on similar plugins because they add stuff that i don't need, so the idea was to add auto merge into plugins like ItemsAdder
BetterModels is nice because it sorta tries to be a drop-in replacement for ME, even though it doesn't 100% succeed at it
iirc it even implements some of the mythic skills so your $35 boss mobs you bought from mcmarket might even work with it
not relevant here in that sense, but i'd guess that will make the api surfaces more similar than e.g. ME and freemcmodels
Umm aktually it’s builtbybit
Isn't there a opensource plugin that uses displayentities instead of armorstands?
written in java
java and kotlin aren't that much different
is there something specific you struggled understanding that was written in kotlin?
No, i just find it a hassle to find stuff in it or the type of some vars
maybe im asking too much now, is there anyone with experience in this kind of stuff who can hop on a call with me? So i can show what i tried so far and help me impl the basics?
wait are you reading the code in intellij or on github?
cuz icl
github
kotlin is like all the bad things in python having a child with all the bad things in java and slithered out of the abortion bucket and developed stage 5 brain cancer
u can activate certain inlay hints which will expose inferred types
"just ducktype shit bro who needs explicit types to know what val shit = fuck() is " but also no soft typing signatures so you get to have infinite compiler errors because some type declared 10 degrees of inference away from the actual error site was refactored
well atleast I can filter a list in kotlin in 20 different ways with their higher order first class functions /s
dont let @tender shard read that
did 26.1 by chance not get an api-version? or has the syntax changed
it probably just changed
Hi, everyone, does anyone know how to serialize ItemStack to json or something else?
that's probably harder to do ^
cuz this do be happening on all 26, 26.1 and 26.1.1
try serializing the map back and fort
emh whatever 1.21.11 works i guess
the error says you're on 1.21.11
ugh time to wait another 5 hours
surprising the plugin still loaded tho,
backwards compatibility do be a thing
oh god i just replaced the jar at runtime
omfg
i wondered why it took so long to move, maybe because its a mount and my internet is 500 years old
is there a more robust way if doing some thing like
if (isInt(x)) {
int y = parseInt(x);
} else {
// error logic
}```
i could have a callback like
```java
if(!tryParseInt(x, y -> /* act on y */)) {
// error logic
}```
but since primitives arent nullable i cant easily think of another solution that wouldnt lead back to callback hell
am i doomed to callbacks?
the boxed objects?
iirc
yeah
i did think about that actually
apache has a method that get ints or default if invalid
to use Optional and generics
wee, thanks
parseOrDefault makes sense but like what if the value IS the default by coincidence
hmm
what if you just
try {
int number = Integer.parseInt(string);
//your logic here
} catch (NumberFormatException ex) {
//error handling here
}
it's not as pretty but it has a clean intent
true
could maybe inline the error part, in case it's just one line
i just hate having try-catch LOL
its what i usually do to make it less messy
true, but they're here for a reason, so why not use them 😄
i generally hate exception handling so much
its a gigantic performance mess sometimes
What are you parsing?
strings
user inputted numbers for currency calculations
wish we had C#'s tryParse method lol
to be fair the Integer.parseInt and Float::parseFloat javadocs do recommend for you to validate the number rather than relying on the error
it's just that floats in particular are so free-form and have so many different representations that the regex is like 300 characters
i could check beforehand, but it doesnt erase my issue that id like to have Less code on the front-end of parsing&retrieving
integer would be straight forward enough i suppose but
parsing strings from user input to do currency calculations
so really its a floating point im parsing
just look for 2 ints and a .
true...
fuhgetaboutit
least of my worries actually
String s should constitute a FloatValue as described by the lexical syntax rules:
FloatValue:
Signopt NaN
Signopt Infinity
Signopt FloatingPointLiteral
Signopt HexFloatingPointLiteral
SignedInteger
HexFloatingPointLiteral:
HexSignificand BinaryExponent FloatTypeSuffixopt
HexSignificand:
HexNumeral
HexNumeral .
0x HexDigitsopt . HexDigits
0X HexDigitsopt . HexDigits
BinaryExponent:
BinaryExponentIndicator SignedInteger
BinaryExponentIndicator:
p
P
if it starts or ends with a . i could just fill in a zero
where Sign, FloatingPointLiteral, HexNumeral, HexDigits, SignedInteger and FloatTypeSuffix are as defined in the lexical structure sections of The Java™ Language Specification
you aren't overcomplicating it enough
you need to write a custom lexer
TRUE
so Double.parseDouble doesn't seem as bad to use
but yeah i'd just try catch parsefloat
and handle the number format if thrown
that is basically what i do
i do end up with a double-parse though so
nonperformant...
(bc i have the isX method)
Use guava and their tryParse methods
yees add the 350mb dependency for the one 3-liner method that just wraps try-catch
Optional<Object> parseInt(String v) {
try {
int n = Integer.parseInt(n);
return Optional.of(Integer.valueOf(n));
} catch (NumberFormatException nfe) {
return Optional.of(nfe);
}
}```
wait i dont need the optionals i could just have type Object
sorry i was callback brained for a second
i mean if you want to check whether it's a "regular" float without the hex or scientific notation nonsense, you can just match it against \\d*\\.\\d*
which will strictly speaking treat . as a valid number, but oh well
the . needs to be optional too
what if they just enter 26
i need to treat that as 26.00
(\\d+|(\\d*\\.\\d*))
🙏
is the pipe necessary there
it's something you have to think about when you're parsing like a 1000 line file full of numbers that are actually all invalid numbers and throw
oh i missed the first d* in pipe
if you don't want to allow .1 , you can just \\d+(\\.\\d+)?
Because using try catch is bad!!!!1
and if you're checking matches instead of find, you also need a -? at the front
not bad just Ugly :(
It’s bad according to stackoverflow
makes my code look like a NOOB because im gonna throw an EXCEPTION
(there are plenty of other reasons my code is newbish)
something something // REMOVE IN FLIGHT with C++ try-catch exceptions on jet plane code
https://www.youtube.com/watch?v=Gv4sDL9Ljww this thing
A single unhandled exception destroyed a $500 million rocket in seconds.
The F-35 wasn't going to make the same mistake.
By carefully slicing C++, engineers created one of the strictest coding standards ever written.
This...is Programming Like a Fighter Pilot.
In this video, we dive into the history of software in aircraft, the (thousands!) ...
lowkey using regex would probably just make it slower than double parse 😭🙏
with equally as convoluted code
actually @lilac dagger brought up a good point earlier
i could do parseOrDefault(x, NaN)
bc im working with floating point (specifically doubles)
so i could only have to parse once and compare against NaN lol
NaN is generally more trouble than nulls
since nulls throw early
nan's you have to explicitly check for
well yes it would be
double parseDouble(String v) {
try {
return Double.parseDouble(v);
} catch (NumberFormatException nfe) {
// eat exception
return Double.NaN;
}
}```
```java
double n = parseDouble(input);
if (n == NaN) {
// error handle
return
}
// use n
...```
i still have to check for invalid no matter what, but i can get it in once parse at least
i'm saying return a nullable Double instead of a double that might be nan
but why
oh yeah
nan's are evil
:(
you could also work with Double
same with infinities
and that allows for null
i mentioned boxed values earlier i think lol
to be air NaN makes sense here since it'd be returned for inputs that are literally "not a number"
or @chrome beacon did
but i still would't do it because honestly the moment you introduce nan's or infinities into anything, you are in for a bad time
you could return early for infinity and nans
it's like fucking memory damage in type unsafe languages
any arithmetic operation with a nan or an infinity almost always returns nan or infinity
meaning if you let one nan loose in your database, oops everything is nan
"Wait, its all NaN?"
"Always has been."
wait, if you parse for double, what's the parser gonna do if user inputs NaN?
NaN
uh oh