#help-development
1 messages Β· Page 1866 of 1
i have a panda, i have his move() function set to just nothing, and his damage() function set to nothing
when i go far away he forgets this stuff
i think he despawns and respawns
do you know of a fix
nope, nms is naturally unsupported and i am not sure. I thought this could be accomplished otherways in the API but im not sure
ye idk trying everything
I have a EntityPlayer/NPC, and I tried to use Entityplayer#move, but it won't do anything. Do I need to sent a packet or..?
yes
What packet?
Assuming you spawned it with packets
Yes
Entity Move?
Entity Position and Rotation
So what I would do is disable saving of your entity. Then manually save and load your entity
on reload i just remvoe all entities and respawn them for this particular issue
Do I need to do this?
nmsHelper.sendPacket(Player, new PacketPlayOutEntity.PacketPlayOutRelEntityMove(this.entityID, x, y, z, true));```
Because if I do that, it will just fly to a random location
how would you manually laod it? seems more intensive imo
yeah but you have to send a lot of them?
like everytime it moves
Not really. Listen to chunk load and spawn the entity
so every tick I need to send that packet until it is on that location?
no - what i mean is teh animations looks smooth cause there are more movement packets
you cant send a move packet for more than 8 blocks iirc
then it is a teleport packet
tbh just spawn a zombie and disguise it as player
how would you check if it is already there? i guess make a variable and check .isAlive() and if not spawn it or smth
And then control a zombie
libraries:
- org.bstats:bstats-bukkit:2.2.1
- org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlin.version}
- org.openjdk.nashorn:nashorn-core:15.3
```i added those as libs
Much easier IMO
however the plugin is still not loading
So what do I need to do to make it smooth?
send a lot of smaller movements
Ahh, now I get it
It won't be there if you stop it from saving
ye
What version of spigot are you on?
anyone know how to reset a map back to its original state after a game is over
ive tried jordan osterbergs tutorial but its way too quick
@opal juniper Can I send you a message in DM?
I can't send screenshots here
verify
does anyone know what all the despawn methods in NMS are
i want to override every single one so my mob deosnt despawn
im trying to make it so my NMS entity doesnt despawn when far away
its just easier
i swear its possible but idk how
as LivingEntity#setDespawnWhenFarAway
which behaviour?
like
heres my class
public class NMSPanda extends Panda {
public NMSPanda(Location loc) {
super(EntityType.PANDA, ((CraftWorld) loc.getWorld()).getHandle());
Level craftWorld = ((CraftWorld) loc.getWorld()).getHandle();
// this.goalSelector.removeAllGoals();
this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Player.class, 8.0F));
this.setPos(loc.getX(), loc.getY(), loc.getZ());
System.out.println(isPersistenceRequired() + " is1");
this.setPersistenceRequired(true);
System.out.println(isPersistenceRequired() + " is2");
craftWorld.getWorld().addEntity(this, CreatureSpawnEvent.SpawnReason.CUSTOM);
}
public void travel(Vec3 vec3){
}
public boolean hurt(DamageSource damagesource, float f){
return false;
}
public void playAmbientSound() {
}
public void addAdditionalSaveData(CompoundTag nbttagcompound) {
super.addAdditionalSaveData(nbttagcompound);
Bukkit.getServer().broadcastMessage("y1");
// nbttagcompound.putInt("DespawnDelay", 0);
nbttagcompound.putString("MainGene", this.getMainGene().getName());
nbttagcompound.putString("HiddenGene", this.getHiddenGene().getName());
}
public void readAdditionalSaveData(CompoundTag nbttagcompound) {
super.readAdditionalSaveData(nbttagcompound);
Bukkit.getServer().broadcastMessage("x1");
// this.goalSelector.removeAllGoals();
// this.checkDespawn();
this.setMainGene(Panda.Gene.byName(nbttagcompound.getString("MainGene")));
this.setHiddenGene(Panda.Gene.byName(nbttagcompound.getString("HiddenGene")));
// this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Player.class, 8.0F));
}
messy bc im trying stuff
public void travel(Vec3 vec3){
}
public boolean hurt(DamageSource damagesource, float f){
return false;
}
public void playAmbientSound() {
}
``` i want thse to stick
this.persistent = true;?
doesnt work either
can you check for something like this.setPersistent
i did
System.out.println(isPersistenceRequired() + " is1");
this.setPersistenceRequired(true);
System.out.println(isPersistenceRequired() + " is2");
true on both accounts ^
The problem is when Minecraft is reading the save it's creating a normal Panda not yours
If you really don't want to do what I said earlier with spawning it yourself, you will have to register your entity so the server knows how to create it
Wrong channel
im trying to get a string list from my lang.yml, and ive triple checked the spelling of everything, but it still returns an empty list... wtf```yml
kick-messages:
disallow-message:
- "&cTest"
```java
List<String> messageList = langConfig.getStringList("kick-messages.disallow-message");
The config is 100% loaded and working cause every normal message (non-list) works completely fine.
WAIT nevermind im an idiot
wow you can tell i was nearly asleep when i wrote this code
if ur not writing ur code in the most ungodly hours are u really coding?
it works w villagers tho
soo it is possible
>et
[22:10:19] [Server thread/WARN]: Unexpected exception while parsing console command "et"
org.bukkit.command.CommandException: Unhandled exception executing command 'et' in plugin Spigot-ExpTech v22w01-pre1
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:47) ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:149) ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
at org.bukkit.craftbukkit.v1_18_R1.CraftServer.dispatchCommand(CraftServer.java:821) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3378-Spigot-8965a50-0ba6b90]
at org.bukkit.craftbukkit.v1_18_R1.CraftServer.dispatchServerCommand(CraftServer.java:806) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3378-Spigot-8965a50-0ba6b90]
at net.minecraft.server.dedicated.DedicatedServer.bf(DedicatedServer.java:453) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3378-Spigot-8965a50-0ba6b90]
at net.minecraft.server.dedicated.DedicatedServer.b(DedicatedServer.java:429) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3378-Spigot-8965a50-0ba6b90]
at net.minecraft.server.MinecraftServer.a(MinecraftServer.java:1206) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3378-Spigot-8965a50-0ba6b90]
at net.minecraft.server.MinecraftServer.w(MinecraftServer.java:1034) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3378-Spigot-8965a50-0ba6b90]
at net.minecraft.server.MinecraftServer.lambda$0(MinecraftServer.java:304) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3378-Spigot-8965a50-0ba6b90]
at java.lang.Thread.run(Thread.java:833) [?:?]
Caused by: java.lang.ClassCastException: class command.command cannot be cast to class org.bukkit.plugin.Plugin (command.command is in unnamed module of loader org.bukkit.plugin.java.PluginClassLoader @13a6aa5c; org.bukkit.plugin.Plugin is in unnamed module of loader java.net.URLClassLoader @15327b79)
at command.command.onCommand(command.java:16) ~[?:?]
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:45) ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
>
What's wrong?
It tells you
oh nvm, its just bstats being like "yOu HaVeNt ReLoCaTeD mE"
package command;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
public class command implements CommandExecutor{
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
//console(ChatColor.RED+" "+label);
//console(ChatColor.RED+" "+args[0]);
Bukkit.getPluginManager().disablePlugin((Plugin) this);
Bukkit.getPluginManager().enablePlugin((Plugin) this);
return false;
}
public void console(String data){
Bukkit.getConsoleSender().sendMessage(data);
}
}
you can't do this btw
once calling disable you can't call enable
if you want to disable the plugin after a command, you want a plugin to disable
commandExecutors arent instances of a plugin
instead you want to grab the instance of your Main (or equivalent main class) that the server is using to handle your plugin
@Override
public void onEnable() {
new command(this);
}
package command;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
public class command implements CommandExecutor{
private final JavaPlugin plugin;
public command(JavaPlugin plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
//console(ChatColor.RED+" "+label);
//console(ChatColor.RED+" "+args[0]);
plugin.getServer().getPluginManager().disablePlugin(plugin);
plugin.getServer().getPluginManager().enablePlugin(plugin);
return false;
}
public void console(String data){
Bukkit.getConsoleSender().sendMessage(data);
}
}
Is this correct?
that will work
Objects.requireNonNull(getCommand("et")).setExecutor(new command(plugin));
This will error
oh right im stupid
getCommand("<whatever>").setExecutor(new command()); instead of just creating a new commands();
just make sure whatever you name the command is in the plugin yml
Cannot resolve symbol'commands'
command, not commands
my bad
@Override
public void onEnable() {
new command(this);
getCommand("<whatever>").setExecutor(new command());
}
How can I find a player by their name on the bungee network, and then send a message only to him?
the "<whatever>" part needs to actually be a command
still error
package command;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
public class command implements CommandExecutor{
private final JavaPlugin plugin;
public command(JavaPlugin plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
//console(ChatColor.RED+" "+label);
//console(ChatColor.RED+" "+args[0]);
plugin.getServer().getPluginManager().disablePlugin(plugin);
plugin.getServer().getPluginManager().enablePlugin(plugin);
return false;
}
public void console(String data){
Bukkit.getConsoleSender().sendMessage(data);
}
}
'command(org.bukkit.plugin.java.JavaPlugin)' in'command.command' cannot be applied to'()'
?learnjava when
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.
needs a plugin argument
I have a Collection of Entity. What should I put in .contains() to get the player's Entity?
wat
bruh i really hates google translation
learn english π
I don't know
what should i insert to get Entity of player?
are you newer to coding plugins?
hm??
Are you trying to get all of the players within a certain region?
[22:41:05] [Server thread/INFO]: /et <args>
ill take that as a yes
Is this be print by my code or spigot
there's should be getNearbyEntites which takes Class as argument
if you dont have a print statement thats printing that in your code then its spigot
List<Player> players = entry.getWorld().getNearbyEntities(box).filter((entity) -> entity instanceof Player).map((entity) -> (Player) entity).collect(Collectors.toList());
No problem. It isn't super efficient, but it will do what you want.
List<Player> players = sentry.getWorld().getNearbyEntities(box).stream().filter((entity) -> entity instanceof Player).map((entity) -> (Player) entity).collect(Collectors.toList());
Whoops lmao, forgot the ".stream()"
is it ok now?
Should be. Try it out.
Thanks :)
not too set?
Can I use command with space?
getCommand("et reload")).setExecutor(new command(this);
not possible
make a subcommand instead
handle the "et" command and then check for subcommands
what's the point of analizing code before pushing to github?
hi guys can you help me please to config preventportbypass plugin
to avoid errors you won't see on remote?
is it checking for errors in your code?
Is there any problem with converting the Player object to a LivingEntity?
Thanks
Player.class::isInstance and Player.class::cast π
hmm
Going to keep these cute little shortenings in my back pocket for later ;)
where to learn lambda?
?lamda
on google i guess?
tru
for what i have seen long **$
lambda lines
i'm justing hitting like yeah ok i'm lost
what are you struggling with?
public Optional<Group> getTopGroup(User user, Track track) {
SortedSet<Node> allNodes = user.getDistinctNodes();
if (!allNodes.isEmpty()) {
GroupManager groupManager = luckPerms.getGroupManager();
return allNodes.stream()
.filter(NodeType.INHERITANCE::matches)
.map(NodeType.INHERITANCE::cast)
.map(InheritanceNode::getGroupName)
.map(groupManager::getGroup)
.filter(Objects::nonNull)
.filter(track::containsGroup)
.max(Comparator.comparingInt(g -> g.getWeight().orElse(0)));
}
return Optional.empty();
}
In short, lambdas are just condensed methods.
public void method(String input1, int input2)
Can be represented as a lambda
(input1, input2) -> { /* the implementation of that function */ }
If you refer to some existing method that matches the signature of that method, you can do Type::theMethod or instance::theMethod
woah!
but damm that code looks crazy
So those .map() methods just accept a Function<T, R> where T is the input type and R is the return type
SortedSet :kekw:
and Function has a method called accept(T) that returns R
However, that snippet above is really going overkill with the calls to .map(). That should really all be condensed into one
Note: i took this from LuckyPerms API
.map(node -> groupManager.getGroup(NodeType.INHERITANCE.cast(node).getGroupName())
Would be equivalent to those 3 map functions
Can just be done all in one
the lp api goes brr tho
:3 <-- looks like face
thats not intellij not working
hava you added the jars?
plz help, i created gradle sub-modules for each mc version. but when i compile it (with java 11, bc i want 1.13+) it gives me bad class file: /home/areg/.m2/repository/org/spigotmc/spigot/1.17.1-R0.1-SNAPSHOT/spigot-1.17.1-R0.1-SNAPSHOT.jar(/net/minecraft/nbt/NBTTagCompound.class)
class file has wrong version 60.0, should be 55.0
1.13+ is also java8 no?
java 11 is supported by 1.13, idk about java 8
Bukkit supported Java 6 for the longest time
Like, Bukkit only started making use of Java 8 features around 1.12 or something
CraftBukkit had compiled against 8 in 1.13 though, yes. If I recall correctly, Mojang required 8 a version or two before Bukkit made the jump
and still, how would i fix this
1.17 requires Java 16
i know
and you're using it as a dependency
If you're referring to NMS, yeah, that's going to be an issue. You'll have to set the Java version of each subproject
Then compile the whole thing with Java 16
I compile VeinMiner against 8, but Fabric mod against 17 (because I obviously need to support the latest client)
However I run Gradle with Java 17
Even if you're running Gradle with a modern version of Java, it will compile your project against the version it has set in its build.gradle
i tried to run gradle with java 17, and the plugin didn't run on 1.13 server, saying that it has wrong class version
Then your sub-project's build.gradle isn't defined properly telling Gradle to build with 8
I'm not familiar enough with Gradle to help you with that though. I'm barely scraping by with VeinMiner. I'm usually a Maven user
so i should set java version in global build gradle to 11, and in 1.17/1.18 sub module to 16/17?
Your parent build.gradle shouldn't have any version defined at all
o.O Then that's a very strange setup
Your parent gradle project should contain nothing much more than build files
how do i return something async with the bukkitscheduler?
i guess its not possible
completablefuture prob
i have a module for shared stuff that accessed and in main project, as well as in nms modules, and the whole project is in parent dir
Ideally you'd have a common project that all of your dependents rely on (like an API of sorts), and each of your subprojects will build with it shaded (or shadowed in)
Yeah, Brush, CompletableFuture
Well, you still can use Bukkit scheduler to complete future asynchornously
something i hate it that java doesnt has pointers π
No pointers, no, but it does make use of references
i should define version with
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(16))
}
}
```?, if yes, then it gives me error
So if you edit a List you're going to be able to modify that from any thread
(taking into account thread safety)
No matching variant of project :v1_17_R1 was found. The consumer was configured to find a runtime of a library compatible with Java 11, packaged as a jar, preferably optimized for standard JVMs, and its dependencies declared externally but:
What's pointer
im doing stuff like this but that return isnt valid
Again I'm not super informed on Gradle. I really dislike working with it at all so I'm not the best to be asking about topics like this. Even setting basic Java versions in Gradle files seems stupidly overcomplicated to me because you can do it in 12 different ways lol
uhm
Yeah that will have to return a CompletableFuture. It would look more like this
public CompletableFuture<User> getUserAsync(UUID uuid) {
CompletableFuture<User> result = new CompletableFuture<>();
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> result.complete(getUser0(uuid)));
return result;
}```
(notice also how I changed it so that it's called getUserAsync() so it's a distinct method)
Can then operate on that result. getUserAsync(uuid).whenComplete((user, e) -> {})
it should have a sync and an async version π thats why i made the getUser0 method
Yeah so you'd also have a getUser(UUID) that runs synchronously
You're better to keep the methods separate because otherwise you're returning a completed CompletableFuture. Which is fine, you can just call .get(), it's just not super intuitive
private final Executor asyncExecutor = r -> scheduler.runTaskAsync(plugin, r);
return CompletableFuture.supplyAsync(supplier, asyncExecutor)
Yeah, supplyAsync() is also another option, you're then not bound to Bukkit's scheduler
It's likely going to return much quicker rather than on the next tick
At least assuming you don't use Bukkit's scheduler as an Executor lol
anyone, who worked with gradle, how can i fix this?
No matching variant of project :v1_17_R1 was found. The consumer was configured to find a runtime of a library compatible with Java 11, packaged as a jar, preferably optimized for standard JVMs, and its dependencies declared externally but:
- Variant 'apiElements' capability com.aregcraft.delta:v1_17_R1:1.0-SNAPSHOT declares a library, packaged as a jar, and its dependencies declared externally:
- Incompatible because this component declares an API of a component compatible with Java 16 and the consumer needed a runtime of a component compatible with Java 11
- Other compatible attribute:
- Doesn't say anything about its target Java environment (preferred optimized for standard JVMs)
what do i need to fill in instead of the suplier?
i want to return the actual user object, not the future
or i should do what choco said π
someone, please, how am i supposed to compile plugin with multiple java versions with gradle?
- Variant 'apiElements' capability com.aregcraft.delta:v1_18_R1:1.0-SNAPSHOT declares a library, packaged as a jar, and its dependencies declared externally:
- Incompatible because this component declares an API of a component compatible with Java 16 and the consumer needed a runtime of a component compatible with Java 11
I'm getting this error. I have no idea why
Error dispatching event net.prisonnetwork.prisonbungee.events.PrisonChatEvent@19f51f14 to listener me.itxfrosty.prisonlink.listeners.ChatListener@4cc6fa2a
PrisonChatEvent: https://pastebin.com/5SbB5bc9
ChatListener: https://pastebin.com/94xZUyVC
hold it didn't send one. Let me fix that.
You cant. You would have to use futures.
im struggling
You cant return User Object instantly, thats not how concurrency works ;>
anyone? please π
how would i even include nms modules to the root project?
i use implementation rn
i'm doing stuff like this afterwards with the user object and i dunno how to implement that while doing stuff async
Try 1.18.1
i did and it gave me the same issue
Did you add the spigot repo?
it automatically does
it works on my other computer
how could i check my java version?
java -version
im running 17
You could try what Intellij suggests
Clean up the broken artifacts data and reload the project
It's literally there
Click it
hm
how can I see if clicked inventory is player's inventory
You check it against the PlayerInventory class
got it
doesnt work
wait nvm
i forgot to refresh the jar
sorry
please help π how would i setup the root build.gradle.kts for multi-module gradle project, with some modules having different java versions than others
So i am trying to make a plugin that has a gui where you can store spawners and then collect the XP via the GUI. If i wanted to calculate how much XP someone should get how do i do that?
I have the item storage all done
pleaseeeeeeeeeeeee
i have it so every stored item has an XP value but when should i change that value
Save a time in the item for the last time xp was generated?
And then generate based off that time?
But then how would i get the amount of XP based off the time?
not the ones that disables and enables plugins
Save the last time collected with; World#getFullTime. Calculate how long it's been then use the player#giveExp method to add xp. For calculating the experience gain you can just create a simple math formula or calculate an average of what a spawner would generally give
would system.currenttimemill work
.
You can use that if you want but it could cause weird behavior if the server shutsdown or freezes for a while
Have you set the java version?
yep, but they are different, bc i am using java 16 for 1.17 and 1.18 nms modules and java 11 for others, bc of 1.13 compability
and i understand that the error is bc the versions is incompatible, but there must be some way to make multi module projects, right?
Then set java in each gradle file
Make sure it matches what you're building against
the 1.18 and 1.17 modules can't match to other modules
they require java 16+ and 1.13 require java 11
there must be some way to make plugin 1.13+ right?
1.13 can use Java 8
Yeah
Would thisw,ork?
so what should i do????
Set the java versions
i don't understand, i set the java versions for 1.17 and 1.18 modules to ```kotlin
java {
sourceCompatibility = JavaVersion.VERSION_16
targetCompatibility = JavaVersion.VERSION_16
}
it dont work either with ```kotlin
toolchain {
languageVersion.set(JavaLanguageVersion.of(16))
}
doesnt 1.18 require Java 17
the 1.17 dont work either
It does
1.18 needs Java 17 and the target should be Java 8
can someone tell me, why the hell this crashes any forge client when joining?
or 11 if that's your target
@EventHandler
public void onServerConnected(PostLoginEvent event) {
//Wir senden Packet ID 1
//Wir wollen empfangen Packet ID 2
event.getPlayer().sendData(FMLHS13, new byte[]{4, 1, 0, 0, 0});
}
private static final String FMLHS13 = "fml:handshake";
just an random illegal stack trace
although its just documented like i did at wiki.vg
so?
java {
sourceCompatibility = JavaVersion.VERSION_16
targetCompatibility = JavaVersion.VERSION_11
}
``` if yes, then it throws same error, Incompatible because this component declares an API of a component compatible with Java 16 and the consumer needed a runtime of a component compatible with Java 11
Is that your 1.17 gradle file?
yep
also make sure to actually be using a java 17 jdk
if i use java 16 jdk how would java 11 modules compile?
You need java 17 jdk. jdk can compile to an older version
No
thats deprecated
use the tool chain π
ur a tool chain uwu

owo?
omg the toolchain is so hot
it downloads the proper jdk for u
i compiled it with jdk 16 and it don't run on 1.13 now
You didn't set target to java 11
where?
bump
targetCompatibility
Do you want to load your own jar files?
I think so idk
Even setting basic Java versions in Gradle files seems stupidly overcomplicated to me because you can do it in 12 different ways lol
fuck Gradle, honestly
I can't keep up
π
wdym idk?
wlel
What do you want
my only experience with gradle is when doing forge/fabric and new forge/fabric projects take 50 years to open
aaaaa
That's because of the decompiler and remapping
and it automatically updates the jar
help me
when i set target version it throws error
what error
- Variant 'runtimeElements' capability com.aregcraft.delta:v1_18_R1:1.0-SNAPSHOT declares a runtime of a library, packaged as a jar, and its dependencies declared externally:
- Incompatible because this component declares a component compatible with Java 16 and the consumer needed a component compatible with Java 11
You need Java 17
Do you have better alternatives
same with java 17
eyo pin that last line
gradle cool π
idk then. I don't use gradle
javac on top
anyone else know gradle?
Try showing your entire setup and someone will be able to provide better help
What's gradle
the Minecraft plugin for IntelliJ sucks so hard
what features does it actually add that are useful for anything?
All I see is it causing crashes and adding text color to strings
this is my whole gradle setup: https://paste.md-5.net/zezagupela.makefile
please help
it never crashed on my pc
you should use subprojects for your different NMS versions instead of just throwing them all in your main project
i do so
i do exactly that
well then try to use IntelliJ i18n feature on strings with that plugin enabed
oh sorry I'm not good in reading gradle files
It's very useful when modding. Not so much with plugins
It helps with Mixings and ATs
Things like that
.
the gradle files are here
That's not the entire thing if you're using submodules
Now go put the entire project on github
its nice for working with mixins lol
yeah okay that might be true
I just find it annoying for spigot, because all it does there is cause problems lol
Never had any major issues with it
select a String, Alt+Enter -> First thing (the i18n option) instantly crashes it
I mean a String literal ofc
Hi there, I'm currently storing per-player-files which all contain a field with a number in it. I also made a function which sorts all files based on the number. When I want to display e.g. number 2 on a scoreboard, I need to call this function and get the second item from the list. But this gets pretty heavy when there's a lot of player files and when the scoreboard is updating every second. What would you suggest?
I was thinking about double storing the number in a small 'top' list, but this does not feel like the right solution.
cache the values of those files instead of reading them everytime
e.g. make a class PlayerData that has every option your file has anyway
e.g.
public class PlayerData {
long number;
String someThing;
...
}
or records when using recent java versions
That sounds like a nice solution!
?paste
?
anyone?
Hello I wanted to ask. How would I be able to make the user customize the config.yml so they could change settings of the plugin?
create a file in your resources folder called config.yml.
in onEnable(), do saveDefaultConfig()
Now you can access with getConfig().getString("value1");
getConfig() saveConfig()
Yea, but how would I be able to make it so people can change some settings via the config file?
they can just edit the config.yml
after that you can reload it using reloadConfig()
that's everyting needed
I mean like
So on ServerA i have 4 values (2 longs and 2 doubles), i am writing them to a ByteArrayDataOutput and sending it as a byte array, so far so good, right? well when i receive it on the bungee and bounce it to ServerB it receives like 10qd when the original value was 10, why's that?
for an example
theres a cooldown for an item like an enderpearl. And you make it longer or shorter by default. But you can change the cooldown via config
well you know how the some prem plugins have a loader for their plugins and it automatically updates the jar
Thank you!
np
π
iirc Spigot has an update folder that already can take care of it. In general though auto update is a bad idea
but you know what I mean right
yep it's part of craftbukkit iirc
just download your .jar to the update/ folder and bukkit replaces it on next startup
?
what's your code to read the data?
readLong()
readLong()
readDouble()
readDouble()
(its in a loop since multiple sets are sent, could that be an issue?)
try {
while(true)
UserData.setPlayer(Bukkit.getOfflinePlayer(UUID.fromString(in.readUTF())), in);
} catch (Exception ignored) {}
```I know its a bad idea i just don't have the full length of the data, so i just run until i straight up can't anymore
UserData data = new UserData().readFrom(in);
Bukkit.broadcastMessage("Incoming data for player " + p.getName() + ": " + data);
data.set(p);
```thats the method
for setPlayer
this.a = in.readLong();
this.b = in.readLong();
this.c = in.readDouble();
this.d = in.readDouble();
that's for readFrom
out.writeLong(this.a);
out.writeLong(this.b);
out.writeDouble(this.c);
out.writeDouble(this.d);
that's writeTo (for writing the data)
while(true)
i mean you are only showing us snippets
its hard to find mistakes for you
the whole file could be better
no one here has time to "judge" your code
and we forget about it anyway after a while
if it helps you feel better, delete your messages afterwards
ok lol
i am just sending snippets since my internet is shit and doesn't like large files
just some people are kind of hesetant to show code
oh ok
some people just are like "someone will steal my code!!"
large is relative here, its pretty small files
like its staking multiple seconds to send these msgs
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("PlayerData");
try {
while (true) {
out.writeUTF(player.getUniqueId().toString());
out.writeLong(in.readLong());
out.writeLong(in.readLong());
out.writeDouble(in.readDouble());
out.writeDouble(in.readDouble());
}
} catch (Exception ignored) {}
```thats the code for reading the data on the bungee, then it is sent to all servers but the one it came from
before the data a player uuid is sent as a string to specify which player the data is for
Why the fuck while(true)
i don't know how much i need to read, so i just read until it goes like "uh oh no more data"
since it has no method to know what's the size
i don't have size... before i write the data
there's also a method to see whether the stream has ended
but no idea what its called lol
not in ByteArrayDataOutput
you know how many times you write those 4 numbers
not really
it depends if a player did an action
and it sends all players at once
so i can't just put the size of players * the size of data
otherwise it would be way easier
hold on ill brb
in AsyncPlayerChatEvent, is it possible to only send the message format to specified players?
Looks like it
fun times
I'm pretty sure that should work jokes aside
Not sure why it looks like that
please, help
Try asking Paper. They're generally better with Gradle
so format the chat for certain players? if so then yes you can, you can either check if they have a permission or do it by name or id
I mean,
What if the player is in an array?
yeah you can do that
some md_5 good design choices
IntelliJ being stupid again... how tf should I make this (@Getter ... instance) final?
?paste
you could do a "for" loop for the array and for each player in a list format their chat
here is a example of a way you could do it inside the event instead of a for loop
e.setCanceled(true);
//then broadcast the message with the format
}
}```
all it does is checks if the array contains the player then it will cancel their message then broadcast a message with the format you would want
I didn't think of it like that, I went the wrong way and tried for (Player player : array) which obviously did not work, thanks!
np
Hi, would anyone be able to help me try and code my first plugin in Java? Im using IntelliJ Community and have no experience coding java, (Mainly python).
?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.
How can i set a double chest? I looked in all spigot threads that i founded about that but nothing worked for me. Version: 1.18.1
Create two BlockData instances of type Chest
Make sure to cast to the Chest BlockData
Set one to left (there should be a setType method or similar)
Set the other to right
And set them to be facing opposite directions as appropriate
Then set the left one on one block and the right one adjacent to it appropriately
Make sure to use setBlockData(data, false)
That way it won't update the block upon being placed and immediately change back to a single chest
e.getDrops().clear();
Location loc = player.getLocation();
Block leftSide = loc.getBlock();
Block rightSide = loc.clone().add(0, 0, -1).getBlock();
leftSide.setType(Material.CHEST);
rightSide.setType(Material.CHEST);
BlockData leftData = leftSide.getBlockData();
((Directional) leftData).setFacing(BlockFace.EAST);
leftSide.setBlockData(leftData);
org.bukkit.block.data.type.Chest chestLeftData = (org.bukkit.block.data.type.Chest) leftData;
chestLeftData.setType(Type.RIGHT);
leftSide.setBlockData(chestLeftData);
Chest leftChest = (Chest) leftSide.getState();
Chest rightChest = (Chest) rightSide.getState();
leftChest.setCustomName(ChatColor.GOLD + e.getEntity().getName() + ChatColor.RED + "'s Death Chest");
rightChest.setCustomName(ChatColor.GOLD + e.getEntity().getName() + ChatColor.RED + "'s Death Chest");
rightChest.update();
leftChest.update();
BlockData rightData = rightSide.getBlockData();
((Directional) rightData).setFacing(BlockFace.EAST);
rightSide.setBlockData(rightData);
org.bukkit.block.data.type.Chest chestRightData = (org.bukkit.block.data.type.Chest) rightData;
chestRightData.setType(Type.RIGHT);
rightSide.setBlockData(chestRightData);
DoubleChestInventory inventory = (DoubleChestInventory) leftChest.getInventory();
inventory.setStorageContents(player.getInventory().getContents());
You're calling setBlockData without passing the second arg
Pass the second arg as false
Also you don't need to set them to chests to get the chest block data
You can just do Material.CHEST.createBlockData()
ok thank you, i will try it
anyone? i asked on papermc but nothing
how would i fix java version error
what means the 2nd arg boolean in setBlockData()?
?jd
what would you be trying to do?
Player#updateInventory
I just want to begin creating plugins but I donβt know Java right now so Iβm actually learning it cause I thought it would be smart to learn Java before creating plugins
Lots of this stuff is very easy to look up in docs or on google
I would recommend finding some tutorials or books on java
We're not here to hold your hand through the learning process, but we can help you along the way
You need to help yourself first though
I found a YT vid by Kody Simpson itβs in parts π
Okay
Note that YouTube videos never give the full picture and have a tendency to oversimplify
ya but when I tried it didnt show up in my ide turns out i had to make it a variable and cast it that way for sum reason
It's always a good idea to read docs to supplement tutorials
Ohhhhh
Yes
Yea*
or they talk 30 minutes to explain something that could be explained in 19 seconds
Gotta get that ad money
I made a game using a datapack, but want to combine the LibsDisguises plugin with it.
So what i want my plugin to do, is check for players' NBT-data and check if they have a certain tag (vanilla /tag), and then running a command from the LibsDisguises Plugin using the (stored?) player that passed the tag-check, ultimately disguising them.
Note: I know basic (C#) code but am new to java / plugins in general. I also know i shouldn't be combining datapacks & plugins but that's just how things turned out.
I thought I'd find the best answers here, Thanks in advance.
so you seee.... interger is a type that is a variable that can be assigned to a interger which can be the number of 1 2 3 4 5..... (int limit) and 0 -1 -2 -3 -4 -5 -6... (-int limit)
and thats how we end our 54 hour part about integers
I do like me some "interger"
?
?
So i am doing a plugin with custom config files and learning to use them but, I am running into an error.
This is the error: https://mcpaste.io/300f3d5680a21a92
So what the code is supposed to do is it should create the config file here: https://paste.md-5.net/azigucacor.java
Then in the main file there is a event handler that should look to see if you click on a diamond ore and if you don't it just returns. After it check that you click a diamond ore it sets amount to 0. Then it should check to see if you already have a entry and then if you do not have one it should create one. Then it should add 1 to the amount so that the count goes up inside data.yml. Here is the file for that: https://paste.md-5.net/yatumovibe.java
also I am following a tutorial and he does the same thing but it works
double killerhealth = killer.getAttribute(Attribute.GENERIC_MAX_HEALTH);
it returns AttributeInstance not double
you need to use the AttributeInstance to get the actual value.
ok
how can i test for player tags (vanilla /tag)
if possible
where do i use that
Let's see those resources.
https://paste.md-5.net/azigucacor.java#L22
this will save config.yml that is in the jar, but you don't call any methods to create data.yml. add in there your reloadConfig() method. Second the error is complaining about an NPE in your listener for the event. I am assuming because data.yml doesn't exist since you never invoked the method to create the data.yml file just the one that creates config.yml
I'm trying to make a blank spigot plugin. I am following the tutorial on the website and it refers to a spigot-api-shaded.jar file ... that i don't find anywere
ran into the same problem earlier, if it's the first jar file its just the one from the server
so I simply download spigot-1.18.jar and use it as external resource with javadoc?
I think so, I am a beginner too though π
I recall it used to work like this but I may be wrong, so that why i was asking
?bt
you can use BuildTools which will install the API into your local maven repo, or you can go to the second link and download the api jar
or you can use the second link as defining the repo for maven to pull the API from
what's the difference from using the actual server spigot.jar? asking out of curiosity
Yea but you don't get it in maven local
Main difference is that the server jar contains more methods or access to more things, but not necessarily things you may want to use and occasionally can end up using the wrong things, also the code for the server jar changes between versions usually which means methods used from the server jar might stay the same, but work differently or both. The API doesn't change often and most everyone just only needs that and it has documentation server jar doesn't π
if you use buildtools you will
I know that's what I'm talking about
oh ;/
honestly sorry for spamming, but I've been stuck with this problem for a while now. I don't know if it's just not possible but how do I test if players have a tag (vanilla command /tag)?
Jars
Thanks a lot for this explanation
ye helped me out too ty
I think thats the Scoreboard Tag?
@wet breach check #help-server
no it's just a vanilla ./tag command
./tag [player] add [tagname], and it will be stored in the NBT data
i think
i mean, entity.getScoreboardTags()
if that's the java naming possibly yes
why the shaded.jar must be used as api interface? Because it already has some dependencies inside it?
omg yes, that's it! thank you so much
spent the whole evening searching for it
So I added the reload config in here:
public DataManager(Diamondcounter plugin){ this.plugin = plugin; //saves/initialized the config saveDefaultConfig(); reloadConfig(); }
But I still get the NPE error about my listener. Did I misunderstand what you said?
awesome, we are making progress now π
thanks for the help so far btw
alright so I already know what the NPE is now complaining about though
so, now it isn't complaining about data.yml however your code assumes there is data in it
yep data.yml is blank so you need to check that data actually exists
yep, and your code in your listener doesn't check if its empty or null
or null, because you can have empty values in there
ok i will try that
first check if its null, then if not null check if its empty
ok
Hey, i used Inventory's larger than 6*9 in previous projects of mine, how can i do that in spigot 1.17 or higher?
because if i try it gives me an error saying its not allowed anymore
you cant
Ok, because it was removed from Mojang or because its removed from spigot itself?
mojang
Ok, thank you
How can I move a zombie while keeping its head with its body?
I tried teleporting the mob every 10 ticks with 15 more yaw, but then the head lags behind like 90deg from the body
here's a video: https://streamable.com/zkq5rh
Hello, I'm trying to integrate MySQL in my maven plugin using this resource: https://github.com/mysql/mysql-connector-j
My question is, which package am I supposed to shade? it's not written anywhere...
okay so I removed the dependency, but the class MysqlDataSource is now unreachable
you should not be using mysql classes directly
mysql is a jdbc driver, you code using jdbc
adding custom textures to a custom chestplate through optifine. how does optifine cit know which one to change though?
I don't, it just gives me a connection object
instead of using ConnectionManager
so I need to use ConnectionManager instead?
I don't think this is related to Spigot.
is there a way to teleport an entity and have it turn immediately, no turning?
is it possible to "reload plugin folder on file change"?
so i don't have the hassle to do it manually
if there is any option or something
From spigot's wiki: Of course spigot has some kind of mysql database driver included, however this driver was never really intended to be used by the public and is also pretty old (As of 14.4.2021 the version is 5.1.49. Latest is 8.0.23). So you will be good with getting your own version of it. Also your plugin will break whenever the driver path changes, or the driver is relocated. In fact the spigot way doesn't work with paper anymore, and I want to provide a general best practise on this page. You can find the latest mysql driver here. Throw this in your gradle, maven or whatever and don't forget to shade and relocate this.
okay, so if I go with you, I need to use ConnectionManager?
use it exactly as any other jdbc driver / mysql tutorial
yeah that's what they always suggest
DriverManager.getConnection
and consider deleting that wiki page, it sounds like crap
it's a huge wiki page lol
The home of Spigot a high performance, no lag customized CraftBukkit Minecraft server API, and BungeeCord, the cloud server proxy.
the wiki in general is a mess
is there a non-NMS way to check if an entity has AI?
declaration: package: org.bukkit.entity, interface: LivingEntity
how can i get that info
what info
In the end I built a shell script
this probably https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/HumanEntity.html#getAttackCooldown()
declaration: package: org.bukkit.entity, interface: HumanEntity
Mockito plugin.getServer still null after being set
hey guys, maven isn't building with plugin.yml
can anyone help?
plugin.yml does not appear in the root of my maven-enabled plugins
Did you include it as resource?
You have to place it into the resource folder
And it will do the magic
You are very welcome
What would be an efficient way to check if an entity has line of sight to the sky?
Like how the game knows to set an undead on fire if out in the sun.
I usually use getHighestBlock at their location
Itβs not perfect, but it uses heightmaps so itβs pretty fast
vault init. problem
thx
how can you access/manage the whitelist from a plugin?
im assuming the whitelist is a lot like the banlist on spigot's side
possibly like this?
(this is referring to a class extending JavaPlugin)
only use static with static
feel like ive heard some "u shouldnt access it thru that" here and there but idk
never use Bukkit.getServer if u can just get it from ur current instance
^ exactly what i was talkin abt lol
Probably doesn't matter but yeah Plugin::getServer is slightly better
what about for adding/removing players?
ah thank you
Dont make me static everything
I'll static you instead
Mean
on startup my custom config / yml file doesnt seem to be being created. this is the code i have
if(this.configFile == null)
this.configFile = new File(this.main.getDataFolder(), "data.yml");
if(this.configFile.exists()) {
this.main.saveResource("data.yml", false);
}
im having trouble with my pom.xml file (dm for screenshot since i cant upload files)
just verify ezpz
upload it to something like Imgur
well
you probably want to check for the config file's absence, not presence
hello wveryone
sup
ask away
does anyone know how to make NMS entities keep their overidden behaviour on despawn
or just prevent the despawn
my wandering trader villagers do this
but i want to use a panda
best way would be to derive a custom entity
ive overidden the damage+move methods so they dont move
since the entity instance may be invalidated and reinstantiated on chunk unload or such
i wouldnt want to check and re-spawn even tho thays probs the best option
and then your injections on the entity will be lost
ye
but it works for villagertraders
so idk why theres no hack for other entities
wandering traders stay the same no matter how far u go or how long
i just set the despawn timer to 0 on them
i think there might be a way in material or like block.getsound
step sound or smth
Found another way that uses Block.getLightFromSky()
Returns a byte value between 0 and 15.
If the value is 15 it means direct line of sight to the sky.
Compare that with the time of day and it can mimic the vanilla mechanic.
Thanks!
also sorry but wym by derive
is there a way to tell if it wasnt vanilla
derive = extend
@ivory sleet
uhh, when I filter materials where itemMeta is instanceOf Damageable, I still get all materials in the game
any idea why that is?
return Material.values()
.filter { it.name.contains(query, true) }
.filter { ItemStack(it).itemMeta is Damageable }
.sortedBy { it.name }
.map { it.name }```
That's F#.
it'll be Note.sharp()
which octave
I think 1.
It starts at 0 right?
I made a really bad tracker plugin that messed with the note system and I remember the octave system being a pain
well, just tried it and the sound was different
than the note block
the nearest i saw is 0
when using paths for custom configs how would i make one entree have multiple things under like
players:
uuid
def players uuid etc
players., value doesnt work
how would I check if an ItemStack is a tool or weapon?
create a list with common tools / weapons
is there really no other way?
no
π
a sharp F note in octave 1 plays the same sound as the violet note
I don't know why yours sounds different
a bit ugly but basically you just need all the pickaxes, hoes, axes etc ina list
i will do a video
technically F# is 1 half octave above F
EnchantmentTarget.TOOL.includes(Material)
but I doubt half octaves are implemented π
it wouldnt be player, value
would i just have to do
player. + uuid, value 0 or
that could explain a lot
return Material.values()
.filter { it.name.contains(query, true) }
.filter { ItemStack(it).isToolOrWeapon() }
.sortedBy { it.name }
.map { it.name }```
I'll do it like this
ItemStack(it).isToolOrWeapon()?
Itβs a bit weird how the enchantment targets are basically Tags, but it works
is that a paper method? spigot doesn't have any ItemStack#isToolOrWeapon method
you should use a set
It's got 2 octaves, same as the noteblocks.
That does mean it's extremely limited without using different instruments. Wish the noteblock system was expanded. Two octaves is way too narrow
I am
that is an array
Kotlin has extension methods π
yeah but you will still have to check by your own logic whether sth is a tool or weapon
well you are using those arrays exclusively for searching, and since they have unique entries, a set is better suited for it
fun ItemStack.isToolOrWeapon(): Boolean {
val name = this.type.name
return when {
name.contains("SWORD") -> true
name.contains("AXE") -> true
name.contains("SHOVEL") -> true
name.contains("BOW") && this.type != Material.BOWL -> true
name.contains("HOE") -> true
else -> false
}
}```
no I'm not, i'm using them to create the sets
then ignore everything I have just said
do fire ticks accumulate or do they get clamped once the player isnt actively in a fire source (fire, lava, etc)
π
lol
tridents
EnchantmentTarget.TRIDENT
shears
shears
oh fukc U
I don't think shears are typically used as tools tho
wool?
or leaves
Vehicle Event Help
thanks
it's like a pickaxe for leaves / vines
I want to say the fire ticks are whatever value was set, if it was higher than the already set value.
and likelihood is that they don't matter enough to be targeted
fun ItemStack.isToolOrWeapon(): Boolean {
val name = this.type.name
return when {
name.contains("SWORD") -> true
name.contains("AXE") -> true
name.contains("SHOVEL") -> true
name.contains("BOW") && this.type != Material.BOWL -> true
name.contains("HOE") -> true
name.contains("TRIDENT") -> true
name.contains("SHEARS") -> true
name.contains("FISHING_ROD") -> true
name.contains("FLINT_AND_STEEL") -> true
else -> false
}
}```
okay, guess this covers all the tools/weapons
do gotta include compass and clock
does compass have durability?
and lead and nametag..
no
I was just thinking for my use case, while my method is generally checking for tools and weapons
changed my method to isToolOrWeaponWithDurability(), bit long, but explains what it does lol
is there anything with durability except armor / elytra that is NOT a tool or weapon?
anvils :smug:
well, I'm after all tools and weapons that has durability
blocks don't count in this case
ik
but anvils are blocks π
and they don't really have durability
i mean they do break after enough uses
yeah sure but they don't have getDurability
whoa that font lol
purebdcraft is my texturepack indeed
not me π
The bomb
comic sans ftw
Could you use the Damageable interface?
one of my favorite packs on god
lmfao!
god?
purebd and faithful 32x π
shit now I forgot the default font
I use 256 iirc
\
Segoe UI yeah
Hello, I have the following SQL code:
private void increaseBy(Player player, String column, int amount)
{
try(PreparedStatement statement = this.dataSource.getConnection().prepareStatement("UPDATE blocks SET " + column + " = " + column + "+1 WHERE uuid = " + player.getUniqueId().toString()))
{
statement.executeUpdate();
}
catch(SQLException exception)
{
exception.printStackTrace();
}
}```
but when I run it I get the following error: `com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column '6fec1162' in 'where clause'`
What did I do wrong?
idk
ahh, probably because I use Material UI theme
set column = column = 1?
I want to increase the value of it by 1
nah i run vanilla intellij theme and its segoe ui for me
I'm new to SQL
(also use the prepared statement properly)
oh wait, you were talking about the default font, I was talking about the default EDITOR font
I know, it's the first time I use SQL in java, this isn't my main problem rn
why do you even have amount here? you're not using it... also iirc you can do column += amount in SQL
I know sql.....
i need a ?learnsql, ive put it off for a long time
oh! those are different lol, didn't even strike me
yeah but it makes sense, editor font would look reaaaally ugly in the UI lmao
but when I run it I get the following error: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column '6fec1162' in 'where clause'
are you sure? I mean no offense, but this is an SQL error, not a Java error
yeah lol
I would suggest using the prepared statement properly and setting the strings
I just never bothered with the fonts π
I can't currently see why else it's broken
yes, why is it creating random letters?
i like fira mono font
I don't understand
Thatβs what they are doing
@echo granite this as well! just Google for prepared statements in Java, and you'll find guides
yeah I know
Baeldung probably have a few
what doesnt that websiteh ave
Free Peanuts
im allergic
Well more for me then
one mans trash is another mans treasure
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column '6fec1162' in 'where clause'
also this looks like it's looking for a column by the name of the first part of your uuid (first part being letters/number until first-)
Oh, it might be because you didn't surround the UUID in quotes (which you wouldn't need to if you use the prep statement properly)
that is why
thank you very much!
how can you whitelist an offline player?
Yep
ah, getofflineplayer
is it worth using hasPotionEffect or should i just do a null check against the effect i want to test for
since i then want to use the result from getPotionEffect
i would use hasPotionEffect if i wont use the potion
the jvm should allow primitives in type specifiers only when defaults are allowed
???
Map<String, int; 4> mapOfInts = new HashMap<>();
instead of get() returning null
it would be the default specified
in this case 4
does the map have default values like that??????
but not primitives
wtf
cmon im genius
never saw that
a
computeIfAbsent / putIfAbsent instead of get tbh
actually it should use ':'
getOrDefault
but they arent primitives
Map<String, int : 4> mapOfInts = new HashMap<>();
not primitives
useful if u dont want to make a key value pair ig
combattually transmitted diseases are a go @young knoll
minecraft stds
Hunger hands sounds like a good band name
lol
i couldnt think of a name for the hot hands so i just called it human torch, like the fantastic 4 guy
oh my god wait
hot hands
Probably obvious to many but TIL you can attach to your server process, set breakpoints and then watch them trigger as you do stuff in game (https://stackoverflow.com/questions/52947783/run-jar-in-debug-mode-from-terminal)
Nice, must've missed them, very useful feature!
i always use that
@quaint mantle that would be tricky given how the JVM handles generics, right now the class is just compiled as if it was Object, versus how C++ does it where for each template type a different version of the class is compiled
fuck Gradle, honestly