#help-development
1 messages · Page 1334 of 1
so fvcking true
I hate that guy
is there an event thats called once a player is fully loaded into a world after joining a server for example
because spawnlocationlistener is called before the player is even apart of the world.getplayers list
other than PlayerJoinEvent, no
what people usually do is just wait a tick in the join event if it comes down to showing a visual effect or something, as sometimes it is triggered before the loading terrain screen changes for the client
I wonder if the join event makes use of the new packet for players when they join 🤔
you mean the world loaded packet? If so, then no, it does not
It'd be nice if it did make use of that packet but then it'd involve trusting the client to send that packet and idk what side effects changing when the event is triggered would have with current listeners
if it were to be implemented, it'd probably be best to have it as a separate event with a method to determine whether it was sent on join (because it is also sent when changing dimensions)
interesting, would be cool though if it does
no more always waiting however many ticks to do something, just can listen for that event lol
I do feel like hacked clients could potentially abuse of it
like just never sending the packet and still moving around and such, I don't think the server cares whether the client sends it or not
the server stops listening for it after 60 ticks and assumes the client is loaded
that is what the wiki says anyways
so yeah, if you were to depend on it for anything, it'd only be useable for anything visual because if you actually set player data in there then it might be potentially exploitable
Just do the same as the server
that would require consumers of that event know what they're doing, which I don't expect they would
Listen, if it hasn’t come after 60 ticks assume they’re loaded and do your logic anyways.
Keep them in some sort of limbo until your logic is run.
I would imagine you could just have the server invoke the event after 60 ticks anyways. Only difference is timing on the event if you do it that way
and its 60 ticks after the last login or respawn packet was sent
I guess 60 ticks isn't long enough of a timespan to do anything potentially dangerous, maybe spam in chat at best
apparently the wiki provides a better way then just waiting 60 ticks. Apparently the client will send 60 client tick end packets
only after 60 of those packets will player ticking start
isn't there PlayerLoadedWorldEvent or sth?
H uh? Explain
Like if a player loaded in a world?
No, like the player has finished loading the world
idk
Like on velocity there's PlayerFinishedConfigurationEvent
also valid, yeah
But I definitely dislike a fixed delay of 60 ticks
For example on a modern computer, the delay is like 0 or 2 ticks at most
And on @jagged quail's computer, it'd be 500 ticks lmao
But yeah, checking for movement is valid
Paper e.g. has API for actual buttons used but we're on spigot here
so the check might fail if e.g. the player logs in while being in water or similar
not sure though
paper does have reliable methods for checking when a player actually entered the world, Spigot unfortunately doesn't have it yet
What do you need it for anyway?
My non existent computer
To be fair, Oliver's car might as well be AWS the way it always has issues
why is it gone?
my car also had like 3 issues in the last months
- I don't remember but sth was broken
- I was on the autobahn when suddenly sth with the motor was broken (turned out that only some hose blew up and repair was only 59€)
- I got an email from the manufactorer: the airbag is broken and needs to be repaired lmao
cars love to have issues
Wdymmm email lol
Broken airbag is insanely expensive
How does an airbag gets broken unless you had to use it at which point isn't the car in pieces already?
What is the minimum Java version required to run a server using the latest version?
have some wiki about this?
Jdk21 i think
is there any text editor which doesnt suck lately
visual studio code LSP server keeps getting dementia for some reason
sublime text costs money
use pen and paper and scan them in
zed is incomplete and lacks basic functionality
notepad
i restarted vscode's typescript lsp server for at least 100 times now
Notepad should still be good afaik
because it forgets that imports exist
Oh you need some sort of ide
i want lightweight ide/text editor
notepad++
idk i always use jetbrains products, they can sometimes have dementia but they work for me
Never had issues with jetbrains' intellij
not particularly lightweight tho
we need open source sublime text 🙁
zed probs
but it has like 500 open PR's
start your own ;D
editor itself is half baked
sublime text is pretty cool but as far as i know its LSP support is not
maybe something changed
i need to try it
Hmm
airbags are for wussies
well sublime and jetbrains are a different world
the issue is more like you cracking your neck/spine because you don't have a seatbelt on your forehead
If i was to do proper coding i'd use jetbrains products
Ah
just like toml
That then
only thing i think vscode does better is centralized config vs a million xml files
also xml for configs 🤮
one nice thing about vscode is the web editor and its integration with github
for some reason xml for configs is standard for java
i blame apache 🐜
true
either way still better than doing it in kotlin
Are those xmls for users?
i still cant find something better than json
its verbose a bit but not as verbose as xml
yaml has weird parsing rules
simpleyaml seems about the best spec for general purpose configs
it's essentially yaml without all the weird parsing nuances
i don't remember, doesn't really matter as you can put any extension on any file
cant find that, could you link?
most of the time regular yaml will parse fine though, so it probably has the same extension
nevermind it was strictyaml, not simpleyaml
the most important change it makes in my mind is that it gets rid of implicit typing, much like most of the proper json parsers do with json
the config itself doesn't capture any type information; it's determined at runtime by whoever is deserializing it
so you no longer get errors out the ass when e.g. version: 1.0 in plugin.yml gets treated as a double rather than a string
secondary to that is all the multiline string shit
my only regret is that it also does away with anchors and references, which i do end up using in e.g. mythicmobs configurations
no java port?
nope, typical pythonoid behavior
hurr durr everyone just does everything in python anyway
If the location I tried is invalid, what location should I try? Perhaps at an offset of 32 blocks?
Something like this where NEARBY_OFFSET_RANGE is 32? https://pastes.dev/CJPSBkxxRF
I have no idea what proportion of blocks I should set for the attempt and how many attempts I should make before looking for another completely random location; I set it as 32 and 3 attempts, I don't know if those are good values
I'm also thinking that if the first attempt increased x and z, then the second attempt should increase x and z, not go back
depends on why it fails
not all checks are equal
if you hit water, you're probably very likely to hit water again in any blocks within say a 8 block range
if you hit a tree trunk, well, those are either 1x1 or 2x2, so any adjacent block is still very likely to work
if you hit leaves, positions within a 3 block range are probably also going to be leaves, but farther out is likely to work
the main point is that you want to stay within the same chunk as long as possible, as going out will generate more chunks again
Yes, in my case I only apply this if the highest block at the location is not found; if it stops because of the ocean biome or the chunk has already been generated, I try a completely random location
even within other biomes, you can hit fairly large bodies of water, like lakes
well, "large" as in like 10 blocks across
but much larger than a tree
In my current approach, I wasn't concerned with chunk size; I was only looking for a valid location nearby (it might go outside the chunk), but this is still quite advantageous because it avoids generating too many chunks
i quoted the wrong msg btw
something to keep in mind is that reading blocks in the world is many orders of magnitude cheaper than generating a chunk; to get a gist of the scale, remember that many mobs like drowned, villagers, and bees constantly scan thousands of blocks to find blocks to navigate to, and every mob scans hundreds or thousands of blocks whenever it pathfinds, and most of this is unnoticeable in the tick loop
so even if you end up checking every block column in the chunk, it will take less time than generating the adjacent chunk
so i would not recommend jumps of 32 blocks or anything more than 2-5 blocks, unless you hit a condition that indicates the whole chunk is very likely to be invalid - such as water
I see
So in this case you recommend checking the highest block of an entire chunk (even if it's water) and if everything is invalid (for example, a huge hole because I only consider it valid for y>40) then in that case try an adjacent chunk
entire chunk = I mean the chunk corresponding to the first location attempt
correct, except i'd bail out and move to neighboring chunks immediately if i hit water
since if there is one block of water, there is probably an entire lake of water: and the entire chunk is probably invalid
for cactus, leaves, whatever else that's more "spurious" i'd continue scanning the whole initial chunk
car manufucatorer pays for the repair
just google "Opel Rückrufaktion"
Sometimes the lake might end at that chunk, and as you said, traversing the chunk isn't costly compared to generating chunks, that's why I suggested traversing the entire chunk even if you encounter water
Oh nice
public static final HeightMap MOTION_BLOCKING_NO_LEAVES
The highest block that blocks motion or contains a fluid or is in the Tag.LEAVES.
When it says "contains liquid," could that be water or lava? Or does it refer to blocks like stairs with water inside?
Water and lava
i tested and doesn't seem to have the same behavior
If the location has a leaf, I teleport underneath the leaf; if it has water or stairs with water, I stay on top of the water/stairs with water
If I do:
world#getChunkAtAsync#thenCompose(... -> {
if (...) return CF#completedFuture(...);
(...)
}).thenAccept(... -> {
// chunk loaded here guaranteed?
});
supposing the future does get completed by the main thread, yes
So the instructions cannot be executed in the middle between the thenCompose block and the thenAccept block?
i'm not 100% sure if that guarantee is quite exact, i think there might be a race condition in it if you do the getChunkAtAsync call off of the main thread, but it's probably reliable enough
getChunkAtAsync is called on main thread here
if the other future you're passing to thenCompose isn't complete, the chunk is very likely going to unload
My question here is this: if that's the case, does it prevent the game tick loop from sending a message to unload the chunk
also, if the future you're passing to thenCompose is completed off the main thread, then thenAccept will also run off of the main thread
i see
But if getChunkAtAsync is called in the main thread, then do I have the guarantee?
no, i think i misread your original question: the guarantee only exists for a pure chain of ``thenX`s from getChunkAtAsync; introducing any other future into the mix invalidates the guarantee
unless you are 100% certain that other future is already completed
this is because doing any sort of composition of futures, like allOf or compose, will cause the resulting future to execute only all of its dependencies (the futures being composed) are complete
while getChunkAtAsync only guarantees for the chunk to be loaded for 1 tick
But the allOff here isn't relevant; because I only need the chunk loaded on thenAccept block if this if statement is true
you know this is kind of what i was talking about with the virtual threads
This seems to be a different case to me
My question here is about the behavior of thenCompose; if when I do CF#thenCompose and within that block it returns a completionfuture that is already completed; if when using CF#thenAccept after the compose, something is executed in that thread between those two calls
the thread chat completes the future (getChunkAtAsync) you call thenCompose on (the main thread) will continue to immediately execute its dependents (the lambda in thenCompose), and then, if and only if the future returned by thenCompose is already completed, immediately continues to execute the composite's dependents (the thenAccept)
in this case, yes, the main thread will immediately execute the thenAccept without any instructions in between it and your lambda in thenCompose, but only if the if in the thenCompose is true, or the future it returns in the else case is already completed
which means that the chunk is guaranteed to be loaded in thenAccept under the same conditions
what is thread chat?
that*
oh
don't know how that turned into a c
Is the thread that completes the CF returned by getChunkAsyncAt determined by the thread that calls the method?
according to the documentation, it should always be completed by the main thread
I even thought of "that" but I looked at the keyboard and the t is quite far from the c 😂
So why do you say it depends on where you call getChunkAtAsync from?
eyeballing the code i'm pretty sure there is a race condition that allows thenX called on the getChunkAtAsync future to be completed on the thread calling getChunkAtAsync instead of the main thread
not an issue as long as you call getChunkAtAsync on the main thread
But you said that according to the documentation, getChunkAsyncAt is always completed in the main thread; therefore, thenAccept will also be on the main thread
the documentation is wrong
well no, the documentation isn't wrong, but the guarantee it gives applies only to the future it returns, not any future created from it
That's why i don't document code. Can't be wrong if it's not documented to begin with 😎
the issue is that calling thenX on an already-completed future executes the lambda on the thread calling thenX
lmao
so even if the future returned by getChunkAtAsync is always completed by the main thread, there's a chance it gets completed by it before the other thread calls thenX
at which point, since the future is already completed, the lambda in thenX runs on the calling thread, not on the main thread
this seems extremely unlikely considering how long it probably takes for the chunk future to be completed vs how fast the caller can go from getChunk to thenX, but the thing with threading is that anything that isn't categorically impossible will happen eventually
just use the method that takes a callback ez
honestly yeah
From what I understand, you're saying that the thenAccept block can be executed in the thread that completes the future within the thenCompose (CF#completedFuture), is that correct?
the lambda in thenX gets called by whoever completes the future which thenX is called on; or the thread calling thenX if it's already completed
so if the future computed by the function in thenCompose is not completed, thenX will be executed by the thread that completes it
if it is completed, thenX will be executed by the thread that completes getChunkAt (the main thread)
so yes, it can be executed in the thread that completes the future within the thenCompose, but only if it isn't completed already
if it is completed already, it gets called by the same thread which runs the thenCompose function
or if you're calling getChunkAt off the main thread and there's a race, thenX could be executed by the thread creating the future chain
the reason why this is so convoluted is because the thenX methods are intended for scenarios where the executing thread doesn't matter
the only guarantee is that the stuff gets executed as soon as possible by someone
for control over which thread/context the lambdas run in, the intended way is to use the thenXAsync overloads, which take an Executor
the issue with this is that passing it the bukkit mainThreadExecutor means the execution could be delayed by a tick, which is enough time for the chunk to unload
I see now; the question is whether the thenAccept is chained before or after the CompletableFuture#completedFuture is executed. If it’s chained before (more likely), there’s no race condition; if it’s chained after, then the thenAccept will be executed on the thread of the CF#completedFuture
Yes, I had thought about that, but then I thought about the lambda being executed one tick later
either way, for your particular case, for the thenAccept to be guaranteed to be run on the MT with the chunk loaded, two things need to be true:
- you call getChunkAt on the MT
- you return an already-completed future from the thenCompose
CF.completedFuture() returns a completed future, so as long as that if is true, it'll run on the MT with the chunk loaded
If I call getChunkAtAsync in the main thread, I'm guaranteed not to have any race conditions because I'm assured that the thenAccept method will be chained before proceeding with loading the chunk that the getChunkAtAsync method asks
myes
but the future you return from the theCompose function still needs to be already-completed, or else the thenX lambda will be delayed
so the requirements for it to work like you want are twofold
yea, to ensure that the chunk is not unloaded
and to ensure that thenX runs on the main thread; if the future you return from the thenCompose function is completed e.g. by a database IO thread, then the thenX lambda will be run by that thread
i see
The way you described it, I thought it would execute quickly, but this takes 250 ms to run xd https://pastes.dev/fo92dgIPgV
doesn't sound right; profile it with spark or something, i suspect you're doing something strange in the utils method
iterating over every block in a chunk section is like sub-1-ms usually
https://pastes.dev/TJFMAwZZak I find it strange how the findSafeLocationInChunkSync method is called on the same server tick as when it was first executed (these 9 calls result from the recursion of only one attemptLocation call), considering that between each call to the method I call getChunkAsyncAt
you seem to be calling getChunkAtAsync 16*16 times for every chunk
that's why it takes so long
https://pastes.dev/6I0Lkqy2e4 The reason it was taking so long was line 142 which was doing block#getChunk. I simply changed that to location#getBlock and now it takes 0ms
But that line shouldn't be causing it; because in my view the chunk is loaded
if i takes 50ish ms per call, you're almost surely not on the main thread
the way how it works off-MT is it enqueues a task to get the chunk on the MT next tick
which is going to block for 50ish milliseconds
I only use getChunkAtAsync once per chunk
https://pastes.dev/xXDjrpYU0Y I discovered the cause of the problem; the problem was in this method where, if it were an ocean, it returned the same result as if the location were invalidated because there was water in a single block, for example (the logic of being invalidated by a single block is in the ternary operator where the returned result was null, which is the same result if the chunk were ocean or had already been generated before). Thus, in the method that uses this particular method, I couldn't distinguish whether I should search for all the blocks in that same chunk or if I should simply try a completely random position; In this case, my code was simply iterating through all the blocks in a chunk that had been generated (in cases where this method in the attached message returns null because the chunk has already been generated), and if the chunk hadn't been loaded (which was what was happening), LocationUtil#getHighestSafeBlockYAt would take a long time to get the highest block (only for the first block, because it had to load the chunk; for subsequent blocks, the chunk was already loaded), thus causing the high time in findSafeLocationInChunkSync.
?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 did tell you exactly that (the stuff about getHighestSafeBlockYAt loading the chunk) like 10 hours ago
where is the msg
I'm having a problem where, when a chunk is being generated to fill the buffer and I type /rtp, I'm teleported to a location that has already been generated and is in the buffer. However, the chunk I teleported to and the adjacent ones remain empty until the chunk currently being generated finishes generating. But supposedly, player#teleportAsync only teleports the player once the chunks are loaded. Why is this happening?
Ask paper not spigot?
I'm banned there 😭
skill issue
wdym empty
I'm banned there too lol
it's not very hard to get banned there
just send a soundcloud link or two
Why do you worry so much about chunk generation? Just tp the player and let the server handle nearby chunk generation, it should only take a few milliseconds
The chunk remains empty for a considerable time
check this ss - it stays like this for a few seconds https://imgur.com/a/o1XEyvC
That's just the server taking a while to send them? Can't really rely on that; double-check with the api that they're generated
inb4 the chunks are unloading because no chunk ticket is added beyond the one for the callback
atp i'd just use the getChunksAtAsync(minX, minZ, maxX, maxZ, callback) and call it a day
💀
But if I do world#getChunkAtAsync(chunk -> {
// chunk is loaded here? even without a ticket?
});
But actually, forget it; it's the player#teleportAsync that does that. I thought that using that I wouldn't see empty chunks when teleporting, but it must be the client taking a while to interpret the message that arrived from the server or smth like that
i hate the ticket system
i mean teleportAsync(target) is quite literally just getChunkAtAsync(target).thenApply(_ -> player.teleport(target))
getChunkAtAsync loads the chunk, yes, it adds a ticket of its own, but it will be removed immediately after the callback; if you wish to keep it loaded you need to add your own ticket
i wish the ticket system accepted namespaced keys or something instead of a plugin instance
suppose for example this exact scenario
you have two systems which load chunks and have to keep them loaded for a few ticks
how do you make sure both can register tickets without stumbling over one another? you only have one plugin to pass, but two systems which should hold their own tickets
so now you end up doing your own ticket system to drive the bukkit ticket system
a perfect example of an api nobody bothered to try using in practice before standardizing and finalizing it as part of the api
isn't that just every api in the whole of the spigot ecosystem?
for all the shit i give paper about them marking everything as experimental, at least they're doing right in principle to keep things experimental until adoption can recognize needed changes
it's just that they never un-mark anything as experimental
Ah yes
I had to register commands for paper and everything was a warning due to the experimental annotation
I guess they did add later a register command in java plugin that didn't had it
lol rip
i wish namespaces didnt favor plugin instances
I get the error 'ClientboundAddEntityPacket(net.minecraft.network.RegistryFriendlyByteBuf)' has private access in 'net.minecraft.network.protocol.game.ClientboundAddEntityPacket'
while using ClientboundAddEntityPacket(ServerPlayer serverplayer)
what could be the issue that i need to solve ?
if you can use packetevents for your packets
thats my suggestion if doing more than 1 packet related thing in a project
^ NMS Packets are a bitch to work with
oh the horror
If this is for your own server, just fork paper or spigot and add API lmfao
oh damn lol
Be a real programmer and make ur own
If it's a public plugin, get ready to do this shit
ill migrate to PE fully someday
now its a hybrid
there were reasons ive done it that way
Someone should make it so that we can use blueprints to make plugins if it does not exist currently
but its a nightmare when suddenly paperweight has to re-pull and decompile all the minecraft binaries
Thankfully I don't have to use PE. I'm already forking paper, so I can just add API as necessary lol
nms packets are pretty nice to work with in conjunction with protocollib + mojang mappings
visualbukkit and there was a thing called blueprints
or well they are, as long as you only need to support one version at a time
I can finally be a unreal programmer
that said everything is ass to work with with multi version support
That is why i stick with the latest version only kekw
plib has performance issues
eeeh not really if you use the nms packets directly
I love listening to packets with my own classes
the perf issues mostly come from the reflective packet wrapper nonsense
Everything is nonsense if we didn't make it
imo hooking into netty directly to send/receive your own packets is always unnecessary and overkill, unless you need to hook into a specific spot in the pipeline, like after packets are transformed into raw bytes, or before/after viaversion transformers
whether its packetevents or protocollib, using an existing solution is cleaner if you don't need to customize exactly where you hook into
Too many nice features in newer versions lmfao
Currently making a mini NPC library built off of the Mannequin entity
i just disguise villagers with libsdisguises 🤡
ld is ass trash
KEKW
its a plugin? but its a lib? but the plugin is limited?
the codebase is and many things about it are, and the dev seems slightly incompetent, but it does work and it does a lot of things out of the box without trouble
I have the Mannequin, so i use it lol
10 billion command aliases
I still wanna make a disguise plugin
Probably have to kill change type and show and intercept packets
"premium" libraries always bother me
I'd compete with ld, but I have enough projects to work on lmfaooo
that model library especially
old me used to reverse engineer that shit on every update
you only need the "premium" if you use the ingame commands
it works for free as a library/api for other plugins
you either make a lib or make a plugin
not necessarily
the plugin part of it could be a different plugin using the lib
not something baked in
there are many advantages to having a service loaded on the server as a plugin
not saying it shouldnt be in plugin form
they could just be separated
so much less bloat at minimal effort
doesn't really seem like a problem to me honestly
old me wouldnt be bothered either, but these days i keep my stuff minimal
my rule is - if something overwhelms the server dev/owner, it will certainly be even more pain for the player
either way, it has many useful things to depend on, e.g. an integration to auto-upload skins to mineskin, an entity property parser so you can configure your things in plaintext with setters like setSitting true, and it can automatically reflect a player's equipment, just to name a few
so i just skip stuff like this
nothing wrong w/the plugin, all im saying is that they could be 2 different things
ive never really used the plugin part of it other than pranking my gf
btw it's not called libsdisguises because it's part library part plugin
it's just a plugin
by someone called libraryaddict
How can I make a player invincible for 5 seconds when teleporting with my rtp plugin? Is there a potion for that?
Or do I need to intercept the damage events, etc.?
just give them resistance 255 lul
this will block everything except void damage and /kill iirc, and is what most rtp plugins do
some also give brief low level levitation in case the player somehow ends up falling through the world before it loads, but that's not something that "should" happen anymore
Isn't there also setNoDamageTicks
it's a bit fiddly, since it's not really "no damage" ticks but more like a "Math.max(damage)" ticks
basically what it does is it takes all of the individual damage's dealt over the course of the ticks, and totals it to max rather than sum
so if you get hit for 10 damage and have your no damage ticks set to 5, then if you get hit for 15 damage again within those ticks, that'll do 15 - 10 = 5 damage; for a total of 15 over the course of the ticks
so maybe if you set the previous damage record to Double.POSITIVE_INFINITY or something and then apply no damage ticks, it'd work
isn't Entity#setInvulnerable good enough?
/**
* Sets whether the entity is invulnerable or not.
* <p>
* When an entity is invulnerable it can only be damaged by players in
* creative mode.
*
* @param flag if the entity is invulnerable
*/
public void setInvulnerable(boolean flag);
does that work on players?
Yeah it works fine for players
neat
is it persistent? if it is, i'd stick with the potion effect still, since otherwise if the player e.g. quits in between you applying and revoking the invincibility, they might get stuck permanently invincible
Just do a quick isInvulnerable check on login
i dislike anything persistent on players because then you need separate "uninstaller" logic
The problem is then the server owner removing the plugin or something like that xd
myeah
I thought about that persistence thing too
Is it normal for world#getChunk to take 500ms? (The chunk has never been generated before)
where are you measuring it
wdym
on the MT or async
long start = System.nanoTime();
location.getChunk();
System.out.println("(0) " + formatTime(System.nanoTime() - start));
MT
I'm doing this on my command (this is executed on main thread)
sync-generating a chunk can definitely be very expensive, it's not something you generally ever want to do
2c/2t celeron ddr2?
i5 13º
that said 500ms is a bit high
my advice would be to not call it
Plugins always use getChunkAtAsync, but when this method runs on the server tick, it will take the same amount of time as if I use getChunkAt no?
not really
it's the same but the other way around
getChunk is getChunkAtAsync().join()
getchunkatasync can process dozens of chunks in parallel, and almost all the work is done off the main thread
doing getChunk means the server is waiting for a single chunk at a time
-# not directly like that but it achieves the same effect
myes
And what about getChunkAt in older versions?
And in modern Spigot because Spigot 1.21 doesn't have getChunkAtAsync from what i know
before async chunk loading/generation, it's probably a bit faster than getChunkAt is now, because now it has the overhead of reordering the queue and making all the chunk thread shit bricks trying to handle the urgent ticket asap
no clue how it behaves on spigot
But then that explains the 500 ms, so it's not my PC's fault
chunk gen is still threaded pretty sure, just, spigot has no api to request it non-blocking
paper even has a mode to record every sync chunk load's stack trace so you can debug what is causing them in order to eliminate them
You're saying the paper allows you to see which plugin uses this method?
Thread.dumpStack()
not just which plugin but the class and exact call stack leading to it; basically the same way you'd locate an exception being thrown
I have no idea how I can use this xd
i see but I'm fine because I won't need it in any case 😅
unless a plugin like luckperms does it which I doubt
i mostly bring it up to put into perspective how aberrant and undesirable it is for a plugin to call it and do a sync chunk load
yea i see
134.9 µs to iterate 16 * 16 blocks, and for each block I'm using getHighestBlockAt. Reading blocks is incredibly fast xd
How does getHighestBlockAt work internally? Is it 100% accurate?
He doesn't need to iterate through all 320 blocks of the world to see the highest block
it's a heightmap
basically as part of world generation and bookkeeping (updates when the blocks are changed) the server updates a blockcolumn -> height mapping
so it's updated whenever the blocks change, but querying it is essentially free, just an array/map read
there are a number of different heightmaps for different purposes, not just one
some of them are used for e.g. sky light, others play a part in navigation and mob spawning
I see in forums that they say getHighestBlock only works for chunks that haven't been modified but apparently it's a lie
Either way, it's not relevant to me because my RTP only allows it for chunks that have never been generated
public static enum Types implements StringRepresentable {
WORLD_SURFACE_WG(0, "WORLD_SURFACE_WG", Heightmap.Usage.WORLDGEN, Heightmap.NOT_AIR),
WORLD_SURFACE(1, "WORLD_SURFACE", Heightmap.Usage.CLIENT, Heightmap.NOT_AIR),
OCEAN_FLOOR_WG(2, "OCEAN_FLOOR_WG", Heightmap.Usage.WORLDGEN, Heightmap.MATERIAL_MOTION_BLOCKING),
OCEAN_FLOOR(3, "OCEAN_FLOOR", Heightmap.Usage.LIVE_WORLD, Heightmap.MATERIAL_MOTION_BLOCKING),
MOTION_BLOCKING(4, "MOTION_BLOCKING", Heightmap.Usage.CLIENT, state -> state.blocksMotion() || !state.getFluidState().isEmpty()),
MOTION_BLOCKING_NO_LEAVES(
5,
"MOTION_BLOCKING_NO_LEAVES",
Heightmap.Usage.CLIENT,
state -> (state.blocksMotion() || !state.getFluidState().isEmpty()) && !(state.getBlock() instanceof LeavesBlock)
);
and in particular, this is LevelChunk::setBlockState, which is the main route all chunk modifications post-generation go through:
@Override
public @Nullable BlockState setBlockState(BlockPos pos, BlockState state, @Block.UpdateFlags int flags) {
int y = pos.getY();
LevelChunkSection section = this.getSection(this.getSectionIndex(y));
boolean hasOnlyAir = section.hasOnlyAir();
if (hasOnlyAir && state.isAir()) {
return null;
} else {
int i = pos.getX() & 15;
int i1 = y & 15;
int i2 = pos.getZ() & 15;
BlockState blockState = section.setBlockState(i, i1, i2, state);
if (blockState == state) {
return null;
} else {
Block block = state.getBlock();
this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(i, y, i2, state);
this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(i, y, i2, state);
this.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(i, y, i2, state);
this.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(i, y, i2, state);
boolean hasOnlyAir1 = section.hasOnlyAir();
if (hasOnlyAir != hasOnlyAir1) {
this.level.getChunkSource().getLightEngine().updateSectionStatus(pos, hasOnlyAir1);
this.level.getChunkSource().onSectionEmptinessChanged(this.chunkPos.x, SectionPos.blockToSectionCoord(y), this.chunkPos.z, hasOnlyAir1);
}
it does seem to update most of the heightmaps, except the Usage.WORLDGEN ones
i see
why 255?
255 is max
The problem is if the player uses invisibility to kill someone xd
So maybe I need to have some additional logic
weakness 255 also 🤡
i don't know, if the spot is pregenrated and you've done your checks, i don't know if you'll need resistance or anything of the sort
the worst i see happening in practice is someone having a poor connection and lagging for a few seconds after teleporting, in which time some newly spawned mob could kill them
It's to avoid what you said about the lava not having flowed through the blocks
eeeh lava is pretty slow and doesn't flow far in the overworld
i wouldn't worry about it
Well, 2 potions effects don't cost anything
plus if they do end up in lava somehow, resistance for a few seconds is probably not going to save them
you can give the potion effects, that's an acceptable level of extra complexity; but i wouldn't start writing some pvp combat toggle listeners or anything of the sort
what if you spawn on top of a cave with a sand ceiling and flowing water causes a block update and you fall down with the sand and suffocate in it 🤡 you never know
I also like resistance because sometimes the location is valid, but a block in front is a hole, for example, and the player used RTP and may have moved forward unintentionally and ends up falling to death
or this
Break their legs for a while so they don’t fall in the hole
Suffocation resistance, duh
why moveEvent#getTo is nullable?
It's something to do with it being inherited from another event, I think the portal event
Or the other way around
Yeah. It's nullable in PlayerTeleportEvent which extends PlayerMoveEvent
And how do I know the new location on the portalevent if event#to is null?
I don't remember for what reason that location can be null 
There was a case where it is, but it's been so long
as it should be
really shouldn't need to be resetting it very often
anyone having this problem?
they haven't used destroystokyo in years
this is also the wrong server to ask for paper support
https://repo.papermc.io/repository/maven-public/ is the current one i think
i don't remember, they keep changing it every 2 months
?whereami
everybody here is banned on paper probably
no help for you then ¯_(ツ)_/¯
ty mate
is there an event that i can listen to detect if player click YES button after trying to open a link from chat (from the confirmation interface)
I got unbanned
They keep asking
Seen so many paper questions here lol
that not my website sadly
Have you written the panel?
yeah
still adding things, this is just a start
how the heck do plugin licenses work?
Do you want to add a license system?
If so it has to work offline and without manual steps
Generally they just do a web request to a server with the buyer id and the server responds if the plugin is allowed to start or not
also know that it'll likely be defeated by EOD lol
This is easily bypassed
^ if there's no obfuscation it'd take <10 minutes. If there's obfuscation, it'll take longer but it can still be outright removed, bypassed, or disabled
Bro got compromised @vagrant stratus
I'm looking for a way to identify if the plugins on my server have been modified
Reproducible builds
No license needed really
But this requires the people publishing the jar to do it, you can't do it on your own
In practice, most CI systems display checksums for any artifacts they serve, which you can use to check integrity
i have a etoken with which i can sign jars
am i the only one who hates generic type parameter naming convention of doing one letter name or T prefix
why not just use something like dollar sign, it makes your autocomplete better since that doesnt collide with the actual class imports
and looks cleaner to look at
class Main {
public static void main(String[] args) {
System.out.println(new Foo(5).id());
}
public static class Foo<$Id> {
private final $Id id;
public Foo(final $Id id) {
this.id = id;
}
public $Id id() {
return this.id;
}
}
}
isnt this just cleaner to look at
💀
I would argue that / is a better symbol
but that's used for division
|Id|
I don't believe generics need any symbolic delimiter tbh, they're supposed to blend in with actually typed params
only time I have found them confusing is when people use whole words for their generic param and I end up trying to find the class for it
<T> never bothered me...
never had an issue with single letter type params
think I've done whole words for type params, like, once
sometimes i do CH when I need to parameterize over various socket channels but that's about it
probably
it can get a bit ambiguous when you have a lot of them
<F,T,A,X> where all the letters are like the first character of something they refer to, like From,To,Accumulator,whatever would start with x, is not very nice to work with
but imo uppercase whole words like <FROM,TO> are a better option than throwing weird delimiters like $ at it or naming them like regular classes From,To
sometimes you need to extend the type
and that's where it might get problematic
what if there are two types that starts with the same letter
Hello everyone. I am trying to setup hotswap for plugin development. I was successful in turning debugging on, breakpoints are working; however hotswap brings following error message: Hot Swap failed <name>: delete method not implemented <name>: Operation not supported by VM
My environment in short: IDEA, Paper (i know, it is not exactly spigot, but my question is universal)
Internet says hotswap should work and idk if something is unsupported in my configuration
Also tried this
https://plugins.jetbrains.com/plugin/14832-single-hotswap/versions/stable
However it also fails with the same message
So i am wondering what i may have missing? I see for someone more qualified then me, since i dont know how all of that happening internally (building artifacts, running configurations, debug connection establishing) and what can be a reason (maybe something abvious)
I can provide more details if needed
public @NotNull <THIS extends VarList<NEXT, E>, NEW_ELEMENT> VarList<THIS, NEW_ELEMENT> add(@NotNull NEW_ELEMENT b) {
return new VarList<THIS, NEW_ELEMENT>((THIS) this, b);
}
normal hotswap doesn't support every action
best it can do is changes within method I think
for Hytale I use jbr-25 for the java version with a flag and that allows for more actions
that's a screenshot from my run configuration
Yes, i tried to change only parameter value in one of the methods call - it led to this result too
When i change
myMethod("hello")
to
myMethod("hello23") for example?
that should work perfectly fine
Well, my only option to try right now is to use another runtime like jbr-25?
I am just guessing maybe it cant hotswap method in running plugin because when it tries to do so it uses different building tool then was used for initial plugin creation (i did that through artifacts) - how can i ensure it is the same?
artifacts 😭
hotswapping is ass
Yeah, i understand it can be done with gradle, but i am really just lacking experience and understanding how that works
make sure you're only compiling the class you're trying to hotswap
if your ide build and the code on the server don't match exactly, the agent is going to try deleting and creating methods and other things on the server to make them match, which will fail
especially terrible when there's reobf involved
If you're using Paper use Paper userdev
See https://github.com/PaperMC/paperweight-test-plugin as a base
Run your server directly from IJ and that should let you hotswap (iirc)
that is definitely much more reliable
debugging in general is much easier when the debugger is connected locally
if your ide build and the code on the server don't match exactly
That is something i am unsure about and idk how to know it is true
Can be a bit hard to tell sometimes
Use this. Will help a lot
Thanks. I tried to do so, but i dont know if its building the same code before launching (comparing with hotswapped)
I think i should try again
I meant with Paperweight userdev
/the runServer gradle plugin that test plugin comes with
So it is like template with gradle already tuned?
Thanks, i will try to
or manually depend on id("xyz.jpenilla.run-paper") version "2.3.1" or whatever the current version is
There are some other advantages to userdev
what i imagine whilst seeing this
Here is the source: Counter-Strike: Global Offensive - Main Menu Music Theme Extended
https://www.youtube.com/watch?v=Rvi6c8toWJM
especially for debugging, since it'll add mojmapped sources to your ide so you can actually see what's happening in nms as you debug it
shouty boi
sometimes reasonable men must do unreasonable things
the naming convention if u have to use more than one letter names is to use <single letter>_<descriptive word/words> iirc
for example T_IN, T_OUT
For a chat-radius plugin, how am I meant to use the bukkit api (in order to check world and distance between sender and recipient) in AsyncPlayerChatEvent since PlayerChatEvent is deprecated?
PlayerChatEvent is still fine if you want to run on the main thread
The deprecation is a warning to let users know they should use the async version when possible
Heh isn't that on paper
No it's deprecated on Spigot as well
declaration: package: org.bukkit.event.player, class: PlayerChatEvent
why do i get Cannot resolve method 'getProperties' in 'GameProfile' ?
i have compileOnly("com.mojang:authlib:3.13.56")
if you're using intellij, ctrl-click or middle mouse click the class to see what's in it
^
if something isn't resolving, it's better to take a look at what's there instead of shooting blindly in the dark
whoops! i tried to use properties() and got this error? 🤔
java.lang.UnsupportedOperationException
at com.google.common.collect.ImmutableMultimap.put(ImmutableMultimap.java:506)
...
profile.properties().put("textures", new Property("textures", b64));
records are immutable
i guess the library i used is outdated 🙁
and it is good practice to make their properties immutable also
the properties map is immutable now hmm
so the profile has an immutable map for properties
let me see how i deal with this
copy the map and the properties and change what you need, then construct new ones
or just create a new one from scratch as above, but be aware that profiles could in principle have more than just the textures property
wait sorry, how do i copy the map?
if you need a new profile with the textures it's fine
you could use the playerprofile api in spigot
or paper
When I updated CCTV for someone I had to fix the player heads and this is all I did:
yeah, you could just skip the base 64 and provide urls instead
oh!
Wasn't my idea to use base64. CCTV's Author did. He had like 20+ heads as base64 saved as strings and I was just trying to get the update out haha
yeah, makes sense then
The author ended up asking for the updated jar so he could post it and he never did 😅
oof
Eh, I was updating it for someone else that wanted to use the plugin anyways
eugh skulls changed as of lately
like 1.21.7 or something
you either pass texture + signature or a name / uuid for it to fetch from
paper's api has ResolvableProfile, no idea what spigot's alternative is
If the server owner types /stop, the item might not be given and the money removal operation in the database might still be executed.
I thought about, for example, removing the item and then scheduling the operation in the database (if it fails due to an offline SQL query, etc., then the method will keep trying). The problem is that this method can also fail due to insufficient money, meaning the item might be given and the database operation simply not be performed, and it's not worth trying to execute the method (unless the player ends up with a negative balance and in doubt, but I don't want that). What should I do here? I really can't access, for example, a cache (this way it would be done in the main thread and would be synchronized with the item give) to check if the player has enough money, since the cache is only for read operations like /money <another player name>, but this cache isn't always 100% synchronized since it's updated between different servers. In other words, this cache isn't used to check if the player has enough balance to buy items, etc
Don’t give anything before the transaction is complete and have proper logs of transactions
Database operations should happen fast enough that items should be given sub second if everything is set up correctly
Are you saying to give the item and then perform the operation on the database async?
If so, it's not possible because this method can fail simply because the player doesn't have money, and I can't verify this synchronously because the cache isn't secure for these things
The problem here is that the Bukkit#getScheduler#getMainThreadExecutor schedules a task, but that task is only executed on the next tick: it's possible that the /stop command is interpreted before that task executes. It's not a question of whether the database performs the operation quickly or not
I am saying doing the operation async and only giving the item after completion
This is what I'm doing in the code I sent, but it has the problem I mentioned above
?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/
No caching of the values so you don’t need a database call?
wdym
Load the players balance into memory so you can check/modify it instantly from the main thread
And then save it async
I can't retrieve the player's balance from memory because this might happen:
long balance = fetchPlayerBalance(...); // this is 500 for example
if (balance >= 100) {
giveItem(...); // let's say that at this moment another process modifies the player's balance (not exactly in this line of code because this isn't measurable, but you understand)
withdrawPlayerBalance(...) -> // fails because the player doesn't have enough money (another process changed the amount)
}
What other process is touching the players money
i have many servers with the same economy
If you have 500 coins on server A, then you must have 500 coins on server B
But the database is already always updated, and that doesn't solve the problem
See eventual consistency
https://pastes.dev/pofTU2jui1 I'm retrieving the player's balance from the database - if I'm doing that, it's because the database always has the most up-to-date value - that's not the problem
The logic here is just fucked though
and that too
I don't do that. That's what Jishuna told me to do, from what I understood
if (hasBalance(...)) { // Optional check
if (withdrawPlayerBalance(...)) {
giveItem()
}
}
As this is multiple servers, you'll have to look into eventual consistency and program around that, which isn't easy
This was literally my code lol
^
a distributed system design where data replicas converge to the same value over time, ensuring high availability and low latency by allowing temporary, brief inconsistencies. It is widely used in CDNs, social media, and e-commerce, ensuring that if no new updates occur, all reads will eventually return the latest value.```
Given your circumstances, you're likely gonna have inconsistencies regardless of what you do. You'll just have to plan things out so things are *eventually consistent* across all of the servers
I have no idea how I can implement this. I'll try Jishuna's solution
You're not really gonna be able to stop two servers from modifying the balance at the exact same time without implementing some sort of DB lock (which isn't guaranteeing consistency either). You're better off looking into how a game like WoW handles things like this
Jishuna's solution seems good to me, and that way I won't need locks
https://pastes.dev/YKQb7DWDgX That way I don't think I'll have any problems
ig this is a possible solution, as multiple servers = more or less what this paper covers
be me
load economy on server start
save economy on server stop
(this is Horrible, dont be me)
I mean, that's good for a single server but iirc they're using multiple servers which requires some sort of eventual consistency or other form of authority on what is considered the most up to date info or whatever tf
Just save every economy change 🧠
(this is Horrible, dont be me)
this isnt necessarily the worst idea
just end up with latency waiting on db
oh yea, true. should be saving it every x amount of time lol
Ideally you'd keep it somewhat in sync with the world saving
fuck the world saving lol
when we getting the WorldSaveEvent
I did this with a custom xp system for a mcmmo like plugin when I was starting out. Also it saved to a yaml file blocking
im using SQLite for rn :P
I store in memory & just save on player quit, plugin disable, and on ocassion lol
honestly disk IO time is like Nothing compared to network imo
at least for small files
esp since im running on an SSD
This is more or less good enough given it's a single server lmfao
yeah i should be saving on player quit honestly
rn i keep all users in memory until /stop
skill issue
quite literally
Hey. Does anyone know how to get the spigot-mojang.tiny file for the development of servers?
Its a fabric hybrid server, more of a personal project, also a learning experience
Aight yeah now you're going to have to figure out how to make one of those mapping files
Or at least convert the maps Spigot uses
Yeah, I guess I can try using SpecialSource? Maybe that will work or somethin.
Hi guys, quick question (as I can't test with spigot right now). Is the BlockBrushEvent called only when the brushing is complete or does it get called for each dusting stage?
?jd-s
I learned more about gradle (important stuff), made build through it and launched server through IDE (as I earlier did for breakpoints) - and hotswap works (yay)! So I suppose it was something about different building workflows (through artifacts or gradle). It wasnt just different names of resulting jar package as i noted were different - I tested with renaming to the same name. Internals of the jars seems to be the same except Manifest file - I dont know was that important or not. Maybe different names still matter internally somehow. I think something in building workflow was different, probably different paths for classes/jars or parameters
I made it work without those two gradle plugins you recommended, however I think I will setup those too. run-paper will make process perfect: I am not sure, do Paperweight userdev have this quick server run flow by itself? "Use this. Will help a lot" - I read about it (userdev) and didnt fully get it yet, what are main advantages of using it?
Thanks everyone
w
The thing is that I looked at the code above that and it patches the brush method as well (so it seems to be called at every brush). That's why I can't understand
I've got kind of an odd situation, probably for a Resources Moderator.. I've been mostly the sole developer for a set of plugins for some time. They are posted on Spigot under another user (they manage the Spigot pages, I develop). That user has gone MIA. Is there a path I can go through to get ownership of the plugin pages to keep things up to date? Or am I forced to create new pages for the plugins?
I don't think Spigot does transfers without the original authors permission
but you can try contacting support
?support
Yeah. Kind of hard to do when I can't get in touch with him 😂 I'll reach out to support!
There won't be any transfer w/o permission from whoever own the account
Yeah thought so
w/ the author being MIA they're kinda SOL
Yeah, that's too bad 🙁 I assume even with a new post, I'd have to make it a slightly different name? Anything against posting comments on the current pages directing users to the new ones?
hi, what is the event called when a player like clicks to switch spectate target state ?
Apparently it’s the teleport event with the SPECTATE cause
For future reference, Javadocs typically, including ours, have a search bar. Searching for "Spectate" yielded 1 result, which was the teleport event
?whereami
Someone does in fact have events for it
You could make the event yourself by comparing Player#getSpectatorTarget each tick
Who's crozono?
rip bozono
Alr pull up with some proof
frozono?
?whereami
I dont get it either
MIA? SOL? What the heck are you people talking about D: lol
MIA -> Missing I nAction
SOL -> Shit Outta Luck
thx
TIL
https://pastes.dev/rd7yezWQQ7 Will the spigot server shut down if the plugin takes too long to shutdown?
when i say shut down i mean a forced shutdown
?whereami
i think it might eventually get killed by the watchdog, but i wouldn't rely on it
i don't think the watchdog is in play during startup or shutdown
So my plugin might corrupt the others
I think is it
Because I did Thread #sleep in ondisable and the server forced the shutdown
Paper's watchdog stops when the server is shutting down when the server shuts down but not sure if that happens before or after disabling plugins
just do Thread.sleep for a minute in onDisable and try it out
But if I have 5 plugins that do that, it will already take 2 minutes and 30 seconds
off the cuff i think the watchdog has already stopped by that point , i remember having a server getting stuck for hours during an automatic restart because something like this blew up on disable and never returned
then again it could've been in onEnable, my memory is bad
tryitandsee
I also had this happen sometimes on chunk save sometimes
chunk save during shutdown*
but no clue if that is/was before onDisable or not
myeah same, though that's far after onDisable's
Do you know how many seconds the watchdog allows the thread to be sleeped?
IIRC it starts out spitting warnings after 10(?) seconds
but there's an env variable or setting to change that
anyway, today I learnt that mariadb has basic json functionality builtin
UPDATE job_users
SET collections = JSON_SET(
collections,
'$.walk',
CAST(JSON_VALUE(collections, '$.walk') AS DECIMAL(20,2)) * 50
)
WHERE job = 'explorer'
AND JSON_VALUE(collections, '$.walk') IS NOT NULL;
Works fine on a regular TEXT column with json data
during normal uptime, the first message is at 10 seconds and it gets killed at 60 or 120 or something
however server shutdown is not normal uptime
i'm pretty sure the watchdog won't do anything there
even if something does kill the server eventually if shutdown gets stuck, it's definitely longer than 5 minutes by default
they do i'll show u
if that's a plugman reload it doesn't count
oh
that's not server shutdown
that's just plugins doing whatever at runtime
currently writing autocomplete suggestion support into my intellij agent harness, and I have a plan
like what
i'll have a cheaper model running shitting out suggestions based on the original file contents and incremental diffs
but since it's a high throughput thing, it needs to be fast and snappy and therefore dumb
so i'll have another model running in parallel, actually paying some thought toward the diffs and try to figure out what i'm trying to do
i originally thought about making that reasoning visible in a chat sidebar so i can stay up to speed what it's thinking i'm thinking
however, the obviously superior solution is clippy
Reloading a plugin with plugman just reloads it
i will have a fucking clippy gif popup going HEY IT LOOKS LIKE YOU'RE TRYING TO WRITE A LISTENER
It doesn’t put the server into the shutting down state
now the only question left is whether the modal notification popups in intellij support playing gif's
~stop works as expected yea thank you
How long does it take for your database transactions to complete anyway
Is your database on the moon
looks like i can only include an animated icon
how small do you figure i can make clippy before it becomes unrecognizable
mmm there's no size limit on icons it doesn't seem like
mm, 8x8
i'm assuming sides of powers of two here
maybe 8x8 is doable
i don't think there's a power of two restriction for icons, i remember seeing weird ass resolutions like 13x13
but 16x16 is definitely doable
i'll see if i can load in a 128x128 icon, not sure what animated formats it supports though
can someone help me? I am trying to get this plugin to depend on another one, and I put the file into the external libraries folder. It is even filling in the blank when I try to refrence it but when I install the finished project it keeps telling me it cant find the packages of the plugin
You either have to install both plugins, or shade the one into the other
Simply declaring the dependency in plugin.yml is not enough
no no no I have both and I made both, I said I put the file into the external library
please share both your plugin's plugin.yml files
also showing your server latest.log would be helpful
name: ScoreTracker
version: 1.0
main: me.datshrek.scoreTracker2.Main
author: datshrek
api-version: 1.20
depend: [BasketballMode]
commands:
score:
description: Score command
usage: /score
ref:
description: Ref command
usage: /ref
permission: ref.use
permissions:
ref.use:
description: Allows referee commands
default: op
the depending file
name: BasketballMode
version: '1.0-SNAPSHOT'
main: me.datshrek.basketballMode3.Main
api-version: '1.20'
author: datshrek
commands:
bball:
description: Start or end basketball mode
usage: /bball <start|end>
pos:
description: Use different positions
usage: /pos <guard|forward|center>
startgame:
description: Start the "Game mode"
usage: /startgame
practice:
description: Pull up the practice GUI
usage: /practice
the original
looks good, share log please
just upload to https://mclo.gs or sth
Easily paste your Minecraft & Hytale logs to share and analyse them.
okay, im new to this so how do I exactly get this log
in your server directory there's a "logs" directory
inside is a file "latest.log"
you can open that with any text editor and just copy/paste it or upload it here directly
9 lines
your server doesn't start because yo uhave not accepted the eula
open the file "eula.txt" in your server folder and put "eula=true" instead of "eula=false" there
then server should start
no bro my server works and so do the plugins, the dependacy I am working on in an update isnt
then you sent the wrong log file
the log file you sent clearly shows that eula wasn't accepted
I mean I havent even put these plugins into the server at its latest so matter what its going to be irrelavent
139 lines | 3 errors
eula.txt needs to be accepted no matter what plugins you install
you are using paper, do you have both a plugin.yml and a paper-plugin.yml in your plugin?
try with spigot or ask on paper's discord
what are you trying to do?
I made these plugins a while ago in eclipse and they worked fine, now I want to update them and they are depended on each other. The dependancy wont work even though I have the file in the external jars and the ide is literally filling in the blanks for it
idk why this guy seems to be asking and trying to see the log as if it matters here
I legit js need to get this dependancy to work, nothing else
because the log tells the error
are you failing to find a class at runtime or at compile time?
checkout the latest log they sent. Both plugins do not specify an api-version
hence they use legacy material names and fail to use modern material names
fosho
kind of got the impression that they're not having some dependency show up in their ide/build
but there definitely is a problem loading those plugins as well
These are not the .yml files read by your server software, otherwise the warning about the api-version wouldnt show up:
how are you building? maven? gradle? or through IDE directly?
maven
unzip the jar and look at the plugin yml in it
run mvn clean package, and then unzip the .jar and show the contents of plugin.yml
alternatively upload one of those plugins to github and share link
alright
just fyi, you shouldn't call your main classes main, simply because they are not the main class of the server. consider renaming them. Also, don't use reload instead restart the server when swapping out plugins
my power just went out im on my phone but thanks for all the help I appreciate the effort, ts is hella annoying
alright thx
milliseconds
But sometimes the plugin might shut down when MySQL is turned off or something like that
yo
if the database queries are done via an executor you can just executor.awaitTermination(5, TimeUnit.MINUTES)
it'll block until transactions are finished
so you can close the database after safely
5 minute timeout is crazy
I don't know if it's worth creating an executor just for that
hell, you could put HOURS i think
XD
integer max HOURS
It's better not to have time out xd
i mean 30 seconds is reasonable
It's just a completely arbitary value i came up with
30 seconds does sound more than enough
Fair
You could also pass an executor you want your completable future to use
dedicated executor for external calls is usually worth it
why?
actually probably not anymore, u could get away with virtual threads just
and then a semaphore to ratelimit
sure you can do that too
And why is this better than saving sync with disable?
you can also use an ExecutorService that spins a VT for each task
and bound it by semaphore
but pooling VTs is absolutely useless and counterproductive
Yup
using an ExecService & semaphore you can also await for termination nicely
it isn't, necessarily, in onDisable you still want to block until all work is done
but you fire threaded tasks during runtime, then await termination in onDisable
but specifically when using hikaricp you don't really need a semaphore, as the library will already block when trying to acquire a connection but there are none available
if player's inventory is full, does that mean item is dropped on the ground?
i forgot how this is usually handled, or if you need to manually handle this
docs:
The returned HashMap contains what it couldn't store, where the key is the index of the parameter, and the value is the ItemStack at that index of the varargs parameter. If all items are stored, it will return an empty HashMap.
well no
if some part of the itemStackReward was given to the player, this way you'd drop that as well
You gotta take the result of addItem method and drop the items from there
Yeah, if the inventory can take 3 from the item stack and you had a reward of 64 you should only drop 61 and not 64
Which was the init reward
just do …addItem(reward).values().forEach(item -> world.dropItem(item))
Pretty much :d
What's this device?
my ups
What's a ups? Sorry if it sounds dumb
power supply
Oh
if you lose electricity it can power up your devices for a certain time
Oh that's amazing
my network was running off from the battery
I actually wanted something like this
Looks like it's out of juice
Expensive purchase or maintenance?
purchase
yeah heavy too XD around 20kg
yeah around 3 hours..
i have nvr plugged in and one switch, one poe switch, rack fans and rack lights.. which are always on
also the main router
Ah
XD
i love it, im doing a plugin now which reads the entire network data, specifically ups power state, and if i lose electricity, plugin detects if ups is running on battery, and sends a warning in the global chat
really cool stuff
Did you get it working?
im working on it, right now im doing another plugin.. voting... adding this:
Oh yeah
since all is stored on db its a little more work
You said something about making a vote service
I already did it, but its for me for now really, and for my friends who play
Still pretty cool
yeaa XD
does anyone know the correct CoreProtect repo / groupid / artifactId for their latest version? because their docs don't mention it and theit discord is dead
the repo, yes. but neither the group nor artifact id
I don't have enough free time to go the repo link manually and search it for possible artifacts, it should be provided in the docs directly
Imagine saying "yeah here's our api: [link to maven central]"
(it is also in their readme
https://github.com/PlayPro/CoreProtect?tab=readme-ov-file#dependency-information)
docs are hard apparently ¯_(ツ)_/¯
if one cannot keep up with writing proper docs, they shouldnt make any in the first place imho
especially since they are selling that piece of shit plugin
Thank god we have AI for that now
are your problems related to coding?
Yes
RIP coreprotect doesnt seem to support logging moving items between custom containers
doesnt it have an api to log stuff like that?
they seem to only support logging into actual containers and a diff between "inventory now" and "inventory next tick"
according to their docs, no
😭
don't even question why "user" is a String instead of UUID
goofy ah api
mb i really had the impression their api would be slightly more sophisticated
their api for lookups is great
their API for logging things yourself is utter shit
guess we'll have to write our own logging shit plugin
because that's useless
:,)
I think CoreProtect is the kind of thing nobody wants to replace because it is too annoying to do so