#help-development
1 messages · Page 610 of 1
i don't like the new switch syntax. the old one is way tidier
i tried getOfflineplayer().getuniqueid
but it gives me warning
Anyone know why when this is ran and you enter the student id it just skips over the course code? ```c
void addStudent(int* student_id, int* course_code, Student* students, Course* courses) {
char id[MAX_ID];
char code[MAX_CODE];
printf("Enter Student ID: ");
fgets(id, MAX_ID, stdin);
id[strcspn(id, "\n")] = '\0';
int i, j;
for (i = 0; i < *student_id; i++) {
if (strcmp(students[i].id, id) == 0) {
break;
}
}
if (i == *student_id) {
printf("Student ID not found.\n");
return;
}
printf("Enter Course Code: ");
fgets(code, MAX_CODE, stdin);
code[strcspn(code, "\n")] = '\0';
for (j = 0; j < *course_code; j++) {
if (strcmp(courses[j].code, code) == 0) {
break;
}
}
if (j == *course_code) {
printf("Course Code not found.\n");
return;
}
printf("Student %s added to Course %s.\n", id, code);
}
output
Enter your choice: 1
Enter Student ID: 12345
Enter Course Code: Course Code not found.
is the warning for getOfflinePlayer?
public class Human {
private String name;
public Human(){}
public String getName(){ return name;}
public String setName(String name) { this.name = name; }
public void setFromConfig(ConfigurationSection section){
this.name = section.getString("name");
}
public void setToConfig(ConfigurationSection section) {
this.section.set("name".this.name);
}
}
Then outside the class you just use
Human human = …;
human.setFromConfig(config.getConfigurationSection("someSection"));
human.setToConfig(config.getConfigurationSection("someSection"));
@worthy moat
yep
https://hub.spigotmc.org/javadocs/spigot/org/bukkit/OfflinePlayer.html#getUniqueId() shouldnt have any errors
declaration: package: org.bukkit, interface: OfflinePlayer
its bc getOfflinePlayer is Nullable
its for 1.8
and how to solve it
update? idk 
Out of luck 1.8 support is not in service
it exists
then you have no problem..?
no i have
hi , mm i know this looks like a dumb question ..
i made a shop plugin , fully working my only problem is
getOfflinePlayer(player_name).getUniqueId().toString()
when i buy an item the lore of the price is still there ..
remove it from the meta
i think its called meta?
i think you should remove it from the meta
meta data?
Yes
yep item meta
That will work
already doing that
Dont see the issue
wait where comes that this.section.set from?
No your not
is it normal to give me a warning in eclipse ?
Yes
okay
explain?
Oh its just section
Remove the this.
okay so setFromConfig would be read and setToConfig is write?
you're clearing the List but not resetting the list as the lore, so you need to do lore.clear and then meta.setlore(lore) then item.setmeta(meta)... a bit annoying but that should help
To read and respectively write
bump
Yeah
But do keep in mind this will remove lore that the user already has on the item, so if someone else is using a plugin that adds items with lore, your plugin will remove it
Whats wrong with that okay1204?
I just wanna increase the attack damage of the weapon
but for some reason using an attribute MODIFIER resets the damage
and makes it do only 1 damage
and also displays all that annoying text
"When in main hand..."
ITS only a shop plugin
just want to change this text from "8 attack damage" to "9 attack damage"
and have the sword deal one more damage
Ok so Ive added the read and write methods to both classes
You can add an itemflag to get rid of those attribute lore things
yeah but then i have to manually display it in the lore
i thought there would be a better way
also how do i increase the damage
okay to write something you mentioned this (I altered it to my classes):
Cache.arena.write(AlphaWars.data.getConfig().getConfigurationSection("someSection"));
But what exactly do you mean by "someSection" What do I put in there?
Its the path of ConfigurationSection
Is that just the Key for my Object in yaml?
Like test: "test"
you have to mess with the attributes
yeah thats what ive been trying to do
If you're trying to save a custom class to a yaml file I'd really recommend serialization. You basically provide some methods that tell Spigot how to parse your class into config data and how to parse the config data into a class. This guide really helped me: https://www.spigotmc.org/wiki/introduction-to-serialization-section-2/
The home of Spigot a high performance, no lag customized CraftBukkit Minecraft server API, and BungeeCord, the cloud server proxy.
sometimes you need to use NMS for it
Collection<AttributeModifier> modifiers = meta.getAttributeModifiers(attribute);
if (modifiers != null) {
for (AttributeModifier modifier : modifiers) {
if (modifier.getName().equals("smithingEnhancement")) {
meta.removeAttributeModifier(attribute, modifier);
}
}
}
meta.addAttributeModifier(attribute, new AttributeModifier(UUID.randomUUID(), "smithingEnhancement", level, AttributeModifier.Operation.ADD_NUMBER, EquipmentSlot.HAND));
this just sets the damage to level
doesn't add to the damage like how i expected
Any suggestions for ensuring an RTP teleports above ground and not in a cave
you can use https://hub.spigotmc.org/javadocs/spigot/org/bukkit/World.html#getHighestBlockAt(int,int)
declaration: package: org.bukkit, interface: World
This one didnt work and was so called trash by some helpers here
oh bet I forgot about that method
thanks
declaration: package: org.bukkit.attribute, class: AttributeModifier
This allows u to specify equipment slot
ive done that
oh really? I thought this was recommended but maybe things have changed in the past few years. Let me read what they said
it looks different though
also still doesnt add to attack damage
it just sets it to 1
@ivory sleet
Okay
thanks
so I just use this to get the original attack damage
and add to it?
bump
So in yaml I’d have
someSection:
name: Conclube
I had a question under this message..Sry
“someSection” gets the indented stuff under it
might wanna go to a c++ server
damn got an error
Caused by: java.lang.NullPointerException: Cannot invoke "org.bukkit.configuration.ConfigurationSection.set(String, Object)" because "map" is null
at de.marvn.alphablock.alphawars.util.objects.Arena.write(Arena.java:31) ~[?:?]
at de.marvn.alphablock.alphawars.listeners.PlayerInventoryClick.onPlayerInventoryClick(PlayerInventoryClick.java:61) ~[?:?]
at jdk.internal.reflect.GeneratedMethodAccessor747.invoke(Unknown Source) ~[?:?]
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:300) ~[patched_1.8.8.jar:git-PaperSpigot-445]
... 19 more```
public void write (ConfigurationSection map) {
map.set("name", name);
map.set("maxPlayers", maxPlayers);
map.set("teams", teams);
map.set("bronzeSpawner", bronzeSpawner);
map.set("silverSpawner", silverSpawner);
map.set("goldSpawner", goldSpawner);
map.set("diamondSpawner", diamondSpawner);
map.set("emeraldSpawner", emeraldSpawner);
}```
the first set is line 31
How does this happen?
u’re calling write(null) effectively
I know a couple people here do you know C
hmm
getConfigurationSection(“someSection") probably returns null
so this one is wrong
I didnt mean that u should use “someSection” literally
not much, but i doubt anyone would help u here. this is a spigot development channel, not c
It was an example
OH im dumb i forgot to add getchar();
Anyone know why when this is ran and you
I used another name haha
Try to clean stdin buffer, fflush(stdin) after entering student Id
But should the name be my class or what?
I just had to add getchar
It have same effect as fflush, "enter" was left in buffer
yea
Causing "enter" to be course code
Ok i probably misunderstand something...What exactly should I enter there?
How does config look rn?
you mean the yml?
Yep
Lobby:
==: org.bukkit.Location
world: world
x: 735.5
y: 23.0
z: -1012.5
pitch: -0.053918753
yaw: 315.0
Only this
nvm still lost
Is this data u’re gonna store or just a set config format?
Its fresh data i stored earlier this day...There is no config format
Can u store it again?
Like without reading it first
But else
You probably wanna add
if (section == null) return;
Cache.arena.write(AlphaWars.data.getConfig().getConfigurationSection("Arena"));```
Is the part in the write () the reading part? Yes am I right?
Yeah
So just do this instead
ConfigurationSection section = new MemoryConfiguration();
blah.write(section);
config.set(…, section);
so like this?
ConfigurationSection section = new MemoryConfiguration();
Cache.arena.write(section);
AlphaWars.data.getConfig().set("Test", section);```
Yea
NOW IT WORKS
BUT
HashMap<String, Team> teams = new HashMap<>();
I ve got this in my Object
(another Object)
I added the same methods...But how do I fix this then?
Test:
name: PirateCraft
maxPlayers: 2
teams:
RED: !!de.marvn.alphablock.alphawars.util.objects.Team
spawnBlock:
==: org.bukkit.Location
world: PirateCraft
x: -122.0
y: 64.0
z: -326.0
pitch: 0.0
yaw: 0.0
spawnPoint:
==: org.bukkit.Location
world: PirateCraft
x: -122.0
y: 64.0
z: -325.0
pitch: 0.0
yaw: 0.0
BLUE: !!de.marvn.alphablock.alphawars.util.objects.Team
spawnBlock:
==: org.bukkit.Location
world: PirateCraft```
Its a bit complicated but basically
For write
{
ConfigurationSection subSection = new MemoryConfiguration();
teams.forEach((key,value) -> {
subSection.set(key,value);
});
section.set("teams",subSection);
}
ok let me test
For read
{
ConfigurationSection subSection = section.getConfigurationSection(“teams”);
if (subSection != null) {
subSection.getValues(false).forEach((key, value) -> {
teams.put(key,(Location)value);
});
}
}
You get the concept I hope
Bruh it does overwrite my other data
it basiucally deletes everything and does only add my stuff
And in the write secion the teams thing does somehow not work
How did u incorporate it
Add it to ur own code
ConfigurationSection section = new MemoryConfiguration();
Cache.arena.write(section);
AlphaWars.data.getConfig().set(Cache.arena.getName(), section);
AlphaWars.data.save();```
I dont add.....I just set something into the config and save...Does that override old stuff?
Cache.arena
Depends
so everytime I set something it just added those stuff
wait let me retry
nvm it just added the stuff
but still this
RED: !!de.marvn.alphablock.alphawars.util.objects.Team
spawnBlock:
==: org.bukkit.Location
world: PirateCraft
x: -153.0
y: 64.0
z: -219.0
pitch: 0.0
yaw: 0.0
spawnPoint:
==: org.bukkit.Location
world: PirateCraft
x: -159.0
y: 64.0
z: -219.0
pitch: 0.0
yaw: 0.0
BLUE: !!de.marvn.alphablock.alphawars.util.objects.Team```
this is how my write looks like
public void write (ConfigurationSection map) {
ConfigurationSection subSection = new MemoryConfiguration();
teams.forEach(subSection::set);
map.set("teams", subSection);
map.set("name", name);
map.set("maxPlayers", maxPlayers);
map.set("bronzeSpawner", bronzeSpawner);
map.set("silverSpawner", silverSpawner);
map.set("goldSpawner", goldSpawner);
map.set("diamondSpawner", diamondSpawner);
map.set("emeraldSpawner", emeraldSpawner);
}```
Ah
I might wanna do it like
(key,value) -> {
ConfigurationSection s = new MemoryConfiguration();
value.write(s);
config.set(key,s);
}
This Serialize shit is going so far that I am really this close to just use a DB
Lol
I think ConfigurationSerializable wouldve worked fine
I don’t like it but it works yk
I tried it but it didnt work
Bad try
Burh
Should I now rollback to the Serializable shit or push this current thing further?
U choose
You say the Spigot thing is much better in my dumb case?
I have to go to sleep quite soon
Its easy if u dont understand shit
you live in germany right? Recognized it with your "
Sweden actually
yeah thats something right for me currently
ah I tried it haha
Yeah close enough, so where are you from if I may reciprocate the question
germany haha
package name starting with .de = germany
Ah
correct
Yeah maybe alex can help now instead
Well I had this gf who lived in germany, but never got good at german, else pretty nice
I cant believe I write whole backend stuff and other applications but fail to understand minectaft..Sometimes I think all I know is just flushed down the toilet as soon as I start with MC
Haven’t you worked with like configuration parsers before?
And serialization data modelling
I worked with Jackson if you mean this parser
Yea
Yeah but Jackson is far away from that...Or at least I never hat do dig that down
Just treat the spigot config api like jackson without the annotation stuff
Yeah
All parsers are similar
They have ways to write and read from readers and writers such that they yield and consume some type of glorified map object
I mean with jackson i just built my object....Added the Annotations and then I could parse and read
Cuz spigot doesnt have that annot thingy
Oh not true
It can be complicated if u want
yea sure but not for small things...Only if you need some specific thing
It does have branches for YML
what's the issue with ConfigurationSerializable?
xD
mhm static arena object
oh damn
another one who hates this test thing
xD
aight...Thanks for your help man..You really saved me a lot of nerves
xD
or well.. majorly fuck up the first time and get it right the second
Which is what I did with my minigame lib
It’s not trial and error if there is no error
wat u got against java.util.Logger? 
Not enough RCE exploits
True
How can I set custom model data for world.item.ItemStack?
Well i think there are just better alternatives out there thats all (:
https://github.com/winnpixie/bt-gui/blob/main/src/main/java/io/github/winnpixie/btgui/BuildToolsGUI.java#L11 no better alternatives, only Java Logger.

also is it just me or does spigot 1.20.1 have a memory leak?
Shouldn’t have?
i removed my plugin to make sure its not mine thats causing it
Set the nbt
Profile it
i left it running for 15 minutes and i came back, my memory usage went from 60% to 95%
its been happening consistently for a couple days
What method should I use for that?
just now i removed my plugin to confirm that it wasnt mine
what does that mean
And it'll generate a file that's usually as big as the amount of RAM the JVM is using
is it a plugin?
yeah
alr ill download it and see
Anyways you'll want to grab that file and run it on a profiler
I usually use YourKit although it's pricy
Think I forced my boss to pay 100$ for a 1 year personal license
Guys how do I serialize a HasMap ?
for(Allergy allergy : this.allergies)
tempSerializeAllergies.add(allergy.serialize()); // Serialize this allergy and add it into the temporary list```
You serialize its keys and values
or store a maplist or something
HashMap<Map<String, Object>, Map<String, Object>> tempSerializeTeams = new HashMap<>();
like that?
oh my
what
xD
I dont know any further
Time to learn the basics of serialization and data structures
What data is there to serialize?
yeah i am fine with that
I saw something about a list of allergies
HashMap<String, Team> teams = new HashMap<>();
oui
Okay
what? no it doesn't
we're not talking about bukkit's team class
oh ok
how can I get the default attack speed of a tool/weapon
So we can store that as a section where the key (string) is the name and the team is the value
Something like
Map<String, Team> teams = ...;
for(Map.Entry<String, Team> entry : teams.entrySet()) {
String teamName = entry.getKey();
Team team = entry.getValue();
config.set(teamName, team);
}
Ideally in its own teams section
material.getDefaultAttributeModifiers(EquipmentSlot.HAND).get(Attribute.GENERIC_ATTACK_SPEED) returns an attributeModifier with a negative value for some reason
And then to read you get the teams section, loop through its keys and call section.get(key, Team.class) and it does magic
I try to write something not read

ArrayList<Map<String, Object>> tempSerializeAllergies = new ArrayList<>(); // Using this as temporary container allowing us to serialize each allergy into a list
for(Allergy allergy : this.allergies)
tempSerializeAllergies.add(allergy.serialize());```
I try to reproduce this
just with a HashMap instead of an Array
Or did I misunderstand something?
Yeah you misunderstood it completely
I just want to fetch the attack speed that is displayed on the item here
ah damn
Get the attribute from the meta and get its base value
i've tried that
getAttributes(Attribute.GENERIC_ATTACK_SPEED) returns null
and material.getDefaultAttributeModifiers(EquipmentSlot.HAND).get(Attribute.GENERIC_ATTACK_SPEED) returns an attributeModifier with a negative value for some reason
There's a registerAttribute method
It should register an attribute with default values
Nope I cant go any further
ugh let me help marvn real fast
Basics of serialization
(I should write a proper post about this)
No
not yet
Serialization is basically the process of converting your object to binary
Or in this case into data that goes in your YML file
HashMap<String, Map<String, Object>> tempSerializeTeams = new HashMap<>();
teams.forEach((key, value) -> {
tempSerializeTeams.put(key, value.serialize());
});``` Is this how they would transform a HashMap?
oh ok
Basically it's the process of
Java Object -> Stored data
Stored Data -> Java object
yes
And usually what's read matches the original data of what went in
yes
With bukkit's YML system, we have this little interface called ConfigurationSerializable
ok
also i did /spark heapdump when memory was at 92% usage, it generated an hprof file which i have no idea how to open
And it specifies that we need to make a Map<String, Object> serialize method, as well as one of 3 things:
- A constructor that takes the serialized map and creates the object from serialized contents
- A valueOf method that does the same process
- A deserialize method that does the same process
And here's a basic example
yes that stood in the docs of spigot right?
public class Person implements ConfigurationSerializable {
private final String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(Map<String, Object> map) {
this.name = (String) map.get("name");
this.age = (int) map.get("age");
}
// Some fancy method
public void growUp() {
age++;
}
public Map<String, Object> serialize() {
Map<String, Object> map = new HashMap<>();
map.put("name", this.name);
map.put("age", this.age);
return map;
}
}
This is your person class
Now I'll edit it so it conforms to the spec
Now this class is "Configuration serializable", and we can yeet it in our config directly, or into any collections as well
Hey, so some villagers seem to be getting frozen, i think tho some mobs arent scaring them either?
yeah
FileConfiguration config = ...;
Person joe = new Person("Joe", 69);
config.set("person", joe);
FileConfiguration config = ...;
Person joe = config.get("person", Person.class);
This is for an individual
But what would it look like if you had a HashMap... I understood it as far as you explained it to me
We can also pass a list, for example
List<Person> city = List.of(
new Person("Joe", 69),
new Person("John", 420)
);
config.set("population", city);
List<Person> city = (List<Person>) config.get("population");
And bukkit's yml system will do all the fancy logic
Now, for maps
A map is basically a collection with a key and a value
And YML also works with a key-value system
As
number: 123
text: "Some text!"
Can be seen as a map {"number":123, "text":"Some text!"}
What if we do the reverse
yep...And in my case I have an Object which is needed to be serialized and in this Object there is a HashMap with String as key and another Object as value
And go from {"team-one":Team, "team-two":Team}
Team implements the ConfigurationSerializable class so we can yeet it directly
And the key in our map is a string too, which we can use as the team's name
technically but i dont save the team alone. I save with in the Arena Object
You can make your arena object serializable and save all its contents
yes thats what I did
And now I have to serialize the teams in my ArenaObject
@Override
public Map<String, Object> serialize() {
HashMap<String, Object> mapSerializer = new HashMap<>();
mapSerializer.put("name", name);
mapSerializer.put("maxPlayers", maxPlayers);
mapSerializer.put("teams", teams);
mapSerializer.put("bronzeSpawner", bronzeSpawner);
mapSerializer.put("silverSpawner", silverSpawner);
mapSerializer.put("goldSpawner", goldSpawner);
mapSerializer.put("diamondSpawner", diamondSpawner);
mapSerializer.put("emeraldSpawner", emeraldSpawner);
return mapSerializer;
}```
So this should work fine?
The teams thing?
Try and see, but seems fine
Back to you, You'll need to use a profiler
Yeah
what do you recommend
I use YourKit
And if you have a trial for it I'd recommend
It's pricy otherwise
I still paid for it
I've used VMs before for free trials
And had like a shared folder
But it was gimmicky
Now it saved this
PirateCraft:
==: de.marvn.alphablock.alphawars.util.objects.Arena
maxPlayers: 6
teams:
RED:
==: de.marvn.alphablock.alphawars.util.objects.Team
spawnPoint:
==: org.bukkit.Location
world: PirateCraft
x: -159.0
y: 64.0
z: -219.0
pitch: 0.0
yaw: 0.0
spawnBlock:
==: org.bukkit.Location
world: PirateCraft
x: -153.0
y: 64.0
z: -219.0
pitch: 0.0
yaw: 0.0
BLUE:
==: de.marvn.alphablock.alphawars.util.objects.Team
spawnPoint:
==: org.bukkit.Location
world: PirateCraft
x: -159.0
y: 64.0
z: -328.0
pitch: 0.0
yaw: 0.0
spawnBlock:
==: org.bukkit.Location
world: PirateCraft
x: -153.0
y: 64.0
z: -328.0
pitch: 0.0
yaw: 0.0
emeraldSpawner:
- ==: org.bukkit.Location
world: PirateCraft
x: -141.0
y: 51.0
z: -273.0
pitch: 0.0
yaw: 0.0
name: PirateCraft
goldSpawner:
- ==: org.bukkit.Location
world: PirateCraft
x: -111.0
y: 63.0
z: -219.0
pitch: 0.0
yaw: 0.0
- ==: org.bukkit.Location
world: PirateCraft
x: -111.0
y: 63.0
z: -328.0
pitch: 0.0
yaw: 0.0
bronzeSpawner:
- ==: org.bukkit.Location
world: PirateCraft
x: -111.0
y: 63.0
z: -219.0
pitch: 0.0
yaw: 0.0
- ==: org.bukkit.Location
world: PirateCraft
x: -111.0
y: 63.0
z: -328.0
pitch: 0.0
yaw: 0.0
diamondSpawner: []
silverSpawner: []```
Yeah that looks ok
ok and now this happens
You'll need to make your read constructor that reverses the thing
yep just forgot that
1s
Ayy just got paid
So if the HashMap does work with Bukket without any problems
public Arena(Map<String, Object> serializedArena) {
this.name = (String) serializedArena.get("name");
this.maxPlayers = (Integer) serializedArena.get("maxPlayers");
this.bronzeSpawner = (List<Location>) serializedArena.get("bronzeSpawner");
this.silverSpawner = (List<Location>) serializedArena.get("silverSpawner");
this.goldSpawner = (List<Location>) serializedArena.get("goldSpawner");
this.diamondSpawner = (List<Location>) serializedArena.get("diamondSpawner");
this.emeraldSpawner = (List<Location>) serializedArena.get("emeraldSpawner");
this.teams = (HashMap<String, Team>) serializedArena.get("teams");
}```
Then this could work right?
Pretty much
actually nvm i think if figured out how to get the attack speed
the hashMap is teams at the bottom
looks like it's just 4 minus the negative value that i was getting
Yes
Order doesn't really matter
4-2.799999952316284 ~= 1.2
But yeah try and see
The default attack speed is 4
?tryandsee
this does not work
Errors?
That’s just how mojang programmed it
1s
Since they wanted you to have an attack speed of 4 when holding nothing
nvm forgot something again
1s
Caused by: java.lang.IllegalArgumentException: Specified class does not exist ('de.marvn.alphablock.alphawars.util.objects.Team')```
Sounds like a corrupted jar to me
rebuild and reupload
ok just deleted the jar...Cleaned with my gradle and then rebuilt it
Still same error
What’s goin on
🤷♂️
are you shading?
if so might want to look to make sure you are not excluding something
but you are using gradle so I can't help much with that
It should so yes
What do you use?
Maven?
Does anyone know since when you can write html code into github markdown file?
wasnt it always a feature
its been like that forever afaik
oh weird i never realize about it
Is there a way I can easily check if something like Cactus is placeable on X block?
Like given a location/type of block?
Basically, if vanilla behavior would have a right click place block of type X on the location they clicked?
There are various methods in BlockData to do this
hadSupport I think? Or isSupported
Would anyone know why when I try to send an entity destroy packet to all online players, it only gets destroyed for one player?
can we see your code
for(Player allOnline: Bukkit.getOnlinePlayers()) {
cadiaBees.cadiaCore.hologramManager.despawnHologram(allOnline, holoManager.getHolosForHive(customHive).get(0));
//CadiaCore.getInstance().hologramManager.spawnHologram(allOnline, holoManager.getHolosForHive(customHive).get(0));
}
public void despawnHologram(Player player, Hologram hologram) throws InvocationTargetException {
List<Integer> holoIDs = hologram.getHoloIDs();
for (Integer holoID : holoIDs) {
ClientboundRemoveEntitiesPacket removePacket = new ClientboundRemoveEntitiesPacket(holoID);
((CraftPlayer) player).getHandle().connection.send(removePacket);
}
}
ive tried a few different ways
im not, its only there cause it told me I had to add it 💀
because if it throws for one player the rest wont receive it
why not put a try catch block lol
actually, I just removed it and its not complaining now
so maybe it was for one of the other methods I tried.
im not deleting the ids from the object though so i dont think its an issue where deleting it from the first player deletes the actual id
if you're just sending the packet that won't be the case
its so weird it only works perfectly if theres 1 player online
so if theres multiple players it just doesnt work at all
or only works for one player?
If theres multiple players, it works for the first player in the player list it seems
or maybe its a random player, but it only works for one
is the packet sending at all for the other players
test it
How?
Oh yeah if I send a message to all players in the loop it sends to everyone
I tested that
I wonder how much of my life I've spent looking at some kind of progress bar
my only idea is that the id is different for each player for some reason
for the spawn packet you are using the same id right
Hastebin is a free web-based pastebin service for storing and sharing text and code snippets with anyone. Get started now.
this is my spawnHologram method
so I just need to create the id outside the loop
Any idea how I could cleanly do that so each player has their own holo? Not all players are supposed to see the holos at all times, sometimes has player-specific info etc
I think at one time I was just incrementing a value in the holomanager..
instead of making a random every time..
class hologram{
List<UUID> viewers;
void displayAll(){
for(UUID in viewers){
add entity packet
}
}
void hideAll(){
for(UUID in viewers){
remove entity packet
}
}
}```
i would do smth like this
where you keep track of all the viewers of a specific holo
Hmm, would it be good to have that in the holo itself or in the manager class?
I currently have an abstract Hologram class, and 2 sub-types InfoHologram and OwnableHologram. The InfoHologram isn't interactable/owned by anyone, and the ownable is, well.. ownable/interactable
but yeah just keep the id as a final variable instead of random each time
Each holo also has multiple holos within it. Like if I make a hologram, I can add lines to it. Each line is its own TextDisplay with its own ID, etc so I also have to store those
tricky tricky lol
https://github.com/MitchGB/MinecraftEnhanced/blob/main/src/main/java/com/buoobuoo/minecraftenhanced/core/entity/interf/CustomEntity.java
Ignore the stupid map thingo i have going on
trying to make this clean
but this sorta uses the same idea
it has children and iterates through each child, hiding or showing the respective entity
default void hideEntity(Player player){
removeShownPlayer(player.getUniqueId());
getChildren().forEach(e -> e.hideEntity(player));
ClientboundRemoveEntitiesPacket removeEntitiesPacket = new ClientboundRemoveEntitiesPacket((this).asEntity().getBukkitEntity().getEntityId());
Util.sendPacket(removeEntitiesPacket, player);
}
default void showEntity(Player player){
getChildren().forEach(e -> e.showEntity(player));
if(this instanceof Invisible){
hideEntity(player);
return;
}
if(!canShow(player))
return;
addShownPlayer(player.getUniqueId());
ClientboundAddEntityPacket addEntityPacket = new ClientboundAddEntityPacket(asEntity());
ClientboundSetEntityDataPacket setEntityDataPacket = new ClientboundSetEntityDataPacket(asEntity().getBukkitEntity().getEntityId(), asEntity().getEntityData(), true);
Util.sendPacket(addEntityPacket, player);
Util.sendPacket(setEntityDataPacket, player);
}```
These two methods are purely for packet sending, not instantiation or anything
looks like I just need to improve my way of storing/creating IDs
its weird to me that entities need an ID AND a UUID
just use the default getBukkitEntity().getEntityId() method
then you don't need to create an id
ClientboundAddEntityPacket spawnPacket = new ClientboundAddEntityPacket(id, uuid, hologram.getHoloLocation().getX(), currentY, hologram.getHoloLocation().getZ(), 0.5f, 0.5f, net.minecraft.world.entity.EntityType.TEXT_DISPLAY, 1, new Vec3(0,0,0), 0.25);
This constructor wants an ID and UUID though
yeah thats what ive been doing, just gotta make a clean way of storing it
I just store it on the hologram object
ID and UUID both?
Hello, quick discussion: I like to use the @NotNull tag in my API code. However, I acknowledge that it's just a tag and won't actually force null, therefore I do validation checks. However my IDE keeps giving me warnings saying "Var is never null" because of the NotNull tag. Firstly, please reassure me that I'm not being dumb by keeping the validation in and secondly, is there a way to "ignore" warnings like you can with spell checkers on word because it's really annoying me
you can supress warnings with another annotation tag
however if its telling you that var is never null, then it might be a case of that its nearly impossible that it could be null
or a situation where the value is never unset
Pretty sure you can just toggle it in ide settings
But it’s good practice to always check nulls
so for example, if you initialize a variable at the top of class, then it would be impossible when you initialize the class that variable would be null depending how its initialized
@drowsy helm Do I need to keep track of the hologram IDs, UUIDs or both? Ideally, id only like to track the entity IDs not uuids
Well it's my IDE. The input SHOULDN'T be null, but I can't stop 3rd parties from doing it
I assume they need to have the same ID for all players but not uuid?
yeah i think uuid isnt relevant
you can just use a random one
What happens if my random.nextInt somehow generates the same ID twice? lol
in that case, how can I keep track of the entities if I dont track their ids?
🤔
look at the code i sent you earlier, thats how i did it in my implementation
you can check if a UUID exists already
or even an ID if you just keep a list of already used ones
think I should use AtomicInteger..?
no?
Hello! I got a question, did the NMS for 1.20.1 change or something? I can't seem to find the import for ServerPlayer
don't think a lot of it changed, but NMS typically changes between updates
@drowsy helm I dont see how you're generating the initial entity IDs
should I just track the UUIDs, then get the entity by UUID then call entity#getBukkitEntity#getID?
that way im only tracking uuids
probably just be best to let the server generate the UUID's for you
less for you to do
Yeah, i know that part..
when I initially create the hologram, the hologram itself gets a randomly generated ID
The hologram itself isn't an entity, but each line is its own entity.
So for each entity, I need to make a unique ID AND UUID, then need to track one or the other, or both so I can store them/reference them later
private int holoID;
private List<Integer> entityIDs;
private List<UUID> entityUUIDs;
are you using display entities or armor stands?
because regardless holograms get UUID's
even if you add more entities for the hologram, if a hologram always has at least 1 entity, you can just use that entities UUID
TextDisplay entities
it should still have a UUID then, even if you are using multiple
https://hastebin.com/share/orakezoluf.kotlin heres my Hologram class
Hastebin is a free web-based pastebin service for storing and sharing text and code snippets with anyone. Get started now.
why not treat each hologram class as it's own entity
They need to be grouped and accessed as groups
cause multiple lines and such
thats fine
yeah thats still possible
you can make an entity that takes in a collection of entities
what do you think the ender dragon is?
ender dragon is nothing more then like 9 entities put together
wait wut
yeah ender dragon isn't a single entity lol
because they couldn't make a single entity move in various ways
so they split it up
and all those entities move together
it is also why the Ender Dragon is the hardest entity to mess with too
sounds like doing that for my case would be overkill
no, in your case its valid because you want all those entities to be associated with a single entity
each "line" my holo gets is its own entity ofc like this
ClientboundAddEntityPacket spawnPacket = new ClientboundAddEntityPacket(id, uuid, hologram.getHoloLocation().getX(), currentY, hologram.getHoloLocation().getZ(), 0.5f, 0.5f, TEXT_DISPLAY, 1, new Vec3(0,0,0), 0.25);
wait 1s
there
I just need a way to make sure "id" is different for each line, but the same for each player..
might have an idea..
extend the text entity, and make it hold a collection of text entities
then you can just keep track of 1 uuid
all those other entities are associated with that 1 entity only
I guess you would have to implement it instead, and then spawn it as a custom entity
reeee
public abstract class Hologram implements TextDisplay {
private Collection<TextDisplay> holoDisplays;
so basically this..
and remove my entityIDs, entityUUIDs..
yeah basically
https://hastebin.com/share/anigefiqod.typescript
I was thinking smth like this
Hastebin is a free web-based pastebin service for storing and sharing text and code snippets with anyone. Get started now.
that would work too
you were the one that wanted to use hastebin
personally I like using md's paste site
I dont wanna use armorstands now that TextDisplays exist
yeah fair enough
thats fine, just swap out the armor stand for text display
I like how TextDisplays can have transparent backgrounds, cant be seen through blocks, etc
?paste
https://paste.md-5.net/aqemurorad.cs thinking this might be the move.
drunk coding is not something you want from me
no work in the morning? lol
ahhh
I only work 4 days out of the week
nice
why you raw doggin the collection
personally i think this is when code quality is at its best
wdym
private Collection<TextDisplay> holoDisplays;
occasionally I can do some awesome things while drunk
but that isn't something I rely on though lmao
like when I am high on weed, I have in the past for some people come up with some like awesome solutions to random things lmao
I haven't quite yet done that while drunk, but who knows it could happen 😛
i mean in the end the only thing that matters is what its actually instantiated as i guess
but thatd most likely be... ArrayList<>
thinks like hashmaps and arrays etc are collections
i know it just throws me off when ppl say collection
lol
?jd-j
usually you only want to use collection for a param which could be any collection
I KNOW WHAT COLLECTIONS ARE
?jdocs
?jd
no i wanted to see it for myself
?jd-s
i need ?jd-j
dont give me that ?learnjava shit 😭
for Java javadocs
those links are javadocs
that would be hard given how often they keep releasing updates
what about
pfft who needs java docs anyways
?learnjava!
Here are some links to get you started on learning Java:
- https://www.codecademy.com/learn/learn-java
- https://www.sololearn.com/learning/1068
- https://www.learnjavaonline.org/
- https://programmingbydoing.com/
- https://docs.oracle.com/javase/tutorial/java/index.html
The last one is the only official one, however some of those concepts assume that you already know a bit about programming. https://media.discordapp.net/attachments/694661573125472256/998143126373941248/6n0v4g.gif
jk
just brute force your code
ihu

oh there you go winnpixie
theres the javadoc link
alright, time to down a couple of beers really quick
to get more drunk
✝️
Drunk weed
well I don't have any weed at the moment
damn, thats a lot of implementation classes
but if I did it would be too late, you want to smoke before you get drunk
wtf is a RoleList
i have used maybe 6 of those lmao
nothing you really need to worry about
must be something more internal, references Beans
no
it has to do with setting relations
more or less more to do with DB's more then anything
most of the time you won't really have a use for it
enterprise uses it more
it was introduced in java 11 I think
or 12
one of those two
This uh... seem legit? @drowsy helm @wet breach
public void despawnHologram(Hologram hologram) {
for(UUID viewerUUIDs : hologram.viewers) {
Player viewerPlayer = Bukkit.getPlayer(viewerUUIDs);
if(viewerPlayer == null) continue;
for(TextDisplay holoDisplay : hologram.holoDisplays) {
ClientboundRemoveEntitiesPacket removePacket = new ClientboundRemoveEntitiesPacket(holoDisplay.getEntityId());
((CraftPlayer) viewerPlayer).getHandle().connection.send(removePacket);
}
}
}
i wonder if the client will shit itself if u try to remove an entity that doesnt exist in its registry
😭
not sure how you would get null
unless there was no players
oh true I suppose
why not just remove them from viewers
hmm
ClientboundAddEntityPacket spawnPacketInteraction = new ClientboundAddEntityPacket(interactID, interactUUID, hologram.getHoloLocation().getX(), currentY, hologram.getHoloLocation().getZ(), 0.5f, 0.5f, EntityType.INTERACTION, 1, new Vec3(0,0,0), 0.25);
How can I even get the entity for an entity spawned through a packet?
cause the entity only exists..on the clients..?
no it would just ignore it
or gracefully in the logs throw some kind of error
cause once the textdisplay is spawned, its gotta be referenced as an entity so I can store it in my list
you would have to keep track of it in some kind of list
you wouldn't be able to use the server methods for it
"server methods"?
i think this is what it does :p
NMS most likely?
you wouldn't be able to query the server about the entity and the relevant methods provided to obtain about it
because the server is not aware about it
so you would need to maintain a global list of entities you spawned via packets
otherwise you wouldn't be able to reference it later
however do note that in this case you can end up with duplicate UUID's since the server doesn't know about it
Basically you're making your own entity system
would this work?
public void spawnHologram(Hologram hologram) {
if(!(hologram.getHoloLines().size() > 0)) return;
double currentY = hologram.getHoloLocation().getY();
for (int curHoloLine = 0; curHoloLine < hologram.getHoloLines().size(); ++curHoloLine) {
int id = hologram.getHoloID();
UUID uuid = UUID.randomUUID();
ClientboundAddEntityPacket spawnPacket = new ClientboundAddEntityPacket(id, uuid, hologram.getHoloLocation().getX(), currentY, hologram.getHoloLocation().getZ(), 0.5f, 0.5f, TEXT_DISPLAY, 1, new Vec3(0,0,0), 0.25);
Entity spawnedEntity = Bukkit.getEntity(uuid);
hologram.holoDisplays.add((TextDisplay) spawnedEntity)
For each holo line, create a TextDisplay entity and add it to the list in the holo?
Make separate lines
why do you need separate entities for each additional line?
you cant have multiple lines of text for 1 textdisplay
plus, I need to be able to reference each line separately
seems counter intuitive if they are to take over holograms
hmm.. someone should PR an API that lets us make per-viewer/entity entities that can be accessed w normal bukkit
Like, I need to update the 2nd holo down, the honey level
and update it independently
of the others.
and in that Screen shot I assume that is 3 entities then?
Yes
also, text display entities don't need to be client side only
on the server they are not ticked
and they don't count against the entity limit either
wait that gradient is super cool. How did you do it?
hax
its 3 entities
have you not been reading?
If I spawned them as a normal entity, could they still say different things for each player? could still interact with them with metadata packets?
nope 🙂
hmmm, not entirely sure about this
as I said, haven't messed with them yet
he means the purple to blue fade
left to right
oh
thanks!
diff text for each player? probably not no
well probably could if you used an entity per player
just hide the entity for all players except that one
XD
but probably not the best way
public void setHoloData(Player player, Hologram hologram) {
for (int curHoloLine = 0; curHoloLine < hologram.getHoloLines().size(); curHoloLine++) {
PacketContainer metadata = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
List<WrappedDataValue> dataValues = List.of(
new WrappedDataValue(22, WrappedDataWatcher.Registry.getChatComponentSerializer(), CraftChatMessage.fromStringOrNull(ColorUtil.translateColorCodes(hologram.getHoloLines().get(curHoloLine)))),
new WrappedDataValue(14, WrappedDataWatcher.Registry.get(Byte.class), (byte) 3),
new WrappedDataValue(24, WrappedDataWatcher.Registry.get(Integer.class), 0),
new WrappedDataValue(26, WrappedDataWatcher.Registry.get(Byte.class), (byte) 0)
);
metadata.getIntegers().write(0, hologram.getEntityIDs().get(curHoloLine));
metadata.getDataValueCollectionModifier().write(0, dataValues);
ProtocolLibrary.getProtocolManager().sendServerPacket(player, metadata);
}
}
im doing this rn to set the data
which can be per-player
ok time to see what game to play
minecraft 💀
Adapt the metadata a bit
and that's your entity class
And maybe have a central listener
bit scattered
a pro didn't make it
But yeah this is how I use it to make a 3 second speech bubble
I'm not a pro
but you never said a pro made mine either so
others disagree
you don't get to decide when you become a pro 😛
more like my night job because I wake up at noon lmao
But I wouldn't say i'm an expert
well I kind of am
I am not an expert, I just know java really well
I made plugins like
XD
yeah he is really good
I know math too XD
but I will have to say, other then Alex he his my favorite German
Alex is germany's most qualified crackhead
Alex is my favorite for other things but still lmao
well not crackhead more like junkie idk mans weird
this really lmao
he would be more go to person about such things and opinions
because odds are he has done it
man can fly a plane, help you with your taxes, produce (dubious) music and make plugins
Also real estate
all the while taking insane amounts of things
yet fails to build a wardrobe lmao
lmao
Well he did it
it was slanted
I'm probably known as the "dude that knows it all" maybe
idk
I'm not known :p
So why wouldnt this work? @echo basalt
public void spawnHologram(Hologram hologram) {
if(!(hologram.getHoloLines().size() > 0)) return;
double currentY = hologram.getHoloLocation().getY();
for (int curHoloLine = 0; curHoloLine < hologram.getHoloLines().size(); ++curHoloLine) {
int id = hologram.getHoloID();
Entity spawnedEntity = Bukkit.getWorld(hologram.getHoloLocation().getWorld().getUID()).spawnEntity(hologram.getHoloLocation(), TEXT_DISPLAY);
hologram.holoDisplays.add((TextDisplay) spawnedEntity);
but u get paid enough for making plugins to pay the bills?
He does
usually
until he comes asking for aide from the benefactor
which is rarely though
Which is good thing because that means he is doing good 🙂
in my defense I was getting paid a couple days late
and my dad refused to pay for shit he promised
Lol, yeah that always sucks
and people owed me cash
I think that is what me and Alex are known for, is being benefactors here
It's all good now
its hell
it might
pretty sure that MikeTheShadow gave me nitro once
not always
maybe at first
but who knows they can get lucky
I gave you nitro as well
I think between us both you ended up with quite a few months of nitro
all shits n giggles till someone giggles & shits
this dude aint gonna wake up tomorrow 💀
I have insomnia I will wake up
besides I don't need to be up until 6:30pm
its only 11:58pm right now
I got no caffeine on me right now
before I get too deep into this, yall think this would work?
public void setTextDisplayData(Hologram hologram, TextDisplay textDisplay, String displayText) {
PacketContainer metadata = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
List<WrappedDataValue> dataValues = List.of(
new WrappedDataValue(22, WrappedDataWatcher.Registry.getChatComponentSerializer(), CraftChatMessage.fromStringOrNull(ColorUtil.translateColorCodes(displayText))),
new WrappedDataValue(14, WrappedDataWatcher.Registry.get(Byte.class), (byte) 3),
new WrappedDataValue(24, WrappedDataWatcher.Registry.get(Integer.class), 0),
new WrappedDataValue(26, WrappedDataWatcher.Registry.get(Byte.class), (byte) 0)
);
metadata.getIntegers().write(0, textDisplay.getEntityId());
metadata.getDataValueCollectionModifier().write(0, dataValues);
for(UUID viewerUUIDs : hologram.viewers) {
Player viewerPlayer = Bukkit.getPlayer(viewerUUIDs);
if(viewerPlayer == null) continue;
ProtocolLibrary.getProtocolManager().sendServerPacket(viewerPlayer, metadata);
}
}
public void spawnHologram(Hologram hologram) {
if(!(hologram.getHoloLines().size() > 0)) return;
double currentY = hologram.getHoloLocation().getY();
for (int curHoloLine = 0; curHoloLine < hologram.getHoloLines().size(); ++curHoloLine) {
TextDisplay textDisplay = (TextDisplay) Bukkit.getWorld(hologram.getHoloLocation().getWorld().getUID()).spawnEntity(hologram.getHoloLocation(), TEXT_DISPLAY);
setTextDisplayData(hologram, textDisplay, hologram.getHoloLines().get(curHoloLine));
hologram.holoDisplays.add((TextDisplay) textDisplay);
Spawning TextDisplays as normal entities, then setting their data with packets
but I've had days where I've chugged 7 red bulls
IDK spawning real text displays
Just make a map
?
eeew protocollib
should look into just hooking into the network yourself
you don't need protocollib for this
I think we are about to have a wall of text
public class HologramTracker {
private final Map<UUID, Hologram> holograms = new ConcurrentHashMap<>();
private int entityId = 50000;
private PacketListener listener = null;
public void addHologram(UUID id, Hologram hologram) {
this.holograms.put(id, hologram);
}
public void removeHologram(Hologram hologram) {
hologram.dispose();
this.holograms.remove(hologram.getUniqueId());
}
public Hologram getHologram(UUID hologramId) {
return this.holograms.get(hologramId);
}
public Hologram getHologram(int entityId) {
for(Hologram hologram : this.holograms.values()) {
if(hologram.getEntityId() == entityId) {
return hologram;
}
}
return null;
}
public Hologram createHologram(String text) {
UUID id = UUID.randomUUID();
Hologram hologram = new Hologram(entityId++, id, text);
addHologram(hologram);
return hologram;
}
public void registerListener(JavaPlugin plugin) {
if(this.listener != null) {
return; // Feel free to throw an exception
}
... can't bother rn
}
lol
This will be your tracker
something to ask, for one of my plugin i need to use a conditions system and handler system for actions someone has any like other plugin that is open source and does something like this?
If checks?
going to have to be more specific then that I think
yes and with values like booleans, <= < > >=, integers checks etc
This is kinda how im doing it
working on simplying my cluster||fudge|| to make papa illusion proud
Ughhhh now that I made my base Hologram object implement TextDisplay, my InfoHologram and OwnableHologram are being pains https://i.imgur.com/JEKjZza.png 🤦♂️
ever seen umbrella academy?
if so, Alex reminds me of Klaus
if you haven't seen it recommend seeing it
Is there any way around this?
public class Hologram {
private final UUID uuid;
private final int entityId;
private final Set<UUID> viewers = Sets.newConcurrentHashSet<>();
private final PacketContainer spawnPacket;
private final PacketContainer metadataPacket;
private final PacketContainer removePacket;
private WrappedChatComponent text;
public Hologram(UUID uuid, int entityId, String text) {
this.uuid = uuid;
this.entityId = entityId;
this.spawnPacket = prepareSpawnPacket();
this.metadataPacket = prepareMetadataPacket();
this.removePacket = prepareRemovePacket();
setText(text);
}
public void setText(String text) {
this.text = WrappedChatComponent.fromText(text);
// Update the metadata packet here
updatePlayers();
}
public void addViewer(Player player) {
this.viewers.add(player.getUniqueId());
sendPacket(player, spawnPacket);
sendPacket(player, metadataPacket);
}
public void removeViewer(Player player) { // Call this onPlayerQuit unless you like memo leaks
this.viewers.remove(player.getUniqueId());
sendPacket(player, removePacket);
}
public void updatePlayers() {
for(UUID viewerId : this.viewers) {
Player player = Bukkit.getPlayer(viewerId);
if(player == null) {
this.viewers.remove(viewerId); // This is a concurrent collection so CMEs wont happen
continue;
}
sendPacket(player, metadataPacket);
}
}
public void dispose() {
for(UUID viewerId : this.viewers) {
Player player = Bukkit.getPlayer(viewerId);
if(player == null) {
continue;
}
sendPacket(player, destroyPacket);
}
this.viewers.clear();
}
// internal
private void sendPacket(Player player, PacketContainer packet) {
// You can do this
}
private PacketContainer prepareSpawnPacket() {
// You can do this
}
private PacketContainer prepareMetadataPacket() {
// You can do this, just init the values
}
private PacketContainer prepareRemovePacket() {
// You can do this too
}
}
dear jesus
Pretty much all you need
omg the bro wrote code on discord
I don't really watch movies or series
Sorry I have a habit of always writing good code from memory
damn it's day outside
wait till you see me do it from my phone while at work 😛
phone code is something else
that sucks
naw its fun sometimes, impressive at times
lol that is awesome
You would choose to do all this in the holo class itself instead of inside a manager class? (setting viewers, updating, etc)
There can be many holograms
And each hologram can have many viewers
right
The tracker's function is to.. track
Not to prepare hologram-specific packets
Sure the hologram's function represents a hologram but we're don't have a separate player manager that's just a Map<UUID, Set<UUID>> for the sake of simplicity
It also makes it easier to destroy holograms
So the way you would use this, is each individual line would be its own hologram
https://i.imgur.com/wEVng1V.jpg going back to my previous screenshot, if I needed to reference a specific "line", what would be the best way of doing that with this?
Oh yeah I still forgot to implement location data in the hologram class
Anyways the idea is to just have a linkedlist of holograms
And a hardcoded offset between each line
Top line would be index 0
The way I was doing it before, id take the size of the "lines" list which contained the strings that I wanted it to say, then did 0.25xcurIndex while looping so it would put 0.25 spacing between each line
sorry for being repetitive but that's something I'm trying to search but none seems to ever publicly do and for giving more details, is for config but i just don't understand how i can do the if and if return false not to continue, i saw conditions like AdvancedEnchantments and they do many other things other than the if etcs
Something like that
Yeah so that's basically either
- a js engine
- proprietary code
I've done that at work
It's a pain
So yeah, I do still need some kind of "manager" (or tracker) class to manage spacing and storing the "links" for these
You could store the chain on your hive object
True, true
its a pain lol, im just making a plugin for fucking enchants to a client and i need to implement that
What exactly do you mean by "chain"? btw
A linkedlist
oh boy, something I havent used yet 😳
It's like an arraylist
but instead of using an array and resizing it
It uses a Node object
That looks a little like
public class Node<T> {
private final T value;
private Node next;
private Node previous;
}
And the list itself is just a
public class LinkedList<T> {
private Node<T> head;
private Node<T> tail;
private int size;
}
what the hellll
To add an element you create a new node, add it as tail's next, set tail as its previous and that node is now your new tail
what would be the advantage of that over a normal arraylist?
Add and Remove operations are smooth
And the data structure just makes more sense
Getting by the index requires iterating up to half the list (shortest path from either head or tail) and it uses more memory
But it's a true chain where each link is only aware of what other links it is connected to
RIP chat
something to ask i have a comparison operator as a string can i translate it to the same i use for coding?
like in the config is written == and inside my code i just can use it
sigh
i just think is impossible but give it a try

