#help-development
1 messages · Page 675 of 1
Tho that being said I was just referring to the algorithmic stampedlock and java’s implementation of it
is it ok to do UserManager.updateBoard(this); in a user object?
how do i add craftbukkit in 1.20.1?
do you want to use NMS classes?
If you need to access NMS classes from inside your Spigot plugin, it is a very good idea to use the so called Mojang mappings. Disclaimer: This post is obviously written for 1.18.2. If you use another version, you of course have to replace every occurance of “1.18.2” with the version you actually use. What...
yes
?nms
thanks
Might be a bit annoying if you are in an enterprise where unit tests and proper decoupling is nice to have
But else Id say rather fine
eh static
Yes. For example, in theory, if in async on an arraylist I remove a value but at the same time I get it on another thread. It's impossible to predict.
I think this is the only time I've coupled a user and usermanaged objects
Malformed \uxxxx encoding.
Arrays are different bro
this comes if i reload my dependency
usually you wanna learn how the list is used if you do it in a multithreaded environment
cuz just wrapping it with a lock is ass
or a hashmap concurent will be the same. If it does a get after removing the value but the get "request" arrives before the delete request
seems fine except that you didnt properly add the dependency nor did you add the specialsource plugin
Wdym?
I think you should learn abit about concurrency
Right now you’re asking things that could very much be answered if you knew abit more about the topic
so i shouldnt have this in my user object
I got no clue why you haven't made a getPlayer method yet
player is OfflinePlayer
ill rename it
oh ok
I'd honestly treat the player class like a data class
and have facade classes for handling logic
or well
That’s how you should have it
treat it like a wrapper :)
Still need to javadoc this
anything fancier should just be done elsewhere
You have one DTO and one that facades the DTO, that way you decouple functionality from what users can do from their actual data they contain
im moving all the methods from user to usermanager
let's imagine
we have a concurent hashmap containing 1, dog
we create thread x and thread y
on thread x we try to delete 1 (and dog)
a few ms later on thread y we try to recover the value of 1.
and the "request" from thread x arrives a few microseconds after thread y. Is this impossible?
yeah I'll go and find out
It's possible in the context of networking but not in concurrency afaik
Recover the value?
That’d only be possible with a callback
yes
I mean its possible but why
No one designs it that way
It makes more sense if you have a thread safe map where
Key=A
Value=1
and u wanna increment value of A on both thread Alpha and Beta
he's basically asking this
Map<String, Integer> map = new ConcurrentHashMap<>();
map.put("joe", 123);
Thread one = new Thread(() -> map.remove("joe")).start();
Thread two = new Thread(() -> {
int number = map.getOrDefault("joe", -1);
assert number == 123;
}).start();
In my understanding the assertion always fails
It depends on who fires first
no, but several players doing things at the same time could lead to this. but is it's very imporable
That's literally why ConcurrentHashMap exists
Delor thats where ur design discipline comes in
Yes but that’s a rather improper way of simulating RC
prevents that?
Read what I wrote earlier delor
okay
Nah ConcurrentHashMap is just thread safe
^
Why does this code cause Caused by: com.comphenix.protocol.reflect.FieldAccessException: Field index 0 is out of bounds for length 0
PacketContainer destroyPacket = new PacketContainer(PacketType.Play.Server.ENTITY_DESTROY);
WrapperPlayServerEntityDestroy destroy = new WrapperPlayServerEntityDestroy(destroyPacket);
destroy.setEntityIds(new int[]{entityId});
destory.sendPacket(onlinePlayer)
Some versions use ints, others use intlists
I'd advise against the packet wrappers for this exact reason
WrapperPlayServerEntityDestroy?`Where is that from?
I'm having trouble understanding what you mean here when you talk about x,y
And instead just writeSafely all 3 types
isn't that wrapper thingy library dead since like 8 years
and it means that regardless of how many threads u mutate the map on at the same time, the map will not freak out
nah theres a new one just not made by comphenix
Actually tell me more about what you’re trying to do
i'd just use the NMS package, then you see from the constructor which fields / types there are
I dont like using nms because of the problems is causes on different versions
it can take both an IntList or an int array
well but apparently the wrapper is causing some issues
internally it uses an intlist
the actual field is an IntList
here's a shitty simple way of doing it
so will just getIntegers().write(0, entityId) be good?
Anyway @sterile breach regardless if you’re on just ONE jvm, or multiple JVMs and Redis you wanna ensure consistency, which means avoid indeterminacy
public static PacketContainer createEntityDestroyPacket(int entityId) {
PacketContainer packet = new PacketContainer(Server.ENTITY_DESTROY);
packet.getIntegers().writeSafely(0, entityId);
packet.getIntegerArrays().writeSafely(0, new int[]{entityId});
packet.getIntLists().writeSafely(0, List.of(entityId));
return packet;
}
works across all versions
thank u
maybe use collections.singletonlist if you care about java8
no clue, I wouldn't use protocollib i nthe first place
why not
because it's more annoying than using NMS
practically every server has it
and more error prone
getIntegers()... well what if it's a short in the next version? with NMS you can tell from the constructor directly what it takes as arguments
or you can just look at the nms packet class
and then? then I do something like
if(version == 1.20) {
myPacket.getIntegers()...
} else if(version == 1.19) {
myPacket.getShorts()...
}
no
I would rather just use normal NMS modules
writeSafely exists for a reason
Yeah cuz practically most lazy plugins just use that
I’d also avoid protocollib as it compromises usability for a specific version to general practicality
how is it lazy it just saves time
But thats cuz I haven’t written multi versioned plugins in ages
if protocollib would have proper packet wrappers that worked in all versions, that'd be nice. But right now, protocollib just adds an additional layer without really adding any benefits
at least when you simply want to send packets, that is
Myea it used to
In newer versions not so much
plus i like not having to run build tools on every version i want to support
ProtocolLib:
public static PacketContainer createEntityDestroyPacket(int entityId) {
PacketContainer packet = new PacketContainer(Server.ENTITY_DESTROY);
packet.getIntegers().writeSafely(0, entityId);
packet.getIntegerArrays().writeSafely(0, new int[]{entityId});
packet.getIntLists().writeSafely(0, List.of(entityId));
return packet;
}
NMS:
ClientboundRemoveEntitiesPacket packet = new ClientboundRemoveEntitiesPacket(entityId);
idk but I like the NMS way more
doesnt nms change every version tho
that's why you use mojang maps
protocollib example supports all versions
unless the packet format changes, then your code compiles and then just throws errors at runtime
and as said, with mojang maps, the code basically doesn't change at all
ic
updating my stuff from 1.19.4 to 1.20 was just changing "1.19.4" to "1.20" in my pom
protocollib is definitely handy to listen to incoming and outgoing packets but I'd never use it just to send packets
I don't think it's useful for my current case because it seems imporable but i will do an example
Well there’s only one reason u’d use CHM
If multiple writes can happen at the same time
or Ig if u wanna have some degree of atomicity
sorry for ugly code cleaning it up in a sec
Does the exact recipe choice support items with attribute modifiers?
how to make sure that a certain item does not fall out of the inventory game when player dies bukkit api
Lol
what the actual fuck
I've changed my recipes to shaped to avoid issues, but I'm still having one. I have two recipes: one that crafts a custom sword (call it X) with attribute modifiers and another that "upgrades" that sword into another custom sword (Y). The first recipe works great, but the second one does not, and after doing some testing, I'm determined that the item meta of X when crafted is not equal to the one the game uses to create the recipe for Y since the UUIDs of the attribute modifiers are different. This makes sense since UUID's are supposed to be different to avoid collisions, but it causes my recipe for Y to always fail. Is there a way around this?
oh well yeah the UUID has to be the same - "EXACT" choice
only thing you can do is to use a normal recipe and then listen to PrepareCraftItemEvent or what's it called and change the result manually
ofc then it won't show up in the recipe book properly
Wouldn't that become performance intensive with a lot of recipes?
no
i made all my database and manager classes static instead of instance based and some of the times i try to use them it says Class cannot be resolved
What about…
no static
(:
(And when you go against it you do look like a clown more or less) [not to frighten u crackma but others]
why do people put private constructors in utility classes, like whats the issue
uhh
if someone constructs it
There's no point in constructing it and it isn't in its design
Because you show intent of that its a utility class outside the class itself
So you make it impossible to construct further reinforcing that point
This this this this
There's no guarantee that some idiot will understand that
theres no consequence to constructing it though
Its like sure u can have a manager class, but why name it with the suffix Manager, no real consequence there
You can have public fields I mean there is no real harm in that
ig, if someone cant understand that its a utility class by looking at static methods tho will they realize a private constructor is a pattern
true
The more expressive and clearer a class is just by looking at it and its properties the more maintainable and readable a system does become
What else am I supposed to end it with :c
It's a class that manages islands, what more do you want from me
javadocs are more expressive than a private constructor though
I hate javadocs
They encourage you to write long elaborate comments
Put the effort into the actual code instead
tf
javadocs are good to define rules of a function
but way too many misuse them Id assert
i understand being against comments in code but you shouldnt have to analyze the code of a method to understand how it works
Nope
at least not for public api
You should understand very intention of a method merely by reading its name
its much easier looking up an implementation detail in a javadoc than estimating the whole runtime of the method in your mind which is prone to errors
AuthorizationHandler#login
you cant pack every detail of a method into its name
Implementation detail in javadoc?
Lmao
No bud
Look at the implementation to learn the implementation
why
Yes thats true but if you ever get to where that becomes a big issue, chances are your method is the size of goliath
Because javadocs are not the primary focus, they are more prone to lying to you and to not be updated
gotta love writing 10x more boilerplate to save 5 lines everywhere
something like
@throws IllegalArgumentException If the argument isn't a valid email
``` or something can be useful
Look at java.lang.Runnable
Shits been there since java 3 or sth
And its usecase has been significantly extended
Yes but thats defining the rules of the function
yeah
And what I mean bu that is the declaring the contract of the function
Thats food
And good
api contract != implementation details
which is not implementation behaviour
so
so, like conclube said, if you want to learn the implementation, you go and read the implementation
orby, let me ask you, what color does ur ide paint ur javadoc comments in?
gray
and i need to close it via task manager
Yeh exactly its the “dont look at me grey” “forget about me grey” “oh im here but u cant see me grey” or dark green for that part
javadocs are displayed differently if its not your source file in intellij
i like writing javadocs 🥲
also its on the method when u hover over it
The colors used by ides are made to make the comments and javadoc a secondary focus, because when u look at code u wanna primarily (probably) read the code and not the comments
Yea they are orby, but usually u only get the first lines or sth no?
its probably because as a developer you dont want the javadocs you wrote for other people in your face
I mean I have my javadoc and comment colors set to bright orange
Well if I see a comment in a code it better be telling me something that wasn’t properly possible to communicate with through the code itself
dont look at my code lmao
I shall not then :>
actually changed by jdk 19 👀
how about this
good
Yeah sure
Shii my bad
Tho alex personally I try to make my comments talk about the code they’re commented over/under, not some other code in some other module
comments shouldnt be that long jesus
wdym? it's a JsonSerializer / JsonDeserializer for gson
That was general criticism
Not particularly thrown at u
Yeah orby what I was saying are ofc just conventions, or well I’d say they are but knowing when to avoid those are just as crucial
Sometimes you have to talk about other modules in a comment, or talk about implementation, given its justifiability
yeah ig
javadocs prob arent needed most of the time
unless its an interface
like bukkit api
Myea
well javadocs makes a promise, the implementation doesn't
if javadocs tell me something returns a mutable list, I know it's a mutable list. If I only look at the implementation and see there that the list is mutable, well - that could change in the next version
true
how would one detect when someone right/left clicks a client side block aka packet
I think java did a horrible design mistake regarding this mutability design speaking of which, they just violate liskov’s substitution principle straight of making immutable lists a private implementation and then just putting that into javadocs instead, well at least we’re getting sequenced collections
Hello !
I made a minecraft plugin in 1.16.5
The problem is that when I want to apply color to message in my config.yml, the default color remains (white):
Main : https://paste.helpch.at/daweteyuti.scss
FlySpeed : https://paste.helpch.at/uyohulaweb.typescript
WalkSpeed : https://paste.helpch.at/erataxudug.kotlin
Color : https://paste.helpch.at/netigadiva.typescript
Config.yml : https://paste.helpch.at/cewukukani.yaml
console doesnt have spigot colors
Yes I am talking about the messages in the config.yml
are you sure the config is being loaded in right (the messages loaded inside ofthe code match with the message in the config)
Yes as u can see
print out the return value of getConfig().saveToString(), does it include the color codes?
I create a value with these functions and I print the result?
just do System.out.println(getConfig().saveToString()) in onEnable
Ok one sec
as expected, your config does not include any color codes
is it possible that only your included config.yml includes the color codes but the actual saved config.yml does not?
I did not understand, the color codes are present in the config.yml I use a Color class to translate and in my FlySpeed class you can see how I use all that to use & for the colors
Hey guys I need advice on directional object. So I disabled vanilla crop growth and have my own system and when a pumpkin or melon grows I manually convert a PUMPKIN_STEM into a ATTATCHED_PUMPKIN_STEM. The issue is I need to set the direction data on the block with Directional#setFacingDirection(face); but BlockData#setBlockData() does NOT take a Directional object. So now Im stuck.
This is a snippet of the code. https://pastecode.io/s/3npr0pj5 I tried playing with casting but it doesn't seemt work?
in which config.yml?
I know setting the type to ATTATCHED automatically connects it to the fruit but I later check the direction of the stem and just setting the type seems to make it not an instance of Directional which is weird
the one included in your .jar, or the one in your plugin's data folder?
Config.yml : https://paste.helpch.at/cewukukani.yaml
Pass it the directional instance anyway
It doesnt take it, i can't its a error
on BlockData? sadly no
Only on Directional
but .setBlockData doesnt take Directional whatsoever so
I also tried casting the directional back to BlockData to pass it in
But unfortunately that makes it not an instanceof directional which I need
My config.yml are in my file of my plugin -> but included in jar (u can use my code to see if u want)
Are you using the right one, is a subclass of BlockData which means you can pass it to setBlockData
You are likley using the other one
org.bukkit.material.Directional != org.bukkit.block.data.Directional
you have to use the block.data.Directional import
Bukkit troll :,)
rip
For my problem I rechecked but yet the code seems right to me I don't see where it's wrong
I had made a slightly simpler plugin and the code is identical in terms of managing the config / colors è_é
i don't really understand. it looks like you have an old config.yml in the plugin's folder that does not include color codes
and the color codes are only inside your default config in the .jar
Wait I think I understood what you were telling me I will try something thank you
[00:19:05] [Server thread/INFO]: player_only: '&cCette commande doit être exécutée par un joueur !'
Thanks i think its work i will try IG
Its work thanks !
np
Hello, in BlockPistonExtendEvent, e.getBlocks contain blocks before being pushed or after ? (mushroom blocks after being updated or before ?)
I think it's before, because it's will
thanks the doc
the event is also cancellable, so it must be before moving
this is smart
it's perfect then if it's before
if I change a block's data, it will changes after pushing?
i guess so
okay
just setting the mushroom block to his state before pushing
will work on both retract and extend events
almost perfect```java
@EventHandler
public void onMushroomBlockPush(BlockPistonExtendEvent e) {
for(Block block : e.getBlocks()) cancelMushroomStateChange(block);
}
public void cancelMushroomStateChange(Block mushroom){
if(!CUSTOM_BLOCKS.contains(mushroom.getType())) return;
MultipleFacing facing = (MultipleFacing) mushroom.getBlockData();
mushroom.setBlockData(facing, false);
}```
filtering e.getBlocks() will be better
not working
maybe I need to delay
3 ticks
lol
just need to get piston relative and add 1 🤓
Hey how do I "reload" a player? Something I am doing only works if I teleport a player into another world and then teleport them back as that reloads the player for everyone. How do I have the same effect without teleporting them?
what are you doing ?
that reload the player
What?
I am doing something with armorstands and it needs to reload the player otherwise anyone else wont see it
well, I don't see what can do that
well nick plugins have to
but also this thing im doing apparently needs it as it only works if i reload the player in a bad way
what are you doing with armor stand?
exactly
hum
well idk sorry
I could help you with mushroom blocks actually but not with armorstands :/
you'd be surprised by the amount of events that happen after the action takes place and (sometimes poorly) attempt to revert it if it's cancelled
Yeah ik but shouldnt be the case here i guess
Neither
== the type
Not the itemstack
getHelmet().getType() == Material.WHATEVER
Process 'command 'C:\Program Files\Java\jdk1.8.0_202\bin\java.exe'' finished with non-zero exit value 1
i already changed enviroment vars, project sdk
what else do i do
that wont work how you want
please use proper method names and early returns and also why are you using the wrapper type instead of the primitive for the health double
if they dont have a the helmet, they next 3 ifs wont run
when they could have all but a helmet
why doesnt just run everything in 1 if statement
Thats even worse
i didnt understand the goal
well idk
hurt them by 4 hearts if they do NOT have full netherite, but don't hurt them when they move?
i dont get it
also note that all of the equipment methods are nullable so you can't just do getType() without checking if it's null
then please refactor your code to be more readable
I'd have a container class that has a boolean set to true or false if they do an e event thar gives then full netherite on equip... and then check the boolean on move.
Checking their head, shoulders knees and toes on move is a heft waste of thread lol
@EventHandler
public void onMove(PlayerMoveEvent event) {
if(!hasFullNetherite(event.getPlayer())) {
event.getPlayer().setMaxHealth(event.getPlayer().getMaxHealth() - 8);
}
}
private static final Map<EquipmentSlot, Material> ARMOR_SLOTS = new HashMap<EquipmentSlot, Material>() {
{
put(EquipmentSlot.HEAD, Material.NETHERITE_HELMET);
put(EquipmentSlot.CHEST, Material.NETHERITE_CHESTPLATE);
put(EquipmentSlot.LEGS, Material.NETHERITE_LEGGINGS);
put(EquipmentSlot.FEET, Material.NETHERITE_BOOTS);
}
};
private static boolean hasFullNetherite(Player player) {
for(Map.Entry<EquipmentSlot, Material> entry : ARMOR_SLOTS.entrySet()) {
EquipmentSlot slot = entry.getKey();
Material requiredMaterial = entry.getValue();
ItemStack equippedItem = player.getEquipment().getItem(slot);
if(equippedItem == null) return false; // No item, this cannot be netherite
Material actualItem = equippedItem.getType();
if(actualItem != requiredMaterial) return false; // This is not the required item
}
return true;
}
hello darkness my old friend
this is how I'd check for full netherite items
alternatively one could ofc hard code it
but I like this more
here's the ArmorEquipEvent https://github.com/JEFF-Media-GbR/ArmorEquipEvent
The sacred jedi texts
Just to be lazy I'd of stored just the slots as a set and then checked to see if those slots on the player had NETHERITE in the material string
ill put a netherite axe on my chest
was about to say
I’ll put a netherite block on my head with /hat
also it's in the move event so I'd rather use something that doesn't require string comparing all the time
I mean that's utterly fair lol
Just don’t get hit 5head
The solution is more interfaces
then add more
What's the dea with implementing an interface into an abstract, and then impmenting a child of the interface into a concrete of the abstract? Is that legal? Lol
I
Don't wanna get arrested by the Oracle police
try
It can be done, I'm just curious if it's the right play.
E.g making an block log abstract and then the concretes implementing child's of it like blockchange
Feels sorta dirty :S
Probably the heaviest plugin I've ever done and wanted folks takes
I know I know, its not quite -8 health on not full netherite. But still
Anyone know how I can create a BlockState from a material in 1.19.2 mojang mappings?
BLockStates are API, has nothing to do with mojang maps
Material#createBlockData
oh wait, blockstates
erm wait
cant you get it from data
Material.DIRT.createBlockData().createBlockState()
but I think this was added in 1.20.1
Yeah i need net.minecraft.world.level.block.state.BlockState in 1.19.2 from a Material
june
theres probably some Craft class to convert it
but idk if the state exists without a block
what exactly do you need this for?
So, I'm trying to rewrite the NMS Chunk method from https://www.spigotmc.org/threads/methods-for-changing-a-massive-amount-of-blocks-up-to-14m-blocks-s.395868/ in 1.19.2 mojang mappings
I need to get a BlockState from a material where the block doesn't exist
does that not want data?
This is what it wants BlockState net.minecraft.world.level.chunk.LevelChunk.setBlockState(BlockPos blockposition, BlockState iblockdata, boolean flag)
Unless I have the wrong method, but that's the only thing I could find
Material bukkitMaterial = Material.DIRT; // only works for Materials where isBlock() returns true
net.minecraft.world.level.block.state.BlockState nmsBlockState = CraftMagicNumbers.getBlock(bukkitMaterial).defaultBlockState();
Thanks
np
btw is there a reason why you're on 1.19.2 instead of 1.19.4 or 1.20.1? o0
1.19.2 is a weird version
That's just the version I started this project on, I'll upgrade it after I finish the main features
oh ok. just wondered because I saw many people using specifically 1.19.2 in the last days
id recommened updating before you do a load of nms
tbh, updating with mojang maps is as easy as changing one property in your pom
well yeah, its not too hard to update just annoying
Well I'm going to want it to work with 1.19 anyways so the order doesn't really matter
1.19.2 nms wont work on 1.19.3 or 1.19.4
btw does gradle support using sth like "properties" in the versions of dependencies (I mean, ofc it does) but does IntelliJ also understand that properly?
Yeah ik
yeah
oki
is there any tutorial on how to write a simple gradle plugin? I wanna write a plugin to run the specialsource .jar
I've already read taht but I don't get it, am I really supposed to write my plugin inside the build file using groovy?
no you can do it in java classes
but then why do they say "You can include the source for the plugin directly in the build script"
i don't really understand that
it's the part at "Packaging a plugin -> Build script"
bc you arent required to make it a seperate project
kotliny syntax
you can make a gradle plugin through intellij project wizard and go from there
either this tutorial is completely incomplete, or I am stupid - they don't mention anything about how to do it in java, do they?
I also don't get why they keep referring to some obscure "buildSrc" directory
what's that supposed to be
no clue
typical gradle docs ugh
create a gradle plugin project and see what you have
yeah well that's what I#m trying to do
but the docs don't really give any useful info
I'll call it SpecialSauce
Lost in the sauce
what the
case
yeah I know
but why
why does that have to be the same
and if it has to be the same, why do I have two available input fields
if it has to be the same anyway, there should be only one input field
you would think case but no
like literally, why can I enter both a name and an artifactid if both must be the same
this is like asking "do you want fries with that" and when I say "yes", they say "sorry we're out of fries"
yeah bro then don't ask
lol
“Do you want fries with that”
“Yes”
“Well too bad motherfucker”
am I supposed to set my groupid etc in settings.gradle or in the publication section in build.gradle?
I can't find anything about that in the docs
IJ's default gradle template uses a weird mixture where the project name is defined in settings.gradle while groupid and version are defined in the build file as normal property
Name is always in settings
Hey
I followed the wiki on the SpigotMC wiki site to use the BungeeCord configuration System but somehow my config doesn't load. (https://www.spigotmc.org/wiki/using-the-bungee-configuration-system/ )
The config file is getting created with the values inside but somehow when I try to access the values by using configuration.getString("") it does return an empty String.
Am I doing anything wrong by loading/accessing the config?
try {
Configuration configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(new File(this.getDataFolder(), "config.yml"));
ProxyServer.getInstance().getLogger().info(configuration.getString("database.host"));
} catch (IOException e) {
throw new RuntimeException(e);
}
are you sure you're properly creating the file?
yeah like I said the file exists
IIRC, bungee doesnt have the concept of paths
you'll have to do sth like getConfigurationSection("database").getString("host")
alright I will try it like this now
ProxyServer.getInstance().getLogger().info(configuration.getSection("database").getString("host")
It still prints out an empty String
loop over the keys and see what it prints out
configuration.getKeys().stream().forEach(System.out::println);
[16.08 03:19:35.380] INFORMATION: [Proxy-1] [03:19:34 INFO]: database.host
[16.08 03:19:35.380] INFORMATION: [Proxy-1] [03:19:34 INFO]: database.port
[16.08 03:19:35.380] INFORMATION: [Proxy-1] [03:19:34 INFO]: database.database
[16.08 03:19:35.380] INFORMATION: [Proxy-1] [03:19:34 INFO]: database.user
[16.08 03:19:35.380] INFORMATION: [Proxy-1] [03:19:34 INFO]: database.password
well atleast it shows the keys
## Database
database.host: "aa"
database.port: 3306
database.database: "aa"
database.user: "aa"
database.password: "aa"
I removed some values cuz I don't wanna leak my db ip
yeah I think the problem is that you're using dots in the key names. bungeecord tries to separate that into getSection("database").getString("host")
but there isn't actually a section called database
try it like this
database:
host: localhost
port: 3306
etc: blabla
see if that works
Okay
your code can stay the same, just change the yaml
[16.08 03:24:24.861] INFORMATION: [Proxy-1] [03:24:24 INFO]: localhost
It did work now
Thank you so much 🙏
takes like 2ms to fix
also intellij is somewhat at fault as it likes to indent
and plugins that indent on top cause issues
(Example: copilot)
I want to make some more PRs to spigot but the workflow is hellishly slow... Use buildtools to get latest, open in intellij, create and run task to apply the patches (and configure the task so it will actually run with the buildtools path), make changes, create and run task to create patches (configure the task so it will actually run with the buildtools path), test, then go back to applying patches if things don't work.
When all is done, creating the patches for me makes all these whitespace changes so I basically have to manually copy-paste the patches I need for the PR, then discard all changes, then paste my changes...
Surely I am missing something (probably a lot). Does anybody have a video or anything that might help me improve the workflow?
I'm looking to improve the SculkCatalyst API if that makes anybody want to lend a hand 😛
^ that workflow is livable for my PRs that were like <10 lines of code, but this one will require a bit more
yeah that is indeed very annoying.
howeeeever, opening the buildtools directory isn't the correct way in the first place
?contribute
You can find information about contributing to Spigot at the following links:
https://www.spigotmc.org/wiki/cla/
https://www.spigotmc.org/wiki/guide-contributing-to-spigot/
https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse/README.md
https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse/CONTRIBUTING.md
second link
and for the whitespace and stuff, don't use auto-formatting in your IDE (at least not if you haven't loaded the codestyle file) and use the included maven profile for the codestyle
other than that, if somebody knows a better workflow, I'd also be interested in getting pinged about that lol
Well when I tried directly from the jira repo, I had a really hard time building a .jar to run
Like I had missing dependencies
did you run applyPatches with the path to your buidltools "decompile" directory?
I don't quite remember 😅
Let me pull it up
i have to add, I never actually did any changes to spigot itself, only bukkit and craftbukkit
well yeah for this I would need to modify bukkit, craftbukkit, and nms
in 99% of cases that's all you'll need though
yeah NMS is part of craftbukkit's patches
The patches probably should be done from spigot repo
this reminds me, I have to change my jira email address
and craftbukkit and bukkit are 2 separate repos, so how can I add an event in bukkit, call it in craftbukkit, then test the .jar result?
Because from jira I have a bukkit and a craftbukkit repo
2 different ones
Do it from spigot repo
Spigot literally clones cb and bukkit after they are done and has its own patches
- you add it to bukkit, then you
mvn installit - you add it to craftbukkit, then you
mvn packageit and use the resulting .jar
- make changes
- maven install bukkit
- maven package cb
So it should be done from there otherwise you risk spigot changing something unexpectedly
Don’t make changes in the spigot repo
Then you end up with the spigot patches in your commits
You can exclude them from commits
while we're in this topic
I guess you could just not apply the spigot patches
I suggest making an event for when a command is forcibly run through dispatchCommand 🙏
But that’s beside the point
anyone know how to change the output directory for (and ONLY for) the final .jar built by gradle?
great question
I've been using gradle for the past like 6-7 years and I still don't know any of it
I'm too small brain for this... so lets say I am starting fresh and have fresh forks in my hub.spigotmc, I should be:
- Clone Bukkit to a folder and open in Intellij
- Clone CraftBukkit to a folder and open in Intellij
- ...? add something or other
destinationDurectory = file()
wait a gotchu one sec
Then do this @shy finch
or if you use gradle.kts
tasks.named<ShadowJar>("shadowJar") {
destinationDirectory.set(file("../some_folder"))
That requires shadow
I'm not using shadowJar
I tend to use shadowJar even when I don't need really need to... less to learn
This probably wouldnt be hard
It isn't
It's just that I've had to use Unsafe to override the command map with a proxied one
Like one or two lines lol
because there's no event and everything is locked down
private final field with a protected constructor or whatever
Well there is but not for the method specifically because it wasnt originally intended to stop a plugin from doing something
private final fields don’t require unsafe
p sure this was for logging purposes
doesn't need to be cancellable
But literally any plugin that forces the console to do something won't fire console command events
It should fire the servercommand event
it doesn't
Because that event fires when reading console input
instead of on the command map
Because the command is suppose to be ran as that command sender. Must of been an oversight
I would probably make a jira ticket for it
cant bother
Give me an event name and ill pr it this or next week
Isnt that server
Dispatch event and fix servercommand event not firing
typical gradle moment
The last one should be classed as an uncaught bug
anyways it's like 3am and I'm really not feeling like working
even though I gotta deliver a project tonight
lmfao thanks bukkit
good luck, chances are high that everything breaks
that's also how I learnt to handle InterruptExc
i never really understood it
thanks aikar!
does anyone know what this means?
FAILURE: Build failed with an exception.
* What went wrong:
A problem occurred configuring root project 'specialauce'.
> Failed to notify project evaluation listener.
> org.gradle.api.tasks.bundling.Jar.setClassifier(Ljava/lang/String;)V
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.
BUILD FAILED in 422ms
What is specialauce?
that is my project
He’s lost in the sauce
Run with --scan to get full insights.
same thing
I wonder how many lines of code luckperms has
And I also wonder if there's any OS plugin that has crossed the 100k limit yet
probably some noob plugin that creates a few items using the same 1000 lines duplicated a hundred times
I mean something qualit
PS C:\Users\colli\Desktop\Code\craftbukkit> mvn install bukkit
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------< org.bukkit:craftbukkit >-----------------------
[INFO] Building CraftBukkit 1.20.1-R0.1-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.073 s
[INFO] Finished at: 2023-08-15T22:16:27-04:00
[INFO] ------------------------------------------------------------------------
[ERROR] Unknown lifecycle phase "bukkit". You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Availab
le lifecycle phases are: pre-clean, clean, post-clean, validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, proces
s-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, in
stall, deploy, pre-site, site, post-site, site-deploy. -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/LifecyclePhaseNotFoundException
PS C:\Users\colli\Desktop\Code\craftbukkit>
not sure where I am supposed to be running mvn install bukkit
I think the largest project I have done is ~42K lines. Even then I know for a fact that some of it could be reduced down.
WeaponMechanics is sitting at about 65k lines of code
biggest I've done is about 45k
we rewrote it in minestom and it's like 20k
Just run „mvn install“
Without bukkit
it really wants bukkit:
(result of running mvn install)
Weird name, id expect the dev profile to NOT run code checks
Run „mvn install“ on the bukkit project
After that you run „mvn package“ on craftbukkit
I assume that is after I run applyPatches
on craftbukkit
because aint no chance in hell this is compiling
yes sure, as explained in the second ?contribute link
alright thanks, appreciate it. This definitely improves the workflow
- you
mvn installthe bukkit project - then you open craftbukkit and run
applypatches.shwith the decompile directory from buildtools as parameter - now craftbukkit should compile just fine using
mvn package
how you do changes to spigot though, I have no clue. but you shouldn't really need that
and from there create the server... now don't hate me, but if I create a test plugin for this server, is the fastest way to depend on custom server to add a system gradle lib?
Or does everybody have a fancier way
Such a small number
you can do mvn install on craftbukkit instead of mvn package - then you can depend on the craftbukkit dependency normally (ofc you must specify mavenLocal() as repo)
it's important that you get rid of the normal spigot repository in your plugin's build file - otherwise it will get overwritten if a new snapshot is available in the repo
oh wait, craftbukkit is not available in any repo
oh, that makes more sense... I guess I wouldn't actually nee to run mvn install on craftbukkit though since why would I need the plugin to depend on craft bukkit?
yeah you usually don't need that
you should be able to just depend on bukkit, I was a bit stupid
but be sure to remove the spigot repo
in your plugin
otherwise it might update to the latest snapshot and use that instead of your own custom version
I think I am going to make a video on this at some point... mostly for my forgetful ass 😆
i should probably turn that into a blog post
epic collab time
I have a habit of being upset at overly complicated or outdated tutorials and then write a blog post once I figured it out myself lol
we can just edit the spigot wiki right?
the wiki is kinda weird
I'm still waiting for someone to rewrite the buildtools article
(or to get the buildtools GUI merged)
the buildtools article is a horrible mess
and it's annoying to edit the wiki because it uses BBcode instead of normal wiki formatting D:
i should ask md to install a mediawiki
markdown purist over here
markdown is fine too but I'm used to wikipedia
That's what I'm waiting for. I was gonna write a bit for it.
tbh, I don't think anyone will miss the current article, feel free to edit it already lol
unfortunately very few people contributed to the discussion about the buildtools article that I started
basically only 2 people and one was complaining about not being able to download buildtools lmao
We didn’t even get much contribution on the experimental discussion thread
Sadge times
Yea, I gave my thoughts on it. Was hoping for some feedback on it.
Could also just split up the one page like this if people don't want to maintain multiple pages.
- BuildTools (GUI)
- BuildTools (CLI)
experimental discussion thread?
About the changes in the experimental branch
I don't think that's needed. the article should imho look like this:
more is literally not needed
what version of jdbc has spigot been running?
That's where I kinda disagree. Going to a wiki page and it only containing like 8 lines of text would give off the impression of a poor wiki article.
I'm not saying to write an entire manual for BuildTools, but keep the simplicity of your screenshot while still providing useful information.
Those errors that are currently listed on the wiki are something that should stay. The links to the Discord/IRC should be made more noticeable, the general description could be updated and the removal of the same command but different version would all be meaningful changes.
which other information would be needed?
all those "currently listed errors" are things that only happened 7 years ago
and ofc the article will be longer than 8 lines if every command line option will be explained
People still run into them for some reason. Not even a week ago, someone ran into this issue.
yeah well okay, if this really happened to someone days ago, then it should stay - at the very bottom in a section called "Troubleshooting", but not in the middle of the article
(imho)
Yea and that makes sense.
right now the article is like 91825 lines where 99% of people would only need to read 0.1%, but the important 0.1% are hidden somewhere in the middle
and that's why people rather use paper because they can just download it
That's it. Time to rewrite everything from scratch.
most paper users are incapable of reading more than 30 lines of text and hence they are so overly confused by spigot, they just cannot run buildtools. that's why I think that the article should start with a huge DOWNLOAD BUILDTOOLS HERE link, and then in the text below, ofc we can explain common issues and command-line options etc, but we definitely need the huge "DOWNLOAD IT HERE" banner at the top
wiki page needs a big "Download SPIGOT" button that does everything an idiot needs 🙂
I want to know how they do the buttons on the main wiki page.
oh yeah there must be a Download button
we should have a spigot.jar downloadable that only contains buildtools, then runs itself and builds latest spigot, and then replaces itself with the finished .jar
so people think they actually downloaded spigot
You know, you might be onto something since a lot of people try to run the BuildTools jar thinking it's spigot. 🤔
p sure that's what paper does
or just a RUNME.jar
no clue how paper works
but I'm pretty sure that spigot went down to 20% of users not because paper is "so much faster" but because they just offer a "Download here" button, while spigot doesnt
yeah. we must talk to md_5 about this
we need to keep buildtoosl and all that for us devs, but there needs to be a simple one button automated system for end users
although having BT gui merged is already a huge step into the right direction
It would also help if the Jenkins page, (which you are redirected to if you click the download button on the navbar) mentioned in all caps.
THIS IS NOT A PRECOMPILED SPIGOT JAR
Every opportunity you have to warn the user, you should take it.
okay guys I got an idea
end users doesn;t even want to go to jenkins. they want an easy to find "Download" button
Well that's where it takes you.
It just redirects you to Jenkins
All because of the legal bullshit
Honestly even I've never used that menu. Spigot site is very unintuitive
I alwasy search download buildtools if I need the link
Spigot-Server.jar - a GUI, similar to the current buildtools gui
- General (you can select the version) and change server.properties stuff there like port, motd
- a huge START button - it checks if there's already a spigot-1.X.X.jar in the current folder - if not, it runs buildtools in the background
- a console GUI, similar to the already existing one, but basically... all in one. A whole GUI. so you just download Spigot-GUI.jar, run it, select version, and that's it
That sounds a lot like those Bukkit GUIs that existed back in the day.
i haven't seen any, but this one could be official
I'd definitely vote for an idiot proof download button
it doesnt even have to have many features, all it must offer is to be able to select a version and have a start button and be linked as "Download" on the homepage
yeah exactly
Hold up, here's a thought.
even buildtools gui isn't idiot proof enough
Can't we just make a
launcher with a builtin version config
that just runs buildtools
in a cache folder
that's what I suggested
Nvm, it wouldn't be compiled on the user's computer.
Legit just make it fetch buildtools from spigot's jenkins
put it in a cache folder
run it
yep that's basically what I had in mind
maybe with an additional tiny config GUI for port, motd, max players, etc
a button to open the plugins folder in explorer
that's server.properties
I don't even mean a gui
yeah a button would be enough
You are straight up describing the Bukkit GUIs.
Just a standalone jar that runs automagically
Give me a sec, I'll see if I still have a screenshot or the original programs.
with maybe a tiny gui with a countdown and a server version
We definitely need something super simple that an idiot can use. When the forks hard fork we are going to have issues.
and a headless mode
ok shadow next project. but this time pls lemme do a gridbag layout 😄
git like 6 projects in my queue atm
yeah like the current buildtools gui
if you do java -jar ... it runs in CLI mode, if you just double click it, it opens theGUI
I got no clue why I'm in the contributors list I just asked to be on it
send it to me
oh
Shadow
send the exe
I'm on win rn
Which one you want?
nothing happens 🥲
Could try the other one.
Could also try running it in compat mode. (If that's even still a thing)
I have another idea
I'm still gonna try wine
Buildtools gui could generate a tiny bat and sh file to start spigot
Called Start-Spigot-Windows.bat and Start-Spigot-Linux.sh
It could also use javafinder to get the correct java
Separate PR for that ideally
Does anyone know what can cause an out of bounds exception when using net.minecraft.world.level.chunk.LevelChunk.setBlockState? (mojang mapping)
Under a new flag that's off by default too
Probably a call to Chunk#setBlock() either < (0, 0) or > (15, 15)
Without plugin intervention, highly unlikely to occur
yeah sure, once the GUI gets merged
Oh it says in the stacktrace the exception is from net.minecraft.world.level.chunk.IChunkAccess.b
I don't even remember how this worked on windows anymore. 😢
paste the whole stacktrace
shadow have you ever used XAMPP?
?paste
I think once, but it confused the hell out of me.
placeBlocksByChunk: https://paste.md-5.net/juvuzakusa.cpp
the Spigot Bootstrapper could be a bit like this.
1 button to start spigot (or build it if not found yet)
1 button to edit spigot.yml
1 button to edit server.properties
(etc etc)
1 button to open plugins folder
yeah that's it
and at the bottom, the server logs including prompt for commands
and ofc a schnitzel should show with a 1/100 chance
very important
anybody knows why this isn't working? It cannot find "SpecialSaucePlugin" which is not surprising, but that's exactly how the baeldung tutorial suggested to do it :/ https://www.baeldung.com/gradle-create-plugin
Can somebody explain to me the difference between the following two things?
Option one, works fine
buildscript {
repositories {
mavenLocal() // plugin published to maven local
}
dependencies {
classpath 'com.jeff-media:specialsauce:1.0-SNAPSHOT'
}
}
plugins {
id 'java'
}
apply plugin: 'com.jeff-media.specialsauce'
Option two, does not work, see error below
buildscript {
repositories {
mavenLocal() // plugin published to maven local
}
dependencies {
classpath 'com.jeff-media:specialsauce:1.0-SNAPSHOT'
}
}
plugins {
id 'java'
id 'com.jeff-media.specialsauce' version '1.0-SNAPSHOT'
}
Error:
Build file 'C:\Users\mfnal\IdeaProjects\testproject\build.gradle' line: 12
Plugin [id: 'com.jeff-media.specialsauce', version: '1.0-SNAPSHOT'] was not found in any of the following sources:
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.
BUILD FAILED in 959ms
you define the plugins repository in the settings.gradle(.kts), not in the main build script, uh something like
pluginManagement {
repositories {
gradlePluginPortal()
mavenLocal()
}
}
and get rid of the whole buildsxript configuration
but then why does "apply plugin" work? ALso neither the gradle docs, nor the above mentioned baeldung tutorial mention anything about that
https://docs.gradle.org/current/userguide/custom_plugins.html#sec:custom_plugins_standalone_project the gradle docs itselfs don't mention ANY repository having to be specified, not even maven local
I am very confused
uhm yes it does?
on which page are you now?
that same page you linked
I don't see any "using your plugin in another project" part
okay maybe more then 7 lines lmao but further down
idk I just scrolled down
lemme
oh there. yeah well but I have published it to maven local already
and also added it to the normal dependency as classpath dependency
I wonder what the difference is between plugins { } and apply plugin:
why does one work without having to specify a separate pluginManagement repository, while apply plugins does not require that
erm other way around
the buildscript and apply plugin thing are kinda being phased out
are you sure? I'm using 8.2.1 (latest) and not getting any warnings
yeah but they encourage/prefer the other way for new stuffs
I still don't understand why one (plugins { } but not apply plugin) requires me to declare a plugin repository - how does it work for other plugins? e.g. why do I not need to declare a repository for lombok or the java plugin?
there's an implicit repository, the gradle plugins portal
wtf
they add their website automatically but not mavenLocal()?
that is... funny
but ok, thanks. I am still confused about why it's so different
adding maving local sounds like a really bad idea
end up accidentally using some modified local version without realizing
how else would I test my own plugin before publishing it anywhere
well you can add it yourself for testing
that's what snapshot repos are for, aren't they? :p
oh I mean adding it by default, sorry
not just adding it whenever. adding it is useful for testing like you said
but adding maven local implicitly I don't think is good
my plugin is already using a snapshot version, and the gradle docs don't mention anything about using the gradlePluginPortal by default
anyway, thanks for your answers, I am still confused about how I would have been supposed to find this out myself
e.g. the difference between apply plugins and plugins { } automatically using the plugin portal but not maven local - where is that documented?
idk I just scrolled down lol
I have now read the full page and didn't find anything about it
that page also discusses the difference you were looking for
between the plugins {} block and the legacy method
thanks! I have tried to find the difference but somehow all it says is that "apply plugins" is "legacy"
oh well maybe it doesn't describe the functional difference, but it does say that it shouldn't be used
idek what the functional difference is, I have never used buildscript and I only ever see it on things using much older gradle versions
yeah me neither, this was the first time today that I really had to use it (I've only seen it on 10 year old scripts) lol
I still find it highly weird that mavenCentral() has to explicitly be added as repository but on the other hand, gradle has no problem in using an arbitrary website for plugins
that makes little sense to me
but mavenLocal() is not trustworthy? idk ugh
mavenLocal() is the only thing where oneself has control over
idk if its because its not trustworthy, I think it can just lead to more unexpected things, like using modified local versions of stuff when you totally don't wnat to
mavenLocal() should always be the first place to lookat imho
yeah well if one doesn't want modified versions in their maven local, one shouldn't install stuff there
it's literally the only repository where one has full control over
but maybe I installed it there 2 months ago
I don't dig around in there and delete stuff
me neiter but I also don't install random stuff there 😄
I want to know that what I clone from a repo will use exactly the right things
mavenLocal doesn't adhere to that
but you don't even know from wich repository you got something
if you have 5 repos declared in your repositories { } section, you can't even know where dependency XY came from
yeah but usually you don't do that
same as you usually don't overwrite stuff in maven local with random things
what is MM
not merging PRs
😭
Machine 
I just am too lazy to spell out MachineMaker and I am already back off to studying so now I am poking him to merge A PR
no clue what MachineMaker is tbh

rip

Okay so tl;dr i have to declare mavenLocal in pluginRepositories to use plugins using plugins {} from maven local, right?
correct
Thx!
in pluginManagement.repositories
merci 
Erm yeah thats what i meant
I am used to maven lol
Oh since so many gradle ppl are here rn
Is there a good comprehensive book about gradle?
Like, an actual book that somebody can recommend
the docs are amaze...... a big maze, lol
Haha yeah
I think its hard to write a book that wouldn't be outdated dramatically in a year
True
gradle's rate of change is very very quick, its one of the bigger issues people have I think
yeah that is indeed very annoying
you can still just use the older version, nothing requiring you to update really
but then my ~/.gradle folder is filled with so many versions
who has the disk space
I learnt java completely from books, I haven't studied anything remotely similar to CS or stuff, but I managed to learn java and maven and stuff fine with normal books, kinda annoying that it's not possible with gradle lol
everytime I look for docs they are outdated or in a very weird order (e.g. I have a question at step 3 and it gets answered in step 27 of the docs)
so I always have to ask people who already know the answer and then I wonder "how did they manage to learn this without asking someone who already knew this"
exhibit A: what you just experienced lol
gradle is a rabbit hole and I sometimes think it's not possible to understand "most of it", you either have to know everything or you know nothing
also stackoverflow questions from a decade ago with a valid answer for gradle 2 or whatever that still show up at the top of search results
that's my biggest problem with SO in general, eck
the IntelliJ docs are equally weird btw
(I'm talking about writing IJ plugins)
yeah anyway, thank you all, I'm a big step closer to my goal of writing a very simple gradle plugin now lol
and it's only 6 am
true, I woke up 30 mins ago
oh btw I have another question about gradle.
in maven, groupId, artifactId and version are essential parts of a pom. in gradle, it seems like only the "artifactId" is essential while groupId and version just seem to be "normal properties" that aren't actually needed to define.
this surprises me especially since subprojects (which seem to be like maven modules) inherit the parent stuff mostly, but in gradle the artifact is declared in the "global" gradle.settings file, which makes little sense to me because usually, groupId and version stay the same in "child modules/projects" and only the artifactId changes
I wonder what the reason is to separate the groupId/version from the artifactId into two different files
maybe I should have studied CS instead of law
Good afternoon! Are there any programmers who can take my order for 5000₽?
?services
If you wish to request or offer development/art/building/administration services, please do so at https://www.spigotmc.org/forums/services-recruitment-v2.54/
Hmm so working on a PR for sculk catalysts, but it seems a class is not included in the craftbukkit repo after I applied patches
I guess I did a step wrong with buildtools?
(this is a problem since I need to modify the code in this class, I need to add an event)
Imagine: we have two servers
The server work like this
Get a value un the cache and delete it
Server 1: we get the value of "1" (is a dog)
We give a diamond to the player
(In the same time an other player di a request)
Server 2 grt the value of 1 and give a diamond
Server1 delete the value.
It doesn't make sense, but it's an example. The 2 players got a diamond for something that should have given only 1.
did u drag over the file from the work/decompile-XXXX dir?
u need to manually drag in the files u want to edit if they arent there and ./applyPatches.sh to them p sure
that sounds sketchy but ok
I guess only classes that already have patches are included?
yes
Can u fix ur spelling errors, ive no clue what u mean
Yes
But it does sound like you need to sync the players inventories as well
We have 2 servers. Conecte a la db.
We have a code that works this way. When a player makes a command, it retrieves the value of key 1 (which will be dog).
Then it deletes it.
So it gives:
Db.get
Dg.delete
Except that if on weaner 1 a player x does this command and starts it
Db.get but just after on another server a player also does this command and the first db.delete has not yet arrived, the second player's db.get will return something even though it should no longer exist. Do you get it?
Not for what I want to do, but yes, at the moment I was wondering how to synchronize them between servers.
Yes in that case you need to synchronize the start of that command or whatever operation/process you’re initiating
Yes, but if it's on 2 different servers?
This
By synchronize I don’t mean java synchronized or java concurrent hashmap
I mean synchronize across servers
You have a proxy server right?
Yes, I was thinking of a synchronized boolean, and when it's set to True we wait for it to be false before making the request, but even then, if the 2 seeveyrs send the boolean to the other server at the same time, it's set to True. It won't work
Yes
Anything I say has nothing to do with java
because java synchronization and thread safety is only something you care about when you’re on that jvm itself, outside we talk more generic
And that is a terrible design I should say also
I would use the proxy server as some sort of manager and permission master
Basically each server send a redis message, it goes through the proxy and the proxy tells whether that message should be ignored/denied or not
That way there is a central service that ensures operations may be synchronized across and deduplicates if necessary
Oh yes, so everything runs in a single thread on the bungee server and there's no risk of desynchronization
Na
And concurrence
On the proxy you want it multi threaded
But at some point you do need to have some synchronization mechanism which I’d use a lock for
Since you’re essentially trying to avoid RC where an operation that should only be executed once could if you’re not careful enough be executed twice
and speaking of all this its not like u drop thread safety on server 1 and 2
That shit is still there
How?
By coding your stuff thread safe and implement atomicity etc if needed
so you'd advise me to run everything through the proxy, making a kind of lock and queue system?
public class BossOfTheForce {
private Map<UUID, BossBar> bossBars = new HashMap<>();
private WitherSkeletonBossbar witherSkeletonBossbar;
public BossOfTheForce(Location loc, AetheriaBosses plugin) {
WitherSkeleton witherSkeleton = (WitherSkeleton)
loc.getWorld().spawnEntity(loc, EntityType.WITHER_SKELETON);
witherSkeleton.setCustomName(ChatColor.DARK_RED + "Boss Of The Force");
witherSkeleton.setCustomNameVisible(true);
witherSkeleton.getEquipment().setItemInMainHand(ForceAbilityItem.createForceSword());
Attributable skeletonAt = witherSkeleton;
AttributeInstance attribute = skeletonAt.getAttribute(Attribute.GENERIC_MAX_HEALTH);
attribute.setBaseValue(1500);
witherSkeleton.setHealth(1500);
witherSkeleton.setGlowing(true);
witherSkeletonBossbar = new WitherSkeletonBossbar(plugin);
Player targetPlayer = (Player) witherSkeleton.getTarget();
if (targetPlayer != null) {
witherSkeletonBossbar.createBossBar(witherSkeleton, targetPlayer);
}
new BukkitRunnable() {
@Override
public void run() {
if (witherSkeleton.isDead()) {
return;
}
if (witherSkeleton.getTarget() == null) {
for (Entity entity : witherSkeleton.getNearbyEntities(10, 10, 10)) {
if (entity instanceof Player) {
witherSkeleton.setTarget((Player) entity);
}
}
}
witherSkeleton.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 1));
witherSkeleton.getLocation().getWorld().spawnParticle(Particle.CRIT, witherSkeleton.getLocation(), 10);
}
}.runTaskTimer(plugin, 100L, 100L);
}
private void updateBossBar(WitherSkeleton witherSkeleton) {
witherSkeletonBossbar.updateBossBar(witherSkeleton);
}
private void removeBossBar(WitherSkeleton witherSkeleton) {
witherSkeletonBossbar.removeBossBar(witherSkeleton);
}
}```
```java
public class WitherSkeletonBossbar {
private AetheriaBosses plugin;
private Map<UUID, BossBar> bossBars = new HashMap<>();
public WitherSkeletonBossbar(AetheriaBosses plugin) {
this.plugin = plugin;
}
public void createBossBar(WitherSkeleton witherSkeleton, Player targetPlayer) {
UUID bossUUID = witherSkeleton.getUniqueId();
BossBar bossBar = plugin.getServer().createBossBar(ChatColor.RED + "Wither Skeleton Boss", BarColor.RED, BarStyle.SOLID);
bossBar.addPlayer(targetPlayer);
bossBars.put(bossUUID, bossBar);
updateBossBar(witherSkeleton);
}
public void updateBossBar(WitherSkeleton witherSkeleton) {
UUID bossUUID = witherSkeleton.getUniqueId();
double healthPercentage = witherSkeleton.getHealth() / witherSkeleton.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue();
if (bossBars.containsKey(bossUUID)) {
BossBar bossBar = bossBars.get(bossUUID);
bossBar.setProgress(healthPercentage);
}
}
public void removeBossBar(WitherSkeleton witherSkeleton) {
UUID bossUUID = witherSkeleton.getUniqueId();
if (bossBars.containsKey(bossUUID)) {
BossBar bossBar = bossBars.get(bossUUID);
bossBar.removeAll();
bossBars.remove(bossUUID);
}
}
}``` I can't see the bossbar
There is no error at console
Please tag if you reply
@shell robin I feel like the createBossBar is never getting called.
If you spawn the entity, it's not gonna target a player immediately.
Other potential problems:
You're not deleting the bossbars, not sure how bukkit handles those but there is a method to remove them.
Also, not sure if you can cast the target to player safely. Could target normal skeleton that shot it. (Tho this will never happen in your code)
Not sure why you're adding the potion effect every 100 ticks, either give it the effect once with -1 for the duration (infinite, works only on like 1.19.4+)
Your boss will always target the player that joined the server last (upon losing target), unless the getNearbyEntities has different implementation than I expect it to have.
Not sure if I'm missing something, but you're not updating the bossbar either
BanList.Type.NAME is deprecated. Shouldn't I use PROFILE?
Yes use Profile
I put null as the date of the ban and my IDE doesn't let me do it.
ban.addBan(dead.getPlayerProfile(), ChatColor.RED + "You lost all your hearts!" + ChatColor.WHITE, null, null);```
it only works if I cast it to Date
well, what should i do
i don't understand exactly where is the error
Just noticed, the tasks never gets cancelled if even if the entity is dead.
yes and? that's fine
I would say create the bossbar with the entity, add targets once it has some
these are possible but still prevent this bossbar from being seen?
no, the problem is that it never gets created since the entity can't target you right after it spawns
what if I wait for 5 seconds?
what if the player hides/tps away
you can't "wait" in this case
check periodically until the skeleton has a target ig
or this
If I just set target != null it won't work :D right?
I-
I have no idea what you're talking about rn
I gave you two solutions that should work and I think I explained (what I think is) the problem fairly well
okay okay
i understand
thank you
i will try both of them
I tried this and added it as a blank texture, but it seems to retexture it to this