#help-development

1 messages · Page 1338 of 1

thorn isle
#

who was the resident towny guy here again

#

elgar?

mortal vortex
#

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"

thorn isle
#

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

slim wigeon
thorn isle
#

the more things change the more they stay the same

#

are you sure you're using the shaded jar?

mortal vortex
#

naming ur classes Main is such a dogshit practice

slim wigeon
thorn isle
#

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

slim wigeon
#

Just wow

mortal vortex
#

that is the best analogy i have EVER heard and im using it

thorn isle
#

now you have 3 ambiguous Main's that you have to reference via fully qualified name

green mauve
#

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?

young knoll
#

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

short pilot
#

Is there a way to modify compostable items, iirc no tag exists for those right? You would have to hardcode the interactions yourself?

mortal vortex
#

you mean like, the ability to make an item compostable?

#

then yeah, no tag

short pilot
#

Ah

sullen canyon
#

If you already picked one, then stick to it

whole mist
#

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;
        }
smoky anchor
#

not a fan of ignoring the log-ips server property

thorn isle
#

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

vagrant stratus
#

Why are we blocking cali though? lmfao

#

what'd i miss?

lilac dagger
#

probably has to do with age verification in california

thorn isle
#

myes

#

the UK is encroaching on US soil again

#

this time on the west coast

#

we're long overdue for a second round

vagrant stratus
#

ahhh

slender elbow
#

lmfao

#

wth is going on

mortal vortex
onyx fjord
#

its not like you face any consequences

thorn isle
#

myes

#

you are stronger than the law

onyx fjord
dry forum
#

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?

thorn isle
#

not super cleanly

#

you'll probably want to parse the placeholders on the backends and then send them to the proxy

dry forum
#

whats the best way to do that

thorn isle
#

what are you trying to do specifically

#

e.g. what placeholders are you trying to parse and why

dry forum
#

any, i want people to be able to use PAPI placeholders in my plugin

thorn isle
#

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

dry forum
#

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

thorn isle
#

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

dry forum
#

so id need to make it so my plugin works with a jar on the proxy and each backend?

thorn isle
#

yes, no way around it

#

papi only exists on backends

dry forum
#

alr thanks

thorn isle
#

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

dry forum
#

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?

quasi gulch
#

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.

thorn isle
thorn isle
#

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

dry forum
#

most placeholders would be offline players

#

if no one is online the feature js wouldnt work

thorn isle
#

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

dry forum
#

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

thorn isle
#

But if your goal is "all" or "any", you do need the player to be online

dry forum
#

but still, if no one is online it wont work

#

which wouldnt work

#

(for my plugin)

dry forum
#

so my best opiton is to use a db then?

thorn isle
#

No? A messaging service

#

Databases store data

dry forum
#

well i was going to do requests through db and i might still need to

thorn isle
#

Your backend already stores the data, the problem is the proxy needs access to it

dry forum
#

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?

thorn isle
#

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?

dry forum
#

yeah

thorn isle
#

That was not a yes or no question

dry forum
#

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

thorn isle
#

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

dry forum
thorn isle
#

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

dry forum
#

alr ill try thanks

green mauve
naive minnow
thorn isle
#

There is a wiki page on it but I don't remember what it says

pliant topaz
# green mauve but i dont think it would be any more efficeint than just taking a random one ea...

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).

Minecraft Wiki

Mob spawning is how passive, neutral, and hostile mobs are created in the world.

#

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

buoyant viper
#

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

pliant topaz
#

of course uwu

wraith spade
#

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);

                });
            }
        }
    }```
sullen marlin
#

Am I blind? Where did you define cloud variable

wraith spade
#

i didnt, im asking how to define then summon after i edited it

#

because idk how im new sry

crystal glen
sullen marlin
wraith spade
crystal glen
sullen marlin
undone axleBOT
#

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

wraith spade
# sullen marlin Then use a consumer as the third argument and edit in the consumer

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

sullen marlin
#

Looks ok, is the code running?

#

Is the location right?

wraith spade
#

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

wraith spade
mortal hare
#

even chatgpt thinks this should be a feature

pliant topaz
hushed spindle
#

ok thats cool except that the opinions of chatgpt dont matter

quaint basin
#

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

mortal vortex
hushed spindle
#

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

wraith spade
mortal hare
#

there's probably nothing more annoying in java than having to convert autoboxed array to primitive one

lilac dagger
#

True

#

But you can have a helper method to do it for you

mortal hare
#

does guava have something for me

lilac dagger
#

I don't know

#

Check both guava and apache commons

mortal hare
#

char[] arr = Chars.toArray(myList);

lilac dagger
#

Nice

wet breach
lilac dagger
#

Looks like it @wet breach

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

lilac dagger
#

Pretty cool apache commons have this for arrays

loud jasper
#

hi

lilac dagger
#

Only issue is it's lang3

wet breach
#

?services

undone axleBOT
mortal vortex
#

wants make minecraft servers 🔥🇵🇰

wet breach
#

guess you can't read

quaint basin
mortal vortex
#

@loud jasper im interested in buying a property in egypt

quaint basin
mortal vortex
#

#discoverRecipe(NamespacedKey recipe)

#

in theory, you just, on player join, and discover it

young knoll
#

The Minecraft recipe system doesn’t support that

mortal vortex
#

very helpful mr helper

#

can we get jishuna promoted to moderator

shadow night
#

Idk if it exists for char but I think I saw mapToInt recently

quaint basin
quaint basin
quartz basalt
#
        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
wraith spade
#

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 ); });

kind hatch
wraith spade
#

oh alright thank you

mortal hare
#

java 9 modules exist for ages yet no lib pretty much ever uses them

#

sad

thorn isle
#

They're more trouble than they're worth

slender elbow
#

no lib
lol

worldly ingot
#

JFX in shambles

orchid trout
#

jay

green mauve
#

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
thorn isle
#

this is something i've wanted in java for a long time

green mauve
#

how could that work?

thorn isle
#

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

green mauve
#

uhm, but each command has its own children and these children have their own

thorn isle
#

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

green mauve
#

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

thorn isle
#

very difficult to say without knowing what you're going for

green mauve
#

the thin is that each branch has to know its parent

#

or leaf

thorn isle
#

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

ivory sleet
#

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

green mauve
#

what is a visitor in this case

ivory sleet
#

interface Visitor {
void visitLeaf(Leaf l);
void visitBranch(Branch b);
}
for example

thorn isle
#
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

green mauve
#

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

thorn isle
#

i usually just nest CommandExecutors in maps

thorn isle
#

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

echo basalt
#

that's gonna be nightmarish to put in use

wraith spade
#

does anyone know how or have a doc or smth on how to pull people into a specific location?

buoyant viper
#

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

covert stump
#

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

mortal vortex
mortal vortex
#

ur last line could be compressed to just:

Component prefix = LegacyComponentSerializer.legacyAmpersand()
    .deserialize(Objects.requireNonNullElse(vaultPrefix, ""));
covert stump
# mortal vortex so what is it actually?

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...

mortal vortex
#

this server is called SpigotMC

#

yk what spigot is?

covert stump
# mortal vortex 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..

mortal vortex
#

you said: "So it should be like... ", so what do you need help with? is it not providing the output you expect?

covert stump
#

Title is missing

#

although lp prefix is good now

mortal vortex
#

customTitle, where is thgis?

mortal hare
#

Jackson2ObjectMapperBuilderCustomizer ah yes object mapper builder customizer

#

java moment

chrome beacon
#

Become the dev you want to find 🧠

mortal hare
#

does anyone know how to register a jackson module in java to forbid certain type from serializing to json?

mortal hare
#

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

frozen saddle
#

can someone help me out, willing to pay via paypal

young knoll
#

?ask

undone axleBOT
#

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!

scarlet ermine
#

Yo im new to plugin development and java coding language does anyone have any tips on how to get started?

buoyant viper
#

id certainly suggest getting a good understanding of Java down pat

scarlet ermine
#

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.

buoyant viper
#

thats good

#

keep practicing

mortal hare
#

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

buoyant viper
#

fp
java

theres ur first issue /j

scarlet ermine
mortal hare
scarlet ermine
mortal hare
#

its like stockholm syndrome, once you start hating, you'll start loving it

#

well its not jspecify issue but still

scarlet ermine
#

Oo wut u coding?

mortal hare
#

its thesis project which i fail miserably right now due to bullshit issues like these

scarlet ermine
#

Damn

sly topaz
#

the moment you start using Optional just to chain some operations, you already fell into a hole

#

normal procedural code won't hurt you

ivory sleet
#

that depends imo

mortal hare
#

streams are my guilty pleasure

#

it just feels so nice to write a for loop in one line

sly topaz
# ivory sleet that depends imo

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

silk elk
#

Does anyone have ProtocolLib experience? I'm genuinely pulling my hair out and I need help

ivory sleet
#

yea you just have to remember any kinf of functional java programming sucks ass cuz its java, miserable

sly topaz
sly topaz
ivory sleet
#

and doing that with jspecify sounds terrible, esp if u run that preprocessor nullaway? or whatever its called 😅

sly topaz
#

but also

#

?ask

undone axleBOT
#

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!

silk elk
ivory sleet
sly topaz
ivory sleet
#

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

silk elk
#

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

sly topaz
#

why

ivory sleet
#

^^

#

api should suffice for the problem ur trying solve?

sly topaz
#

though I think people use the consumable component with some fancy resource pack shenanigans for things like that in modern versions

silk elk
#

How would I go about using the API there? Doesn't changing the players rotation require you to use teleport?

sly topaz
#

yes, but why are you avoiding teleport to begin with

silk elk
#

Because its janky and I would need to be constantly calling it

#

For what I'm trying to do at least

sly topaz
#

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

sly topaz
#

you will be using a resource pack for the gun models I imagine so it shouldn't be much of an issue

silk elk
#

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

sly topaz
#

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

silk elk
#

I'll try it and see what happens

young knoll
#

It’s just sending a packet

#

And updating some fields

silk elk
# sly topaz I think you're digging yourself into a problem for no reason honestly, teleporti...

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.

kind hatch
#

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.

wicked swift
#

@everyone

#

Can anyone help me with my server

mortal vortex
wicked swift
#

Pls

wicked swift
mortal vortex
wicked swift
#

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

mortal vortex
#

and again, you need to be more specific, "can anyone help me setup my server" is incredibly vague, where are you stuck?

wicked swift
#

Oh sorry mb

covert stump
# mortal vortex `customTitle`, where is thgis?

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();```
mortal vortex
#

thanks for the update??

#

congrats, it works.

covert stump
umbral ridge
kind hatch
#

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. .-.

chrome beacon
#

Hm? You didn't know that?

lilac dagger
#

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

chrome beacon
#

they interact with the world and other entities

lilac dagger
#

i'm sure they had a reason to use entities for this

chrome beacon
#

Making them an entity just saves time

lilac dagger
#

true

thorn isle
#

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

young knoll
#

Could be a really big particle I guess

fallow saffron
# thorn isle since it interacts with the world, it must be server-side

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

chrome beacon
#

I mean do you really want them wasting time on that

#

There are a lot of other things to do

slender elbow
#

if spawning a lightning bolt brings your server to its knees then you have way bigger problems to worry about

onyx fjord
#

does client send cookies before joining?

slender elbow
#

no, it is the server that can request a cookie from the client

covert stump
#

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

frosty bolt
#

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>
mortal hare
#

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

ivory sleet
#

you might be able to store them off heap

#

not sure to what degree thatd help, but maybe?

thorn isle
#

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

echo basalt
#

you have no idea how many heapdumps are out there on git with all their credentials inside

green mauve
#

what are -infinity, infinity, NaN, -0.0 like things for? are they really used for anything

echo basalt
#

They represent some funky quirks of floating point operations

#

Like dividing by zero

umbral ridge
#

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

raw sequoia
thorn isle
#

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

chrome beacon
raw sequoia
raw sequoia
chrome beacon
#

2h is a very long time

raw sequoia
#

which vexes me

thorn isle
#

is it downloading or building

#

if it's downloading, what is it downloading

raw sequoia
#

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 ---

chrome beacon
#

It took like 15m on my 3470

raw sequoia
#

currently

thorn isle
#

are you on uh

#

dialup

remote swallow
#

the speeds look like that a bit

zealous scroll
#

Anyone have an idea of why some living players are returning #isDead true?

raw sequoia
#

hmm I see

#

I guess I'll terminate this one

#

probably the wsl

thorn isle
#

in which case an old stale player might be dead or invalid

chrome beacon
#

^

raw sequoia
#

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

chrome beacon
#

Just let it run

thorn isle
#

add those dependencies into your whatever build script

#

the DFU and authlib are public artifacts

chrome beacon
#

There's nms entity too

#

So can't just use public dep

thorn isle
#

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

raw sequoia
#

[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

chrome beacon
#

What's wrong with maven

#

It's actually quite good

raw sequoia
thorn isle
#

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

raw sequoia
#

btw why does spigot build tool exe is blocked in my pc

thorn isle
#

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

chrome beacon
#

Exe is just a wrapper and probably got false flagged because of that

thorn isle
#

it's self signed or something probably

raw sequoia
#

this is weird, it also included 3 files called scoped_dir

chrome beacon
#

Same place you got the exe

#

They're right next to eachother

#

?bt

undone axleBOT
thorn isle
#

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

raw sequoia
chrome beacon
#

Wdym?

thorn isle
#

click the linux button

raw sequoia
raw sequoia
thorn isle
#

doesn't matter

#

a jar is a jar

#

the only difference between the linux and mac buttons is the color

raw sequoia
#

this is damn weird, the window gives .exe while the linux gives a jar

thorn isle
#

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

chrome beacon
#

Or the classic 32bit Java install

raw sequoia
#

btw just to be sure; this issue of mine can be solved by build tools right?

chrome beacon
#

Yeah BuildTools can grab the required stuff

#

Don't recall if .10 was superseeded by .11

#

If so just change it in the pom

fickle spindle
#

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?

chrome beacon
#

Load the old config add the new value then save it

fickle spindle
chrome beacon
#

You just set with the setters

fickle spindle
# chrome beacon 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?
solid heart
chrome beacon
thorn isle
#

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

solid heart
chrome beacon
#

You shouldn't use those

#

Server hosts just run bt for you so that's fine

fickle spindle
solid heart
chrome beacon
#

A config doesn't need to contain a value for you to set a value

fickle spindle
# chrome beacon ??

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.");
}
chrome beacon
#

vcs2 just told you how

fickle spindle
solid heart
fickle spindle
solid heart
thorn isle
#

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

fickle spindle
fickle spindle
thorn isle
#

i have no idea what that means

thorn isle
fickle spindle
# thorn isle 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

thorn isle
#

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?

fickle spindle
fickle spindle
thorn isle
#
  1. load the config
  2. check if your new things are in the config
  3. if they aren't, add them with config.set(newThingPath, newThing), call config.save()
#

since you are loading the existing config, any changes the user has made will still be in the changed config

fickle spindle
#

how can i load the config? saveDefaultConfig();?

#

how can i check for new things? idk

thorn isle
#

that loads the config also, yes

#

if (config.has(newThingPath)) or whatever

fickle spindle
#

okay so if i have done "saveDefaultConfig();" i should be good with the loading

fickle spindle
thorn isle
#

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

thorn isle
fickle spindle
#

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?

thorn isle
#

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

mortal hare
#

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

fickle spindle
thorn isle
#

yes, and remember to save it

umbral ridge
#

thank you :D

fickle spindle
#

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)```
buoyant viper
#

?whereami

fickle spindle
#

oof mb xd

limber crest
#

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

sullen marlin
#

Are you using bungee? Does it depend on which server you join first?

limber crest
#

I am not using bungee. It doesn't matter the order, either

fallow saffron
#

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?

eager hawk
#

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?

hushed spindle
#

reloading is rarely recommended but for simple plugin testing it's fine

eager hawk
#

Alright, ty for informing! :)

hushed spindle
#

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

eager hawk
#

I don't think it'll be that big but thanks for letting me know, might use it in the future :)

thorn isle
#

Hotswap

onyx fjord
#

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

quaint basin
#

Is there a method in Bukkit that allows me to see all player deaths and return Map<Player, Integer> or something similar?

lilac dagger
#

Maybe there's a statistic that track those

#

If not you might have to impl such a system yourself

quaint basin
#

Maybe I'll have to read it from the disk

thorn isle
#

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

quaint basin
lilac dagger
#

It'll hang the thread you're in

#

Does it delegate to online players instead?

thorn isle
#

i don't know if it's thread safe but everybody definitely uses it async already

lilac dagger
#

If so it's not thread safe

thorn isle
#

e.g. every voting plugin ever

chrome beacon
#

If you have to ask the answer is almost always no

#

Doesn't stop people from using it that way though

thorn isle
#

i don't think i've ever seen it throw a cme but it might not be strictly "safe"

quaint basin
lilac dagger
#

Get the stats once and put them in a database of your choice

chrome beacon
lilac dagger
#

And then continue with that

thorn isle
#

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

quaint basin
thorn isle
#

but yes, a database is probably better for this

young knoll
thorn isle
#

neat

quaint basin
#

But supposedly Bukkit # getOfflinePlayers should be thread-safe if it only reads from disk

thorn isle
#

maybe the offline pdc api is the paper one?

quaint basin
#

I don't understand how this can't be thread-safe

chrome beacon
#

It accesses the online players too

lilac dagger
#

OfflinePlayers + checking if he's online

chrome beacon
#

it's not a pure disk read

thorn isle
#

it seems to be backed purely by the filenames in the player data dir

lilac dagger
#

It is?

slender elbow
#

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

thorn isle
#

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 🤡

lilac dagger
#

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

thorn isle
#

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

quaint basin
#
    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

thorn isle
#

getOnlinePlayers is fine, it's a read

#

the worst you'll get is a cme, you won't end up breaking the server internals

quaint basin
thorn isle
#

what is not fine is getOfflinePlayer, since that will write to the offlinePlayers map

#

which could fuck it over completely

thorn isle
#

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

quaint basin
thorn isle
#

there are several degrees of thread safe

quaint basin
thorn isle
#

getting potentially stale data can be considered thread safe, it depends on the contract

quaint basin
#

But yeah, that's not going to happen ig

thorn isle
#

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

quaint basin
#

How can a CME occur here?

thorn isle
#

players.addAll

#

addAll is implemented via iterator

quaint basin
#

String[] files = storage.getPlayerDir().list((dir, name) -> name.endsWith(".dat"));

and this too prob

thorn isle
#

well that's just a Files io operation

#

playerDir isn't going to change at runtime

quaint basin
thorn isle
#

filesystem access all-bets-off threading wise unless you use explicit locking anyway

thorn isle
lilac dagger
#

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?

thorn isle
#

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

thorn isle
#

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

lilac dagger
#

Hmm, what about reflections to get the offline players only?

thorn isle
#

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

lilac dagger
#

What does get offline player do?

thorn isle
#

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

quaint basin
#

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

thorn isle
#

use a database

buoyant viper
#

all roads lead to database

placid rivet
#

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

lilac dagger
#

spaces instead of dashes?

#

&m does the rest

placid rivet
#

i want a straight line

#

without any space between

lilac dagger
#

that's what &m does no?

#

you just use spaces

#

just spaces

#

not dashes

#

"§7§m ",

#

like this

placid rivet
#

let me see

thorn isle
#

that will create a horizontal line without any gaps, yes

placid rivet
#

oh, it works

#

yeah ty

thorn isle
#

&n or whatever the underline code is will also create a horizontal line a few pixels lower

placid rivet
#

thought there has to be some text

thorn isle
#

protip: you can also make space bold

buoyant viper
#

me finding out u can ~~ ~~ strikethrough space on discord

lilac dagger
#

yeah, it supports a lot of cool stuff

mortal hare
#

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?

sullen marlin
#

No idea but wouldn't surprise me if you couldn't transact commands to structure

ancient plank
young knoll
#

I like how they have NamedTextColor.GRAY in there too

#

Just for good measure

ancient plank
#

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

pliant topaz
#

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

pliant topaz
buoyant viper
#

wait yeah why are u mixing legacy formatting with component 😭

#

?jd one sec

undone axleBOT
ivory sleet
pliant topaz
#

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)

thorn isle
#

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

pliant topaz
sly topaz
#

player.sendMessage(textOfChildren(text("Something ", GRAY), text("else")))

sly topaz
thorn isle
#

bad pattern bad shmattern, what's wrong with it

#

text is text

sly topaz
#

like, when you have that you have to ask yourself, at what point it stops being convenient and just boilerplate

thorn isle
#

i shouldn't have to wrap my text (String) in another text wrapper (TextComponent) just to append it to another component

sly topaz
#

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

thorn isle
#

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

sly topaz
#

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

thorn isle
#

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

sly topaz
#

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

thorn isle
#

well, i think you're wrong and that it's ass and they should bring it back

sly topaz
#

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

young knoll
#

If people want to write heinous shit with my library that’s their right

sly topaz
#

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

thorn isle
#

appending text to text is my right also

ancient plank
#

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

sly topaz
#

should just make a translations file and use the TranslationStore API

thorn isle
#

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

sly topaz
#

you don't need an IDE plugin for it, IntelliJ automatically infers it most of the time

ancient plank
#

these aren't ever going to change outside of plugin updates so that's a needless addition tbh

sly topaz
#

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

ancient plank
#

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

sly topaz
#

often enough a localization system pays itself off

buoyant viper
#

i have never once localized a message in my life

#

if u dont speak my language u dont speak my software .

sly topaz
#

are you an english native?

buoyant viper
#

yeah

sly topaz
#

makes sense then

thorn isle
#

i'm not english native and i agree that if you don't speak english you have no business dealing with my software

ancient plank
#

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

sly topaz
#

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

thorn isle
#

rather, it definitely can

sly topaz
#

only time I see it being hurtful would be when people want too much from it

thorn isle
#

keep it simple, stupid

#

"just for good measure" is the path to hell

#

and it's paved with large libraries

sly topaz
#

the moment you introduce templating into your localization files is the moment you know you've gone down the wrong path lol

ancient plank
#

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

sly topaz
#

that's MCDev plugin

#

you can click on the boxes to get a color palette I think even

buoyant viper
#

ik intellij does it for java.awt.Color thats about it tho

ancient plank
#

yeah you can change the colors in here it's cool

sly topaz
#

it's pretty nice indeed

ancient plank
#

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

echo basalt
#

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);
buoyant viper
#

keeping my localization minimal (non existent)

echo basalt
#

remove the key from the config if you don't want the message to be sent (links to a dummy class)

thorn isle
#

real men localize all strings on the protocol layer

echo basalt
#

eh sure

thorn isle
#

i do this for player chat already but i've yet to figure out a way how to do it sensibly for system messages

echo basalt
#

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

buoyant viper
#

i always send unformatted text, to save on bandwidth

#

eye candy is bloat

thorn isle
#

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

ancient plank
#

does run command click stuff like that not run from the player's permission group

echo basalt
#

depends on how you format it

buoyant viper
#

well what if an admin clicks it

thorn isle
ancient plank
#

fair enough

echo basalt
#

there's a replaceText function that doesn't replace command tags

ancient plank
#

I'd say "Well admins clicking stuff willy nilly is a security problem" but well

thorn isle
#

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

ancient plank
#

can't trust anyone to know what they're doing tbf

young knoll
#

That’s a lot of head

echo basalt
#

didn't pictogram do that to show custom motd images

ancient plank
#

woah there he is

thorn isle
#

yeees

thorn isle
#

then mojang changed motd to not render heads in the very next version

echo basalt
#

and then reverted it for motds

#

I think

thorn isle
#

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

ancient plank
#

wild

thorn isle
#

or maybe it's 64

buoyant viper
#

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

gleaming steppe
#

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.

buoyant viper
#

load on join, save&delete from mem on quit, flush dangling on server stop

#

eventually ill do periodic save also

gleaming steppe
#

Nice hope it works well!

thorn isle
#

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

vivid skiff
#

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!

thorn isle
#

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

ivory sleet
#

ME replica?

thorn isle
#

for transformations, this is a good resource, i relied on this for my game engine

ivory sleet
#

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
vivid skiff
# ivory sleet ME replica?

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

thorn isle
#

that's a tall order

echo basalt
#

a strategy I did in the past was just having all the bones in at once and selectively hide them with MEG

vivid skiff
#

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

vivid skiff
young knoll
#

There are free model engine like plugins

ivory sleet
#

^

young knoll
#

Some might be outdated but they'd be good to learn from

thorn isle
#

perhaps abstract the dependency into its own modules so you can depend on e.g. the free BetterModels or ModelEngine both

vivid skiff
#

i found one written in kotlin, but didn't undrestand much on how it works

thorn isle
#

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

young knoll
#

Free Minecraft Models is pretty good from what I remember

thorn isle
#

knowing magmaguy it's probably also written in kotlin

echo basalt
#

Nah

#

Java for sure

thorn isle
#

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

young knoll
#

Looks java to me

echo basalt
#

At some point I considered making a compat layer between all of these

vivid skiff
#

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

thorn isle
#

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

young knoll
#

Umm aktually it’s builtbybit

vivid skiff
#

Isn't there a opensource plugin that uses displayentities instead of armorstands?

#

written in java

ivory sleet
#

java and kotlin aren't that much different

#

is there something specific you struggled understanding that was written in kotlin?

vivid skiff
#

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?

ivory sleet
#

cuz icl

ivory sleet
#

ah read it in intellij

#

much easier w kotlin code

thorn isle
#

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

ivory sleet
#

u can activate certain inlay hints which will expose inferred types

thorn isle
#

"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

ivory sleet
#

well atleast I can filter a list in kotlin in 20 different ways with their higher order first class functions /s

buoyant viper
slate mortar
#

did 26.1 by chance not get an api-version? or has the syntax changed

lilac dagger
#

it probably just changed

autumn zinc
#

Hi, everyone, does anyone know how to serialize ItemStack to json or something else?

lilac dagger
#

that's probably harder to do ^

slate mortar
#

cuz this do be happening on all 26, 26.1 and 26.1.1

lilac dagger
#

try serializing the map back and fort

slate mortar
#

emh whatever 1.21.11 works i guess

lilac dagger
#

weird

#

check the internal

slate mortar
#

just wanted to do that lol

#

ugh ij sucks

lilac dagger
#

go here

#

wait

#

you're on 21

#

not 26.1

slate mortar
#

wut

lilac dagger
#

the error says you're on 1.21.11

slate mortar
#

oh yea

#

the fuck

#

does bt still build 1.21 by default?

lilac dagger
#

yes

#

i think so

slate mortar
#

ew

#

that makes sense then

lilac dagger
#

yup

#

just confirmed

slate mortar
#

ugh time to wait another 5 hours

#

surprising the plugin still loaded tho,

#

backwards compatibility do be a thing

lilac dagger
#

😄

#

as long as you use the api and you don't use nothing new it's fine

slate mortar
#

oh god i just replaced the jar at runtime

lilac dagger
#

enjoy the shutdown errors

#

🙁

slate mortar
#

omfg

#

i wondered why it took so long to move, maybe because its a mount and my internet is 500 years old

buoyant viper
#

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?

chrome beacon
#

Can always use the wrapped versions

#

like the jdk does

buoyant viper
#

the boxed objects?

chrome beacon
#

iirc

chrome beacon
buoyant viper
#

i did think about that actually

lilac dagger
#

apache has a method that get ints or default if invalid

buoyant viper
#

to use Optional and generics

slate mortar
#

wee, thanks

buoyant viper
lilac dagger
#

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

buoyant viper
#

true

slate mortar
#

could maybe inline the error part, in case it's just one line

buoyant viper
#

i just hate having try-catch LOL

slate mortar
#

its what i usually do to make it less messy

lilac dagger
#

true, but they're here for a reason, so why not use them 😄

slate mortar
#

i generally hate exception handling so much

#

its a gigantic performance mess sometimes

chrome beacon
#

What are you parsing?

buoyant viper
#

user inputted numbers for currency calculations

lilac dagger
#

what if you put the default number as NaN?

#

wait nvm

#

it's only for Doubles

buoyant viper
#

wish we had C#'s tryParse method lol

thorn isle
#

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

buoyant viper
#

integer would be straight forward enough i suppose but

thorn isle
#

what are you doing again

#

what are we parsing?

buoyant viper
#

parsing strings from user input to do currency calculations

#

so really its a floating point im parsing

lilac dagger
#

just look for 2 ints and a .

buoyant viper
#

true...

thorn isle
#

but what about my e notation

#

and what about the 0 before the . being optional

buoyant viper
#

fuhgetaboutit

lilac dagger
#

oh yeah true

#

e

buoyant viper
thorn isle
#
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 
buoyant viper
#

if it starts or ends with a . i could just fill in a zero

thorn isle
#

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

buoyant viper
#

TRUE

lilac dagger
#

so Double.parseDouble doesn't seem as bad to use

thorn isle
#

but yeah i'd just try catch parsefloat

lilac dagger
#

and handle the number format if thrown

buoyant viper
#

that is basically what i do

#

i do end up with a double-parse though so

#

nonperformant...

#

(bc i have the isX method)

lilac dagger
#

the try catch then

#

and handle the error in one go

buoyant viper
#

true

#

what if it was like

young knoll
#

Use guava and their tryParse methods

thorn isle
#

yees add the 350mb dependency for the one 3-liner method that just wraps try-catch

buoyant viper
#
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

thorn isle
#

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

buoyant viper
#

the . needs to be optional too

#

what if they just enter 26

#

i need to treat that as 26.00

thorn isle
#

(\\d+|(\\d*\\.\\d*))

buoyant viper
#

🙏

thorn isle
#

but yeah just try catch it

#

the impact from filling the stack trace is negligible

buoyant viper
#

is the pipe necessary there

thorn isle
#

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

buoyant viper
#

oh i missed the first d* in pipe

thorn isle
#

if you don't want to allow .1 , you can just \\d+(\\.\\d+)?

young knoll
thorn isle
#

and if you're checking matches instead of find, you also need a -? at the front

buoyant viper
young knoll
#

It’s bad according to stackoverflow

buoyant viper
#

makes my code look like a NOOB because im gonna throw an EXCEPTION

#

(there are plenty of other reasons my code is newbish)

buoyant viper
buoyant viper
#

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

thorn isle
#

NaN is generally more trouble than nulls

#

since nulls throw early

#

nan's you have to explicitly check for

buoyant viper
#

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

thorn isle
#

i'm saying return a nullable Double instead of a double that might be nan

buoyant viper
#

but why

lilac dagger
#

oh yeah

thorn isle
#

nan's are evil

buoyant viper
#

:(

lilac dagger
#

you could also work with Double

thorn isle
#

same with infinities

lilac dagger
#

and that allows for null

buoyant viper
thorn isle
#

to be air NaN makes sense here since it'd be returned for inputs that are literally "not a number"

buoyant viper
#

or @chrome beacon did

lilac dagger
#

well, there's options

#

you choose what you like more tbh

thorn isle
#

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

lilac dagger
#

you could return early for infinity and nans

thorn isle
#

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

buoyant viper
#

"Wait, its all NaN?"
"Always has been."

lilac dagger
#

wait, if you parse for double, what's the parser gonna do if user inputs NaN?

thorn isle
#

NaN

lilac dagger
#

uh oh

thorn isle
#

well i think

#

let me doublecheck