#help-development
1 messages · Page 1267 of 1
the server knows nothing about the 3d-models
also don't cross-post
sry
the server knows what model an item is using, you can get it by using ItemMeta#getItemModel (or checking the custom model data in older versions)
Hello can someone help me fix that dump:
https://paste.md-5.net/qajonuwume.md
I don't understand why the server was stuck more than 10s on my createFromConfigSection method. I can't even reproduce the crash 😦
I'm a little desperate not to find it. We have a server with quite a few players. The crashes are annoying.
I've already added 3D weapons to my server using ItemsAdder, but I'm wondering how to assign special abilities to those weapons.
maybe, whilite (true)?
Im never using while(true) in my plugins
i think while (isAnyone) and isAnyone is always true
ItemsAdder is a premium plugin, you'll have better luck asking for suppport on their discord server as I doubt anyone here knows anything about how to configure ItemsAdder
First of all Am I wrong? We agree that the dump shows that the server crashed because it stayed too long in the createFromConfigSection method right ?
check plugin page, or, for help, contact with plugin developer (or plugin community)
hey guys
?whereami
guys, thank for the support very good idea
This is a help-development channel what?
I will do that
the isssue doesn't come from paper this is related to one of my plugin dev using the spigot api
plugin making, not configuring, i think
there's no guarantee that it was stuck for 5 seconds on that particular method
the stack trace is just a snapshot of what was happening at that instant
oh ok damn so its more complicated to find the issue of my plugin rip
unless the stack repeats multiple times, it probably isn't the issue
that doesn't really mean much since Paper could've changed something in order to cause this for all we know, though I am not specifically saying that is the case. General rule of thumb is to ask for support on their discord server if you're running their platform
when i need to execute something after 1 hour should i check every second or so, if the time has passed, and then do it? i think setting a task for 1 hour may result in it being executed too early or too late
So maybe it's not an error from one of my plugins ?
are ur ask is equals with "how to schedule task"?
tlantisLibs-1.0.9.jar//com.nours.atlantisLibs.tasks.DistributedTask.run(DistributedTask.java:89)
this occurs in every stack trace
so whoever is responsible for this piece of code or the code run by this piece of code, is probably responsible for the issue
whether that's you or not idk
CMILib1.5.4.3.jar//net.Zrips.CMILib.GUI.GUIListener.clearIconItems(GUIListener.java:49)
it could also be interference with existing plugins doing something moderately dumb that you're exacerbating
here it seems like cmi scans through every opened inventory and scans the nbt for something something
and you seem to be opening a lot of inventories with a lot of heavy-nbt items
are you set the max and mix RAM for the server?
i have an a similar problem, when i didn't install RAM specifically
SuperiorSkyblock2-2025.1.jar//com.bgsoftware.superiorskyblock.listener.MenusListener.onInventoryCloseDupePatch(MenusListener.java:54)
there's also this which runs on inventory events and appears to be allocating many exceptions and filling stack traces through some cache library
com.google.common.cache.CacheLoader$InvalidCacheLoadException.<init>(CacheLoader.java:246)
the listeners from different plugins also seem to be interchanging in between stack traces, indicating that more than one, possibly more than intended, inventories are being opened
it could also be some sort of memory bandwidth/ram issue yes, maybe try running a memory test
the one from superiorskyblock seems the most responsible, since allocating stack traces rapidly is super expensive
and that looks like an outright programmer error
total tilted
Does it still update itself but never remove the old version
In what sense?
It downloaded a new jar into the plugins folder but never removed the old one
what CMI is doing is pretty inefficient too, they're not caching their reflection
xd
Spigot won’t load multiple plugins with the same name, so it would just always load the old version anyway
Not exactly the most useful auto-updater
is it making cmi auto updater?))
imagine if there was an "update" directory or something like that where you could put updates and the server would swap them in on the next restart
https://github.com/Zrips/CMILib/blob/main/src/main/java/net/Zrips/CMILib/NBT/CMINBT.java#L1542-L1572 this is what ends up getting called for every CMINBT item created
sweet dream
just to look for a single string on the nbt, could've just been PDC but welp
CMI 🚮
I am honestly amazed at the quality of the code (not in a good way), wasn't Zrips the same dude who made the Jobs plugin?
btw. if replace an existing jar plugin, it can make a errors especially when server is shutting down
(tried)
well of course, that's why the update folder exists, so plugins don't try to do that
its just a wet dream
Hey popular things don’t have to have good code
See: Every videogame ever
popular think must just work
Someone help me, I'm new to this.
https://imgur.com/ilgS5w3
can you have a command that doesnt have a name, just takes / to open? If you cant assign it as a literal command, how can you listen for it?
what kind of command wouldnt be named
yeah, I also wonder lol
I do wonder whether you can do that without doing something hack-ish like listening for the chat event instead of the command event/registering the command as usual
Did you reload maven
have you tried just registering the command like that
How do you do that? haha
how would u have a nil named command in plugin.yml?
i imagine u would have to reflectively add it to the command map
Particle.REDSTONE
for some reason redstone doesnt exist, I am on 1.21.4
I'm using this one <dependency> <groupId>com.github.placeholderapi</groupId> <artifactId>placeholderapi</artifactId> <version>2.11.6</version> <scope>provided</scope> </dependency> </dependencies> </project> and it still doesn't work I took it from "https://mvnrepository.com/artifact/com.github.placeholderapi/placeholderapi/2.11.6"
DUST
oh so dust is just redstone now?
I already reloaded Maven and still nothing.
commands: {"": {}}
could possibly work
commands:
"":
description: "empty command test"
if you like new lines
No, dust is a customizable particle iirc
wrong way around
mmm ok
guys I got a problem with my paginator class.. specifcally with flushing and refilling the inventory when switching pages
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
every page is basically the first page
the outputs are correct:
only about 7 players on the second page should be shown
but the first page is always there
the reason I know it's the itemstacks not getting removed correctly is because the arrow on the left side (previous page) is added on the first time you enter the 2nd page but does not get removed when going back on first page
I tried inventory.clear() and creating a new inventory but nothing worked..
I could prob optimize this but this is how I handle pagination on my (old) menu systme
public void forceUpdate(BaseMenu menu, int page) {
int startIdx = (page - 1) * slots.size();
int endIdx = startIdx + slots.size();
for (int index = startIdx; index < endIdx; index++) {
int slot = slots.get(index - startIdx);
if (index >= elements.size()) {
menu.setElement(slot, emptyElement);
} else {
menu.setElement(slot, elements.get(index));
}
}
}
hope this helps :)
tbf it's pretty much how they manage it lol
the issue doesn't seem to be with the pagination itself but something about the inventory instances or so I'd like to believe since the issue isn't immediately clear from the given code
perhaps reusing the inventory instance or whatever the InventoryGui#createInventory method does is causing the inventory to not be properly updated, but I wouldn't be able to say without the whole thing
I've been thrown for a loop forever now
but I fond the core issue
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
in GuiManager.handleOpen if (handler != null) is false
the problem only happens when going to page 2, from my Paginator.nextPage()
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
on line 107. manager.openGUI(this, player);
this should be correct
yet the handler which is a PlayersToInvite instance extending paginator
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
hope this makes it a little bit clearer?
the core issue is that InventoryGui.decorate on page 2 doesnt get called therefor no items show up and page two registers no events and shows no items
rather than adding so many debug messages, just use a debugger
how do I use one? <.<
?debug
create a debug configuration in intellij, add the params it tells you to add in the configuration popup to your test server's startup script and add breakpoints where the issue lies
also set timeout-time to 999 or something in spigot.yml as well as player-idle-timeout to some big number in server.properties
that way when the breakpoint suspends the server, it doesn't make a thread dump nor kicks the player due to inactivity
which kind of configuration?
remote jvm debug
that should be correct?
yeah, copy the command line arguments for remote JVM and paste it in your start.bat or whatever you use to start your test server
ah, if you have a configuration to start the server, just hit the debug button on IJ
bruh
you don't need the remote JVM debug for that
now put a breakpoint in the nextPage method and step through it to see where it breaks
if you're running paper you can use -Ddisable.watchdog=true to avoid getting watchdog thread dumps btw
in VM options?
yes
how did you say I can avoid being timed out?
increase player-idle-timeout in server.properties to some big number
ah okay
if you're fancy, you can also get Jetbrains Runtime and run your configuration with it, and also add the -XX:+AllowEnhancedClassRedefinition VM option so that you can do enhanced hotswapping (means you don't have to reload/restart to make changes to your code)
well, as long as it is code that doesn't require of any initialization hooks/events, anyway. You'd still have to restart if you're changing something that's already initialized like at world init or onEnable
gotta install the TimeoutOut mod
was that always a thing
yes
I remember just setting idle timeout and not getting kicked out before, though I might just be misremembering lol
client (and server) has a ReadTimeoutHandler(30s) in the netty pipeline
Isn’t idle timeout infinite by default
why is this happening now?
I don't think I did anything different
my breakpoints just stopped working suddenly
ah wait
I forgot to rebuild prolly
Okay I found the issue
but I still have no idea why it's behaving like that
so...
https://pastebin.com/C06gdF4B
line 100 manager.openGUI(this, player);
This should pass the InventoryGui instance
https://pastebin.com/8wGT8Zev
line 27 this.activeInventories.put(inventory, handler); This for some reason does not get the handler and save it
because the logger on the next line logs the <K, V> pair to be <PlayerToInviteInv, null>
so handler is null here.. even though when I debugged it, it is there
not null
is the problem with the types or smth?
😪 im too tired to even type, ima go sleep its past 3am
should i just give up 🙏
I'm creating a very simple sumo 1v1 plugin
how can i detect when someone falls in water ?
I'm looking for a very performance friendly approach, so im not planning to use PlayerMoveEvent
cant u just use command blocks to detect the player reaching a certain y level which triggers a command, which could be from the plugin
take this with a pinch of salt, i started learning java last week
use 2 command blocks
1st
/scoreboard objectives add yCheck dummy
2nd
make a repeating command block with
execute as @a store result score @s yCheck run data get entity @s Pos[1] 1
3rd - chain command block on the repeating one
execute as @a[scores={yCheck=..50}] run <your_command, eg trigger fellInWater which will be a command in your plugin that will possibly reset the match or change the score and reset player positions>
and obviously when u have a repeating command block u do gamerule commandblockoutput false so it doesnt clog ur console
nah it's like 15 or 30s pretty sure
Man, im going for a task
thank you tho
isnt it simpler to do it based on a y level check rather than falling in water?
im freelancing, the client specifically wants the "fall in water" part
do not use a command block for ur client bro 💀
60s
i dont really see a //good// way to do this WITHOUT using that event tbh
unless u use a Task that checks at a lower frequency than PlayerMove
There's nothing wrong w PlayerMoveEvent
as long as you filter stuff out
Minigames having a loop task yikes
We usually just have a task scheduler per game instance and run a million tasks there for sep things
Makes the code cleaner and stuff
Youd be surprised how efficient it is.
may i ask if anyone know how to randomly sort the playernames on the tablist 🙂
Player#setPlayerListOrder or sth
shuffle the online players and then set the order to their idx in the shuffled list
there is no stuff like it unfortunately 😦
in 1.16.5
why would you ever use 1.16.5
that's like one of the worst possible versions you can choose to use
i am developing with a bukkit and forge hybrid core 🙂
hating on people's decisions? wtf
they cant work around what a modpack is built on
just any nms way
no idea
the hybrid worked likewise the spigot 🙂
🙂
How do I disable xaero's minimap?
I've tried
player.sendMessage("§f§a§i§r§x§a§e§r§o"); when they join based on https://www.reddit.com/r/feedthebeast/comments/oq9qgu/is_there_a_known_way_to_disable_xaeros_minimap_on/
and
PotionEffectType minimapEffect =
PotionEffectType.getByName("xaerominimap:no_minimap");
PotionEffect effect = new PotionEffect(minimapEffect, Integer.MAX_VALUE, 0, false, false, false);
player.addPotionEffect(effect);
and
NamespacedKey effectKey = NamespacedKey.fromString("xaerominimap:no_minimap");
PotionEffectType effectType = Registry.EFFECT.get(effectKey);
PotionEffect effect = new PotionEffect(effectType, Integer.MAX_VALUE, 0, false, false, false);
player.addPotionEffect(effect);
based on https://modrinth.com/mod/xaeros-minimap#:~:text=Potion effects to control the usage of the minimap
first one just doesn't work, for the 2nd and 3rd, effecttype ends up as null
its a client mod adding potion effects on the client side
they do not exist on the server side
?
it says
Potion effects to control the usage of the minimap or some of its features for the players on your server/map. The following potion effects exist as of writing this: xaerominimap:no_minimap, xaerominimap:no_entity_radar, xaerominimap:no_waypoints, xaerominimap:no_cave_maps. The effects are of the neutral type by default, but you can also specify a harmful type by appending _harmful to the end of the effect ID, for example xaerominimap:no_entity_radar_harmful.
Yea
the mod adds these potion effects to the game
you are not running this mod on spigot tho
it is only running on the client
the server does not know about these potion effects
what about this?
there has to be some way to disable it, as I've seen other servers do it
idk why the message would not work ¯_(ツ)_/¯
might want to delay sending it by a tick or something
It still doesn't work
Well, spigot might be trying to Parse the message then,
Which won't end well for you given most of these colour codes don't exist
brh
thanks!
Omg it tellraw commands it 
This account is already verified!
why is my handler not null but also doesn't get inserted into the map?
FloorIsLava.getInstance().getPluginLogger().info("Registering inventory: " + inventory + ", Handler: " + handler);
if (handler == null) {
FloorIsLava.getInstance().getPluginLogger().warning("Handler is null for inventory: " + inventory);
return;
}
this.activeInventories.put(inventory, handler);
FloorIsLava.getInstance().getPluginLogger().info("Active inventories: " + Arrays.toString(this.activeInventories.keySet().toArray()));
}```
this is so annoying
have no idea what's wrong
other inventories work
its a specific gui that doesnt work
what doi you mean it doesn't get inserted to the map? The logger clearly shows it is in the Set
only the key
it should read the key and value
on other inventories it shows
[11:37:35 INFO]: [FloorIsLava] Active inventories: [org.bukkit.craftbukkit.inventory.CraftInventoryCustom@68e72816, org.bukkit.craftbukkit.inventory.CraftInventoryCustom@2347a944]```
you are only reading the KeySet
the paste shows two inventories, not a key and value
you are using Inventory as key?
you are logging an array of keys, not a key and value pair
it's most likely just the hash changing when you reopen that inventory, since a different Inventory instance was created when you opened the Inventory again
yes. I'm supposed to find the corresponding class for each inventor
well
class instance
but this makes it so that the mapped inventories get decroated properlly based on their class
but page two of PlayersToInviteInv doesnt get mapped correctly
That would be an issue with yor PlayersToInviteInv, not the inventory key map
okay now im logging the entry set
[11:50:57 INFO]: [FloorIsLava] Registering inventory: org.bukkit.craftbukkit.inventory.CraftInventoryCustom@17e340c, Handler: com.bluenova.floorislava.util.gui.inventories.lobby.LobbyInv@36e488a4
[11:50:57 INFO]: [FloorIsLava] Active inventories: [org.bukkit.craftbukkit.inventory.CraftInventoryCustom@17e340c=com.bluenova.floorislava.util.gui.inventories.lobby.LobbyInv@36e488a4, org.bukkit.craftbukkit.inventory.CraftInventoryCustom@42e61815=com.bluenova.floorislava.util.gui.inventories.lobby.LobbyInv@12658685]
```this is a healthy key value
[11:51:40 INFO]: [FloorIsLava] Active inventories: [org.bukkit.craftbukkit.inventory.CraftInventoryCustom@77abc32=com.bluenova.floorislava.util.gui.inventories.util.PlayersToInviteInv@62d3b97c]```this is the broken one (paginator page 2)
paginator is an abstract class allows me to make paginated inventories based on an Iteratable (or however its spelled)
I think its more an issue with my paginator class but I tried looking there.. idk why it wont work
boolean condition = (itemList != null && (currentPage + 1) * itemsPerPage < itemList.size());
if (condition) {
currentPage++;
updateInventoryContent();
GuiManager manager = FloorIsLava.getInstance().getGuiManager();
FloorIsLava.getInstance().getPluginLogger().info("Next page clicked, THIS:" + this);
FloorIsLava.getInstance().getPluginLogger().info("Next page clicked, THIS Inventory:" + this.getInventory());
manager.openGUI(this, player);
}
}```
Logs seem fine here too
```[11:57:36 INFO]: [FloorIsLava] Next page clicked, THIS:com.bluenova.floorislava.util.gui.inventories.util.PlayersToInviteInv@5978556a
[11:57:36 INFO]: [FloorIsLava] Next page clicked, THIS Inventory:org.bukkit.craftbukkit.inventory.CraftInventoryCustom@38c50690
[11:57:36 INFO]: [FloorIsLava] Registering inventory: org.bukkit.craftbukkit.inventory.CraftInventoryCustom@38c50690, Handler: com.bluenova.floorislava.util.gui.inventories.util.PlayersToInviteInv@5978556a
[11:57:36 INFO]: [FloorIsLava] Active inventories: [org.bukkit.craftbukkit.inventory.CraftInventoryCustom@38c50690=com.bluenova.floorislava.util.gui.inventories.util.PlayersToInviteInv@5978556a]```
what does openGUI do?
at this point it'd be easier to check if you put the thing on github so I can run it myself and check lol
[12:02:12 INFO]: [FloorIsLava] Active inventories: [org.bukkit.craftbukkit.inventory.CraftInventoryCustom@57e6908d=com.bluenova.floorislava.util.gui.inventories.util.PlayersToInviteInv@7ba36a8d]
[12:02:12 INFO]: [FloorIsLava] No handler found for inventory: org.bukkit.craftbukkit.inventory.CraftInventoryCustom@57e6908d
OMG WDYM NO HANDLER FOUND ITS RIGHT THEEREEEE
leme do that
it is most likely the hash code being different as I told you, but yeah
the hash code is the same, 57e6908d
that is the class's hash code, not the Inventory instance
huh.. okay..
huh I just pushed and it isnt showing me my gui branch
it's called feature/gui-system-framework
yeah, that one doesn't exist there
if you do it through the IDE often times it is just the annoying pre-commit hooks that it adds
just let it finish, don't wanna push a ref twice accidentally
okay done
also you need two players on a server at least
<.<
or you can just remove line 114 allOnlinePlayers.remove(player1); // Remove the player themselves
from LobbyInv
and you can test it solo
okay let me clone it
it's the most fun gamemode ull ever try (personal biased objectively correct opinion)
I don't think I've ever played floor is lava gamemode lol
isn't it pretty much like tnt run
mine is different
every game is a random vanilla generated plot and sometimes you get resources and sometimes they're scarce
its my lifes work
Hopefully the versions of the plug-ins you have in the tmp-plugins folder work properly with 1.21.5 or I’ll have to go dependency hunting lol
Wait, is your plug-in paper-only
Either that or you didn’t shade in adventure platform
I thought I only needed to do that if Im on spigot
I still gotta shade it if spigot servers wanna play?
Well, yes
The plug-in seems to work still though logging is probably borked so I am gonna ignore that for now
yeah i gotta clean that lmao
Okay no it seems I got to fix that since the commands aren’t doing anything lol
I’ll just run it with paper for now
Though you also seem to be depending on paper-api instead of Spigot’s, that’s fine if you don’t want to support Spigot but if you plan to publish it in SpigotMC, then you’re probably gonna want to do that
lmao yea i know now
It’s harder now that paper has hard-forked to support both platforms, but just depending on spigot-api so that you don’t accidentally use paper-specific API still works
so all i need to do is reshade adventure api back again?
You’ll want to shade adventure-platform-bukkit or whatever it is called if you want to use adventure on Spigot
Though that means you’ll have to wrap audiences and what not on Paper too unless you create a separate module just for handling that
ugh
It is very annoying, yeah
i was so happy to remove that when i switched to paper
Hi, is there an API / a website to get all Minecraft versions released in a json, txt or a format like this ?
Does someone know why this doesn't show the hurt animation (red outline on player)?
PacketContainer status = protocolManager.createPacket(PacketType.Play.Server.ENTITY_STATUS);
status.getIntegers().writeSafely(0, victim.getEntityId());
status.getBytes() .writeSafely(0, (byte)2);
protocolManager.sendServerPacket(victim, status);
for (Entity e : victim.getNearbyEntities(10, 10, 10)) {
if (e instanceof Player p) {
protocolManager.sendServerPacket(p, status);
}
}
}```
PAGINATOR paginator is my bane
byte 2 does nothing from the looks of minecraft.wiki
might need to send a damage packet
It causes a little knockback
I believe it's a correct code, it worked for 1.16.4
but somehow stopped working on 1.21.5
thats a lot of updates since then
OMFG
I DID IT
all I had to do was not reopen the gui from the gui manager.. so it's the same inventory but I change the contents
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
here is the new paginator
ull notice I simple just removed the openGui from nextPage and previous page functions
and call decorate instead
so a paginator is always one inventory that just clears and refills without closeing and opening a new inventory
which is annoying cuz I would've liked to add a page number in the inventory name
but i honestly will not complain right now. later I can revisit it and revamp it
omfgg
there we go. all my desired functionality
That method has been deprecated in Paper
I legit was on the brink of destroying everything and starting from the ground up
It’ll also open a new inventory so be warned
perfect thanks !!
https://minecraft.wiki/w/Java_Edition_protocol/Packets maybe try looking into Hurt Animation packet @valid basin
where do you guys publish your plugins?
what's the most popular platform? is it modrinth nowadays?
spigotmc?
spigotmc and modrinth personally
but there is more people looking on spigotmc for plugins
everywhere
spigotmc, hangar, modrinth, planetminecraft, curseforge
so i meant to reply to This message
wow ok so my plugin just prolly doesnt work that's why it sucks
I'm still alive for anyone worrying.
woah
maybe, idk
that's your opinion x)
Does maven not let you have mutliple modules with the same artifact and group id?
If your graph looks like it has "sawtooths", then you are just fine.
yes that's how the GC works
Those sharp drops are the gc working.
yeah I thought so
Im currently working on an leaderboard system that will display the top 15 players with the most clicks ( clicks is an pdc value stored as an big int )
Somehow when I do /topclicks it doesnt spawn an armor stand and only Command executed will be logged
https://pastes.dev/9mb0nSXhG2 ( Command )
https://pastes.dev/1j6SH6rDZi ( Funcs )
Does "Before spawn" get logged ?
If not then you have problem with the value saving probably
And you're not doing PDC anywhere
You're never adding to the storage anywhere
So it will always be empty
Wait it's loading from file in the constructor mb
Still though that would require it to be in the config at startup which is an odd choice
Yeah it's not PDC
hm
Which is fine btw, I am just confused
Yea how do I get like an array with all pdc stores or like all data tho?
?pdc this is PDC
well not in what you showed
yea and like I said im rewriting it rn
why even mention it then, you're just confusing us
?jd-s
wait but do they
Doesn't look like it
then how could I even make an leaderboard?
Then file storage would be their best bet then.
I wonder if that could be a decent PR.
pr?
Or if it's even possible right now
manually open the player file :D
You just store the values in a different way.
You already have a file where it's being written to apparently, so just use that.
the thing is I dont I just store pdc values on the player and then modify them like I dont save them
That is not what your ClickDataStorage shows.
Where do you actually use PDC then?
I say: ignore PDC, store it all in the config file.
Save the config file every few minutes instead of on every update.
sqlite database instead of yaml
or your own data format*
Using yaml like you're doing will load the entire file in to memory which isn't ideal
Like I tried it before with the code I send up in the message from the start and I did it like 40% me 60% chatgpt and tried but it doesnt work and now I do realize that you cant acess offline players pdc data. And yes I got other like classes that add or remove clicks from an pdc value
But Idk how good its going to be if I like store all data in an file
but then again the data won't update when the player is offline right?
"chatgpt" ah
so that's not really required
😭
Yeah waay too many people rely on GPT or other AI nowadays
Ig I could make an leaderboard that only displays the top 15 players of clicks that are currently online
Don't need to.
You know what clicks people have when they quit so if they qual for the leaderboard or not
So you'd just store that in to the leaderboard
There is no need to loop every player every time to make the leaderboard
Just calculate what's changed
So when someone joins it will add thier clicks to an file and when someone leaves it will add them too but like they wont change till they rejoin? and then the leaderboard just updates like every minute sorting all data?
Using PDC for clicks is fine
Use a file for the leaderboard though
as for updating the leaderboard it can probably just be done in real time
Wouldn't be too expensive nor hard to do
(Just save the file every couple minutes)
Largest downside of doing it that way would be if a player for some reason has their clicks reset while on the leaderboard. Could be a bit of a problem finding replacement player on the leaderboard
Looking for tech admin, write in PM
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/
How do I modify the display name of an entity that has an specific tag?
What exactly are you struggling with ?
I want to change the name of an armorstand that has the tag clicks_lb
is the problem finding the entity, setting the name ?
Setting the name is literally just entity.setCustomName
no how do I find the entity via tag
well then ask that
I believe: use getEntities in World, use stream to filter by tag
Hey guys i have a question
is there a way on legacy versions like 1.8.8 to disable crop item natural drop when it gets in contact with water ?
listen to the BlockFromToEvent and check if the destination block is a crop and if so set it to air
you'd also have to listen to the block place or interact event when the water gets placed directly onto the crop ig
Thx I'll look into it 😄
you don't have to use packets to play the animation if that's what you're looking for
LivingEntity#playHurtAnimation exists
Oh nice, does it give the knockback to the player or it just shows the bobbing red hurt animation?
Hey @sly topaz (sorry for the ping) you wouldn’t happen to know about world gen do you? Just curious cuz I posted in the review thread and perhaps you’re more versed with the api and I’m still figuring how to integrate my obstacle generation
I am honestly not sure since it gives you a parameter for the direction of the hit as well
try it and see ig
I don't mind the ping, however I know next to nothing about world gen, at least in terms of the API
I'll check it out still, but I don't think I'd have any valuable input on it lol
probably helps if you ask what it is you are wanting to know
No. The hit angle correlates to the direction in which your screen tilts
(because yes, that tilt does depend on where the damage came from)
How the surface noise generation is done, Im currently using world edit to paste in objects post world gen
All that’s in the review thread btw
Ah no worries, just curious
you will need to look at Mojang code for the world generation
The game just does it in stages
First it builds the base shape, then it creates the surface (grass, dirt, etc) then it adds decorations on top of that (trees n shit)
yep using the seed to come up with variables that plug into the algo to generate stuff
Yeah I figured, my impl isn’t too awful, just integrated my internal course generation with chunk generators so at least I’m not crashing the server forcing block type changes to thousands of blocks kek
The decorations/obstacles still look a bit unnatural
I feel like I've seen that before about some golf course generation
That’d be me
Literally been stuck up on this aspect of the project for like 4 months
End goal: randomized but seeded course gen so you’ll never get bored playing a handful of courses, my physics are randomized a bit so you’ll never be able to just play a certain way on a certain course either so
Really just trying to emulate real life disc physics
Real life physics and play style rather, obviously you can’t throw the exact same way every single throw
Well i wanted the crop block not to break at all , so the water can just ignore it in its flow
or stop entirely if crops are infront of it
then you can just cancel the event instead of setting the crop to air
waterlogged state didn't exist back in 1.8.8 so you can't have crops inside of water but you can stop it from touching crops
tried that but still it pushes through the crop making it drop
what did you try
so basically
if next block is CROPS or even SOIL
event.setCancelled(true);
i also debugged
what is next block here
the debugging was weird:
current block : WATER
next block: STATIONARY WATER
So i was thinking of getting the block below the NEXT BLOCK
check if its SOIL or CROPS
but what did you use to get the next block
event.getToBlock
is there a way to mark an arrow and detect when that specific arrow or snowball hits another player?
maybe PDC?
PersistentDataContainer
its like the nbt api abstraction spigot provides
thats ofc one way
another way is to just store the entity in some reference
and then make sure the call .remove() on it onDisable, or whenever suitable and then once its removed u de-reference from it
in a minigame
how easy do you think that is?
its very easy
even when detecting a specific arrow being used?
holy shit I thought this was another person with an invisible pfp
lol
well u can ofc put it in a list/set/map or some collection also I suppose, maybe its smarter to use UUID or to go by entity id (integer) instead tho
huh okay. but thatÄs just for spawning, I wanna detect if I'm using a certain item.
which makes me now think of the obvious solution of checking wether or not the player is actually holding my custom item in order to tag the next entity being thrown
u wna make sure the player is holding the right item in order to then summon the right projectile entity?
yes.. or so I thought the easiest way is
I can make a snowball with custom lore and maybe check for the lore?
or is there a cleaner solution
u can use PDC on items maybe?
yeah ur right, does this run the risk of bloating data if I don't remove them properly?
na not rly
oh okay so its perfect
the data is just stored inside the custom item data component iirc
nice thankss
^^ nws
new world spigot
Ows
OVH 🙏
After hours and days of debuggings
I have achieved something incredible in a legacy version
An obsidian formation detecting algorithm.
by the combination of multiple events with the ability of detecting 99% of formed obsidian blocks from water and lava interactions.
Grats
Is there a clear cut way to obfuscate a client's coordinates without strictly teleporting them?
@alpine urchin you're the packet guy, perhaps you know?
wdym
Like, is there a way to change the player's coordinates, to show up as like 6969, 69, 6969, while they are really at 420, 69, 420?
without actually making them move to 6969, 69, 6969, is there a way to make it appear as though they are. like through their F3?
No, that's client sided, you cannot modify what the client sees
Pretty sure it's hard coded into the client
You could try packets
thats like how the server tps you
notice how if you lag, and move your position in f3 still changes
yeah, try packets, but I doubt it would work
He totally could it’d be quite the chore though
Well if the client is told at the start they are at X, the location will change according to X. He’d have to intercept the playermove packet before the server does tho or the client might slingshot all around. He’d also maybe have to play around with the chunksending code idk
Perhaps, but it's not guaranteed to work, I think it won't, due to the rendering also dependant on x y and z
Exactly he’d probably need quite a bit of packet manipulation
Fork the jar at that point lol
the client only gets initial coords from the server when they spawn in
after that, its all on the client and its the client that tells the server where its moving to
right so could you send bogus coords?
yes but the client will still try to render what coords it gets so you will have a buggy mess
probably, but you would have a weird desync in positioning lol
Wasnt there some whole base on 2b2t that used a proxy to offset user coordinates?
that was all serverside
idk, I don't follow what groups like 2b2t or others do
I just go by what I know of the source code
the problem you will encounter is if the client or the server realizes the coords are messed up
and either one tries to correct it
end result player gets disconnected
but what would be the purpose of spoofing coords though?
Could a resource pack modify the debug screen?
sure, you can even send reduced debug info. But it doesn't completely remove the information rather just obscures it from easy access. If you have a mod you would still be able to see that info
Yeah, I'm not sure he can do anything about it other than creating a custom client
but it would help though to know why spoofing coordinates would be needed
or what the goal is of it
like if you wanted to confuse players as in their compass can't be relied on, then you could just change up the region file ordering instead
this would cause chunks to load in an area that they are not originally from
thus changing the landscape and making it appear they are not at the right coords when really they are
But then internally wouldn't the chunks save in that position
Idk, don't know why he wants to spoof f3 position
no, coords for the chunks I don't recall are saved as they are saved in the region file as region files have their own coordinates
yes chunk coordinates
no
region files have their own coords in the name of the region file
which stores 1024 chunks
Really?
yes, from chunk coord you can figure out which region file it belongs to
hi frosty ty for lunch
by the same process in how you get chunk coord from a position coord
It works exactly the same way
Any idea how I can set a comparator to on and subtract mode via NMS
Because it reads a custom inventory fullness
no bukkit?
Basically, I've got it to turn on and output a signal, but subtract mode, I got no idea
NMS is required to change the nbt tag of the tile entity (not block) "outputSignal"
them being tile entities hm
Output signal is part of the tile entity but mode is a block state
yeah, I tried setting mode to subtract, but then it gets turned off
it needs to be on and subtract
So this works for outputting a signal atm:
WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle();
BlockPosition blockPosition = new BlockPosition(block.getX(), block.getY(), block.getZ());
IBlockData iBlockData = worldServer.getType(blockPosition);
net.minecraft.server.v1_8_R3.Block b = iBlockData.getBlock();
if (signalStrength > 0) {
worldServer.setTypeAndData(blockPosition, iBlockData.set(BlockRedstoneComparator.POWERED, true), 3);
worldServer.b(blockPosition, blockPosition);
worldServer.a(blockPosition, b, Integer.MAX_VALUE);
} else {
worldServer.setTypeAndData(blockPosition, iBlockData.set(BlockRedstoneComparator.POWERED, false), 3);
worldServer.b(blockPosition, blockPosition);
worldServer.a(blockPosition, b, 0);
}
TileEntityComparator tileEntityComparator = (TileEntityComparator) worldServer.getTileEntity(blockPosition);
NBTTagCompound tag = new NBTTagCompound();
tileEntityComparator.b(tag);
int signal = tag.getInt("OutputSignal");
if (signal != signalStrength) {
tag.setDouble("OutputSignal", signalStrength);
tileEntityComparator.a(tag);
worldServer.update(blockPosition, b);
I tried using IBlockData for both enum POWERED and SUBTRACT
doesn't work :/
that code looks a lot like uh
Went through the NMS classes but found nothing that can help :/
no mappings for 1.8 either makes it difficult
uh
?mappings
Compare different mappings with this website: https://mappings.dev/
I can reverse engineer the mappings fairly well
its one of those things highly requested all the time in here so someone made a link to a nice website for it
Well give that person a raise!
pretty sure you just need to call k with an updated blockstate
here's a somewhat remapped version of 1.8
oop didn't rename those flags
Which is precisely how the interact method works
but subtract isn't done there, and I am manually modifiying the comparator tile entity as you saw
the tile isn't enough
Subtraction is just an operation that runs to calculate signal strength
basically goes a bit like this
Mode == SUBTRACT ? max(getInputSignal(...) - getAlternateSignal(...), 0) : getInputSignal(...)
Specifically
And that's called on refreshOutputState
You can just pass the block data on the method you're calling and it'll update and update the tile entity, not the other way around
Let me try that way then, thanks for the info
I have an issue with my gui
the slots in the players own inventory share the mapping of the slots inside my gui inventory
as if the button mapping is reflected onto the player's inventory
these buttons shown here are the spots where clicking inside the player's inv does the same bahvior as the button in the custom gui
hope that makes sense.. I saw a solution to this before but I totally forgot what it was
because I was yet to run into the issue myself
ah okay easy fix, just make sure clickEvent.getSlot() == clickEvent.getRawSlot()
help spigot nms get world ID
how can I convert an entities' NMS info into Bukkit, are there any existing helper functions for that?
Like converting a blockpos into location, etc
believe there is in the server code, CraftBukkit.toLocation or something like that, same with entities. Just have to look
been a while since I messed with the server code and I don't have it up at the moment
sounds like a plan
this isn't google
What's the best way to use hex colors in the nametag of an player?
Why was it decided to support Hex-Colors everywhere so easily, except in Nametags ._.

It's just the legacy team system
It doesn't support any more than the 16 legacy named colours
It also uses player names and stringified entity UUIDs, so...
I would have used NTE now, but it hasn't been updated since 1.20. Then I'll probably have to use NMS or find another API xd
NTE?
nametagedit
Hi, how can I glow player for specific player? I mean only player X see glowing player Y and the other way
teams or packets
Player#sendPotionEffectChange
Nice, I didn't know you could now do individual effects per player
do I need to use it in some runnable to update every tick, or is it like normal effect which I can apply one time?
just a normal effect
Sucks to be on 1.20.1 then
Is there any translator for remapped class names and not remapped? For example what is eqivalent of EntityPlayer
Compare different mappings with this website: https://mappings.dev/
?nms to auto map
Yes i know that, but i just have nms names and converting to remapped is pain in the ass
yes
I am scared of this 1.21.4 version fr
it's amazing
arent spigot mappings the same as paper mappings?
or are you talking about smth else
thought they need to be in order for paper and spigot to work interchangeably
PacketPlayOutNamedEntitySpawn
What happend to this packet?
Most likely the name changed
No
Spigot has its own mappings plus mojmaps whereas paper only uses mojmaps
?mappings
Compare different mappings with this website: https://mappings.dev/
Yes i know this
Problem is it disapeard
And what i am asking is if it's got replaced? No need for that?
I thought there was a section in wiki that had the name changes listed
Microsoft could care more about us developers :>
I can’t find it so either I’m full of shit or not looking in the right place
What revision version is 1.21.4 it's R3?
it was removed in 1.20.2 and is now just PacketPlayOutSpawnEntity
Why the fuck it requires me to put 2 entities in costructor?
don't ask me, it is basically the same packet as the one you were asking about, just the one you asked about was a stripped down version.
I need to shade in adventure api if I want my plugin to work with spigot servers.
That I know how to do.
But I was told I also need to make wrappers around my MiniMessage components. what does that mean?
a wrapper is just a class that wraps the object
IE, making a player wrapper for example your player class would just have the player object as part of the contructor and you would just add your information in that class you wanted to be part of it, etc etc. Nothing fancy really
and then change the mappings imported in all of the classes that use Player?
but do I need to do this with every audience that my plgin uses? aka lore, and inventory and all that?
what? why would you need to change mappings?
I mean like.. instead of import bukkit.Player; or wtvr it is it would be import wrapperPlayer.Player;
a wrapper doesn't change how the object functions, rather just makes it easier to access and add information without changing the base object. As for using it elsewhere you can use the base object still just it wouldn't include the additional info from your wrapper class.
and which you want to use would depend which you need. However ideally you would just use your wrapper object everywhere to keep it clean
@somber scarab do you just want to store some extra data inside a Player obj?
depends if you do an instanceof check though :P
I want my paper plugin to use adventure api even if user is running spigot
oh that won't work
Fuck adventure api
I did it before..
unless you re-implement paper's player object and forward it to spigot's
well wrapper objects are never instances of whatever you are wrapping, otherwise defeats the purpose of said things
I mean you may have some filtering applied on the wrapper before passing it to the object
I jsut forgot how to do it again xd
In Adventure api there is something called LegacyCompoentSerializer.
Pass as argument always a Component and check if engine is paper. If paper send component, if not use LegacyCompoentSerializer and send string
does paper not render LegacyComponents? why couldn't I just seralize everything?
Just use adventure-platform-bukkit
Handles everything for you
public static Audience audience(Player player) {
if (isUsingPaper) {
return (Audience) player;
} else {
return bukkitAudiences.player(player);
}
}
Group group = api.getGroupManager().getGroup("duke");
if (group == null) {
player.sendMessage(ChatColor.RED + " group does not exist!");
return;
}
api.getUserManager().modifyUser(player.getUniqueId(), (User user) -> {
// Create a node to add to the player.
Node node = InheritanceNode.builder(group).build();
// Add the node to the user.
user.data().add(node);
targetPlayer.sendMessage(ChatColor.GREEN + "You have been promoted to Duke. " +
"You can now add, remove, and banish players, as well as access the kingdom store.");
player.sendMessage(ChatColor.GREEN + "Player has been successfully promoted.");
});
Yo quick question for those with LuckPerms API experience, I'm trying to do a group update here to group.duke
But after I run this, I get the success dialogue but running /lp info on my target player shows that they have not changed groups
any help?
stupid question, if I run a paper server.. then I switch the jar to spigot with the same server files.. could it work?
so I can choose on what platform I want to run my server and change between them for testing
if you're using paper specific functionality, no...
well that's the point.. I wanna make sure my plugin works on spigot as well
then develop it on spigot
@blazing ocean even after the hard fork, paper still claims it can run spigot plugins yeah?
Yea as long as you're not using any API added after the hardfork
So then yeah just make a module for paper specific functionality and write the rest with spigot
Not for me, nova
soooo I added adventure-bukkit-adapter and shaded it in...
and I added both of these in my main class
public void onEnable(){
this.adventure = BukkitAudiences.create(this);```
``` public @NonNull BukkitAudiences adventure() {
if(this.adventure == null) {
throw new IllegalStateException("Tried to access Adventure when the plugin was disabled!");
}
return this.adventure;
}```
okay
now whenever I need an Adventure Player for example
do main.getInstace().adventure().Player
I'd just do this
?
where do I get bukkitAudence from?
also I don't just need a player from adventure
What are all the possible reasons for one player not appearing for another specific players (like being in /vanish, but still appearing on tab)?
do I check for paper using this?
isUsingPaper = Bukkit.getServer().getClass().getPackage().getName().contains("paper");
where i can download bungeecord for 1.21.1
https://ci.md-5.net/job/BungeeCord/1938/ this is not working
?notworking
"Does not working" is a useless statement. Please describe what exactly is not working, what you expect it to do, and what actually happens. If you get any console errors, also ?paste the entire stacktrace.
no, check if the class io.papermc.paper.adventure.PaperAdventure exists
i downlaoad https://ci.md-5.net/job/BungeeCord/1938/ from this and i dont have it
paper does not move everything to their packages lol
anyone help?
Don't have what
bungeecord
You downloaded Bungeecord but don't have Bungeecord
i put in plugins
???
yes
Bungeecord is not a plugin
where i need to put it
do u think I should switch back my development env to spigot?
If you want to have your plugin work on spigot, you'll have to use spigot...
spigot plugins will work on paper
okay yeah so I'll have to switch back
I use NMS to set the prefix and suffix, the hexcolor also works there, but the player name remains white. Is it even possible to change the player name color to a hex color?
not without a text display
;-:
so what do I do with all these again?
public static final MiniMessage miniMessage = MiniMessage.miniMessage();
you also shade mini message
I shaded in adventure
<pattern>net.kyori.adventure</pattern>
<shadedPattern>com.bluenova.floorislava.libs.adventure</shadedPattern>
</relocation>```
adventure-platform isn't mini message
weird.. before the last merge when I switched to paper, I didnt need to shade in MiniMessages and it worked
ahhh as a dependancy
mb
okay perfect that solves that
another thing is my TagResolvers
oh now I can jsut import them
sickk
You don’t even need NMS to do this btw, like rad said we get text displays through the api and are easier to work with anyway
oops
back to square 1
so How did I make items and Inventories format their text as well?
if I am using spigot adventure api

This basically
use the legacy serialiser
?img
Can't send images? That's because you're not verified! Use !verify to complete verification.
Alternatively, you can upload screenshots to any image hosting site and share the link.
Here's some screenshot utilities that you can use to upload images.
Lightshot: https://prnt.sc
Imgur: https://imgur.com/upload
Flameshot: https://flameshot.org
#1100941063058894868 is the place for code reviews. Remember to read the pinned message!
aight thx
Thank you
I don't think i can do better tbh, I tested with Huge griefing and destruction using lava and water, ALOT of obsidian has been formed,
Every grief , produces like 1-2 obsidian blocks that are not detected , and idk how they aren't tbh
💀
am i tripping or does the world spawnlocation(from /setworldspawn) ignore yaw and pitch?
Probably
yeah it does
vanilla bug
would I be stupidly ambitious if I wanted to make a custom world generator for my own plugin use?
how easy would that be?
How do I block the /plugins command? Because just like canceling it doesnt work cus some players with hack clients can still acess it
The permission node is bukkit.command.plugins
Also the clients don't use /plugins they simply parse the namespace prefix
the namespace prefix?
/minecraft:give
ah okay
minecraft is the namespaced prefix
You can disable that by setting send namespaced to false in the spigot.yml
Lol
Okay so I only need to do that and display the plugin command permisiion
does anyone know any good Book UI prompt api?
🙏🏻
Smh you made a hacked client
😿
its where i learned most of my java lol
like a solid 90-95%
its legacy code that shouldnt be used anymore except maybe to learn concepts

2b2t gaming
I was testing things and made a plugin that sets result of craft to 2 Dirts on any inventory interaction event. If you click this dirt when valid recipe is formed - you get the dirt and every item in grid decreases by 1. if you click this dirt when no valid recipe is formed - you get the dirt but every item in grid after decreasing by 1 also doubles, even going above 64. why does this happen and how do i make it decrease every item in grid by 1 and nothing else? (1.21.4)
PrepareItemCraftEvent
pls add more words
Is there a way to change the enforce-secure-profile setting via a plugin?
hm? why
Use the event to change the output of the recipe
but its only called when recipe is formed
i need to update things on every grid change
Because I use a cloud and a template is used per server, but I cannot use the same server.properties for each subserver
I thought you just wanted to replace all recipe outputs with user
basically i want to make some custom recipes but api doesnt let you make custom recipe choices (whyyyy it isnt there yet) so i thought the easiest way to do it is to check whether or not there is valid custom recipe on every grid change and if there is - change output but strange things happen if this output is taken as i explained above
as i said api doesnt support custom recipe choices
it only supports material predicate and exact predicate
but i need other things
uuuh what do you need specifically
i want ingredients to be itemstack predicates
so i can make ingredient require some nbt tag
for example
That’s what exact choice is
What’s preventing you from just using pdc?
it looks like there is a PredicateRecipeChoice, but that's internal to paper
there is no predicaterecipechoice in paper
it's internal
if i make exact choice for {abc:"abc"} it will only work for {abc:"abc"} but not for {abc:"abc", bca:"bca"}
In that case
Register a recipe with just the generic items without NBT and use the prepare craft event to validate them
If they don’t match you can set the result to null
looks like it's also only applicable to potions
it doesn't look like vanilla shaped crafting really supports arbitrary predicate ingredients, either
there are exact matches and type matches
Hell, before 1.20.5 there weren’t even exact matches
thats was my first solution but im not satisfayed with it. for example, what if i want to register recipe with ingredient requiring nbt tag but it can be any material. what to do then? i dont think registering recipes for every material would be a great idea considering there can be combinations of them
nms.Ingredient is final and implements test by ```java
@Override
public boolean test(ItemStack stack) {
// CraftBukkit start
if (this.isExact()) {
return this.itemStacks.contains(stack); // Paper - Improve exact choice recipe ingredients (hashing FTW!)
}
// CraftBukkit end
return stack.is(this.values);
}
Paper
Make a custom crafting system like hypixel skyblock
Sadly you can’t implement RecipeChoice
Well you can but it won’t work
i might misread something but when it actually comes to checking i think its checks if RecipeChoice is instanceof Material or Exact and if it isnt it throws an exception
yes
but the reason why is that the recipechoice is converted to nms.ingredient
and the reason why no "predicate choice" exist seems to be that nms.ingredient itself doesn't support it
i mean, thats something, but i want to find a way for using vanilla crafting table (and not reimplementing every single event that can happen inside it)
so it seems even going into nms won't help you here
nms.ingredient does seem like a fairly simple patch would have it support predicates
so maybe open an issue about it
MD has already expressed concern about it
A plugin adds a recipe using a custom ingredient predicate, then that plugin is disabled
Now what
you unregister the recipe
or, if that has issues with backwards compatibility, have the predicate choices themselves be registered in a plugin -> choices registered by plugin mapping, and have the choice de-reference the underlying predicate on plugin unload, subsequently always returning false
Make a feature request and describe all that :p
in paper issues on gh was some attempts on implementing PredicateRecipeChoice but they failed and it seems like because of Shapeless recipes. i might be wrong about what the problem is, but if its about that some itemstack can match multiple predicates i dont understand why noone just used the kuhn algorithm
seems rather silly
paper features always run into and fall on their face over the most trifling and inane issues
clown
?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/
i mean yeah, could've just released it for shaped recipes at least
i don't really remember what we were talking about or what your issue is, but if the issue was that when taking out the recipe result "weird things happen", have you tried listening to that click event and changing the cursor/active item?
this concern applies to anything that writes to minecraft's storage, be it player data or region files yet things like PDC don't have any concerns on cleaning up after plugins
the recipe registry is ephermal anyway
though in this case it's a bit more far fetched as the changes aren't going to be persistent, yeah
I do believe there should be something that allows plugins to clean up after themselves even after removal
Tbf predicates work a bit better than a custom class that implements RecipeChoice
hm, is there an easy way to check if current crafting grid is a valid recipe (non custom)?
Since it makes a magical little method that isn’t tied to the plugins classloader
i think yes you can pass an array of stacks into some api method somewhere and itll' give you the matching recipe, if any
at least i very vaguely remember it being a thing
there's also Bukkit#craftItem if you want to give it an array and have it adjusted to what's left after crafting
it does what nms does, which is the latter
and yes, it is shit
I mean, considering the dynamicity of recipes, I don't find it all that unreasonable
big modpacks mess up everything in regards to performance since they just (ab)use of the existing systems that aren't made for their behaviors anyway
what is shaped/shapeless recipe ratio in vanilla?
probably like 10:1 or more
most recipes are shaped if my memory serves me right, don't think there's that many shapeless recipes
then hashmaps should speed it up at lot ig
i did reimplement the recipe matcher as a pet project
the biggest trouble is that many recipes accept material tags rather than exact items or materials
so a naive hashmap based implementation will swell to billions of entries from the combinatorics
i did however manage to make it O(1)* except for a few malignant cases like iirc slabs and stairs, that required 2 hashmap lookups rather than 1
at the same time it would have thrown arbitrary predicates like what you want largely out of the window
is there a limit on how many material tags item can have?
a material could be listed in every tag and a tag could list every material; no
in practice the ones that are involved in crafting usually only list 4-10 materials
biggest one is i think the one that lists all logs and stripped logs
how did you make it O(1) then
well, O(1)*
as in if someone makes a recipe that only uses material tags that list every material, there will be 2 map lookups minimum
in practice however with vanilla recipes, 99% of recipes completed in one lookup
it's a bit complicated but i basically inspect all material tags used by recipes and their specific layouts in the grid to compute token keys that, when substituted for any given material in an array used as a key to represent the recipe matrix, will find at least the recipes they were used in, but may return more recipes if the material tags align/overlap
for example, in the bottom row of the 3x3 recipe matrix, all materials used to craft a furnace will map into a single token key
this means that no matter which type of stone you put in those slots, the furnace recipe will always be found