#dev-general
1 messages · Page 338 of 1
🥲
Although that might only apply to first party types
Yes
Use extensions at use site
badplugin nostalgia
@half harness Here is an example of my "util" file, in what world would you need the Util.<stuff>?
oh.
but i can't make extension functions for everything
Haha
You can actually
Bet
what-
Any.everything
everything is an extension function
what would I do for sending a message to bungee -> spigot and spigot -> bungee
String#send?!
ew
What
send(“string”)
Player.sendBungeeMessage
lol
if you dont like extensions
wht
im not using Plugin Messaging
whht
You mean logging? I have "This message will be logged".log()
What if you wanted an extension that would be used everywhere?
no not that
1sec
that exists?
Yup
ngl I prefer log(s) in this case
like ```kt
fun sendChatMessage(ipsToSend: Map<String, Int>, message: String) {
bm is weird
Yeah
ipsToSend = ips to send mc message in
Map<String, Int>.sendChatMessage(“blah”)
Ew
String.sendChatMessage(ipsToSend: Map<String, Int>) then "Message".sendChatMessage(mapOf(something to ip))

No
hm
why is that ew?. you are sending a chat message to some ips that are stored in the form of Map<String, Int>
It's ew because it's not Java
no re
lol
fun getMapFromIpAndPorts(ips: List<String>): Map<String, Int> {
val map = mutableMapOf<String, Int>()
for (str in ips) {
try {
map[str.split(":")[0]] = Integer.parseInt(str.split(":")[1])
} catch (e: Exception) {}
}
return map
}
```what about this?
reeeeeeee
extension property dkim
Oh my god what is that
that method name
Dkim, you're not in Java
lol
No mutability
jesus
val List<String>.ipAndPorts: Map<String, Int>
what should it be
No
oops
i know, what should i change
u guys aren't telling me what to do
dkim you could do something like list.map probably or maybe list.associateBy. i forget the name
Make parseIpAndPort and then use .map for the list version
instead of the mutability inside the method
^^
The exception handling 🥲
but BM what do you have against extension property here
debug { "some log" }
info { "some log" }
with this approach with inline classes you can void logging in some cases
Possibly nothing actually
I might have misunderstood
fun List<String>.getMapFromIpAndPorts() = associateBy {
val (ip, port) = it.split(":")
ip to port.toInt()
}
Much nicer
val List<String>.ipAndPorts: Map<String, Int>
get() = mapNotNull { it.split(“:”).getOrNull(0) to it.split(“:”).getOrNull(0).toIntOrNull() }```
when we are doing debug log, sometimes we need alot of information and we need to proccess this information, like, mapping a values of a big list
what in the world is that
“ < "
idk if what is sent would work even
Matt's looks nicer imo
Yeah
yea it does
Don't think that'd make too much sense to be a property
Yeah properties should only be for short stuff imo
with this inline function format for logging, you avoid execunting something for just logging
fun List<String>.getMapFromIpAndPorts() = associateBy {
val (ip, port) = it.split(":")
ip to port.toInt()
}
```what does:
- associateBy do
- (ip, port) do
- ip to port.toInt() do
associateBy converts a List to a Map with a given function
We know
associateBy will associateBy
(ip, port) de structure
port.toInt()... i believe in you
i know what (ip, port) do
Then why did you ask
you asked what it did
but now i dont know what ip to stuff does
"getMapFromIpAndPort" christ
well i didn't know when i asked
i do now
because u told me
i think
Open in IDE and look at the to function
It's for maps
blah to blah creates a pair
to is an infix for Pair.of()
i can't
just call it "d" and make people look at the docs
the to creates a Pair
Constructing Pairs
Then read docs
a to b = Pair.of(a, b)
associateBy requires a Pair if I recall
every time
ill think abt it
associateBy is for (K) -> V and making a Map<K, V>
You want map() and toMap()
I think
@obtuse gale
Actually associateBy wouldn't work there, it'd be associate instead
@half harness
Yeah associate works too
Associate prints {411.545.1.2=8000, 152.651.5.245=6000}
AssociateBy prints {(411.545.1.2, 8000)=411.545.1.2:8000, (152.651.5.245, 6000)=152.651.5.245:6000}
I think this is associateWith
doesnt that mean its going from (K) -> V into Map<V, K>
not (K) -> V into Map<K, V>
associateBy basically takes a list and associates its elements by some key
so you go from some List<V> to a Map<K, V>
uh oh
All types would have to be a resutl type or we will need it to be an expression
associateTo does the opposite, it takes a List<K> and transforms it into a Map<K, V>
Otherwise theres no way to find invalid matches
then associate takes any List<T> and transforms it into a Map<K, V>
/** {@inheritDoc} g-g-gee I don't know Rick, isn't that a bit dangerous? */
protected final @SafeVarargs synchronized static strictfp boolean $validJava(boolean φ, Class<?>[]... wheee) throws Throwable {
do do do do break; while (false); while (false); while (false); while (false);
return φ |= φ &= φ |= !/**/false;
}{}{}{}{}{}{}{}{}{}{}{}{}{}{}
``` aah I found it
Ah true
Hmm
what about just a concise match binding?
let result = match expression with (pattern, b)
Returns Some if it matched, otherwise None
That could be the functionality for all non exhaustive patterns
wtf φ
why is it there
lol
yea that looks good
ok
Not sure about with
It reads nicely, but it's a whole keyword with only one use
I guess we can find other places to use it too
let id = match expression := pattern
Hmm
Perhaps
let id = expression := pattern
Or just as
as is currently casting
yea that sounds good
Something like bind would be cool to pipe further things on the result
yeah
Tbh I think we should probably rework a lot of things if we want to go deeper into the functional side
Like when we made it, neither of us really understood FP I think
yea true
right, I gotta figure out how I want to do this now lol
a single entry point means I probably need to expose the loading stuff to the API
which sounds a bit whack
since a top-level function can't be abstract
i dont think you do?
maybe I should take a different approach
especially if its event based
either DI or single entry point, those are my thoughts
I'm thinking in having the startup logic be a function that's called, but everything else can be event-based
just have plugins listen for a startup event as the fun main()
You can load the plugins in the backend. you shouldn’t need to expose any of it
hmm
I was first thinking of just having the function take a context param that's injected when the function is called, but that gets a bit whack
then I thought of having main call a top-level function that takes a higher order function as an argument (say PluginContext.() -> Unit for example), but that would need to call something
and that wouldn't really work
i think the context could be very nicely provided via the startup event.
the developer can create a top level variable of the context or something which can be used throughout the plugin to get things like the server, descriptor, etc
that gets a bit whack though
also, as I said, I'm not sure about having the startup logic be event-based
since that just once again increases boilerplate
i dont think it does?
fun main() {
onStart(SomeEventHandler)
}
```or something to the equivalent
you would have to copy and paste that everywhere
lateinit var context: Context
fun main() = listen<StartupEvent> { event ->
context = event.context;
// blah
}```
yeah that looks a bit whack though tbh
first, you'd have to copy and paste that everywhere (unnecessary boilerplate imo)
second, using a lateinit var where you really shouldn't have to
Why not be a sane person and do what all frameworks do with an entry class dedicated to the plugin?
why do you copy paste that everywhere? It’s less boilerplate than a class even if you do, but you dont.
// example event listener file
fun listenToMoveEvent() = listen<MoveEvent> {
//blah
}```
then just call `listenToMoveEvent()` in the startup event listener
if you mean ```kotlin
class MyPlugin : Plugin() {
init {
// some initialisation stuff
}
}
you said it had too much boilerplate when you inject the server, description, etc
that's not what I meant by that
I meant ```kotlin
class MyPlugin(
val server: Server,
val folder: File,
val description: PluginDescriptionFile
) : Plugin(server, folder, description)
pls no
Make var illegal
right. how do you avoid that?
i’m sure there’s a better way BM i was just writing something quick as a proof of concept
that's what I'm trying to figure out
I mean use Koin if you feel like it'd be better
i’m saying you avoid it with a startup event
what would that look like with Koin?
you are saying you won’t do that because its too much boilerplate
the constructor thingy is yeah
you said startup event is too much boilerplate
Idk Koin too much, but from the example it'd look something like
class MyPlugin : Plugin() {
private val server: Server by inject<Server>()
}
yes ik
vomtigin_face
yeah idm that but BM will kill me for using property-based DI lol
also, boilerplate
Would using them in the parent class work?
Btw @half harness that code I sent you will throw at least 3 errors if you don't do the pattern correctly
oh-
using the injections and then registering the plugin's main class as a Koin module? sure it would
how do i do it correctly?
so I could use property-based DI in the super and then boom, no boilerplate in the impls
dkim the error would probably be index out of bounds
ban property DI
nah but you probably shouldnt be forcing users into that
and if you say that's ew BM then you can fuck right off because I don't give a fuck
if i remember the code
it is
forcing users into what?
Using Koin
event driven api :)
not having to do property-based DI yourself by me doing it myself on the backend is probably the best way to avoid boilerplate injection here
You'll need some checks, for example 152.45.02.11 will IndexOutOfBoundsException, 152.45.02.11:sdasd will NumberFormatException
it's still property DI
however you choose to hide it
oh bardy. you could eliminate the lateinit var by providing the context in every place in the api. all events have it, commands have it, etc
true, but then I risk compromising the constructor
and yet again running into the same issue
wdym compromising the constructor
class MyCommand(private val context: PluginContext) : Command(context, name, permission, aliases)
DSL commands >
command event 
if me using property-based DI on my end means my end users don't have to use constructor-based DI themselves then I'm willing to accept that
command("hey") {
}
yeah I'll have that too
I already have a DSL for Brigadier, so this would go with that
The other way would be to provide the plugin with something like a "PluginManager" and let the super constructor register itself
Alternatively you can just do like Bukkit and have the server as a singleton 😬
and thus load whatever is needed
that's not what I want
when are you embedding the clojure script engine
also, that's the exact thing I'm trying to avoid by dependency injecting the server
All this wouldnt be a problem if you just embed Elara actually
define variables and execute
🙂
I want to strongly encourage DI and strongly discourage singletons
which is why I should probably just embed Koin tbh
the bad ending
PLEASE tell me whats wrong with Krypton.getServer()
tesla stock is 14% wtf
down or up
up
I mean, ```kotlin
class MyPlugin : Plugin() {
init {
registerCommand(SomeCommandClass)
}
}
o
I don't even need to force users to use Koin
KotlinBukkitAPI will not force, but will have some extensions
registerCommand(SomeCommandClass)
event<CommandEvent>().subscribe {
:)
}```
even though the backend will use property-based DI, you won't have to do it yourself
why
yeah no, commands won't be event-based
no
why do you do this to yourself
subscribe 🤢
use Flow
SharedFlow
literal anti-pattern
also, it's not even that bad, idk what your problem is
it is
why? because you say so ?
no
sure, it might be, but it's a compromise I'm willing to accept for my end users
spring heavily discourages it
what
you're acting like proper DI is impossible
class MyPlugin : Plugin(
"MyPlugin",
listOf(MyCommand::class, MyOtherCommand::class),
listOf(EventListener::class, OtherEventLister::class),
)
Spring do that, Dagger do that, Koin do that, Kodein do that
it's not, but it's going to increase boilerplate
Spring heavily discourages it, Dagger also discourages it, Koin doesn't, which I consider a problem
as I said, I would rather me suffer than the users of this suffer
I don't do that, but all top usage DI frameworks do that
Kodein is even worse
by an incredibly marginal amount
who cares about having to override a constructor
big deal
I will need to check the documentation again, because I learn to use Koin/Kodein as a constructor injection
Kodein's github only shows property based
if Koin supports actual constructor injection that's nice
also, KodeinAware and KoinComponent SUCK
but my other issues with it still stand
Koin makes you do all the instantiation yourself
that's also one thing I kinda like about Koin
no black magic
The first one that you learn in the Koin documentation is constructor injection with modules
This tutorial lets you write a Kotlin application and use Koin inject and retrieve your components.
beautiful
eh?
also, even though it seems to be against the law apparently to do property injection, I still think it looks really nice
you can't instanciate a Application, Activity
You dont need koin at all
it just feels a lot cleaner
Thats pretty much equivalent to using singletons
yeah
Just waiting for Android to wipe everything clean
that's not dependency injection
mhm
well, ServiceLocator is that
Which?
using a singleton for DI
yea that not much of a great idea
In android, you can't run from property di
you can't create a custom constructor for Views (if you want use it in XML)
ou can't create a custom constructor for Activities
You dont use di in android
Atleast not in the same sense
you consider your activity to be the root element
And pass on dependencies to its dependencies
Application is the root element
and for Views?
Except for maybe with sticky services
What about them?
what do you do, how you get the dependencies?
If dynamically created just with constructor I assume?
If thorugh xml, pass in the properties you can
you can't pass property meaningful through xml
And if Views have access to the acitivity lifecycle probably hook into viewmodels?
Youd use other patterns to supplement those requirements ussually
Like Adapter for eg
Adapters you can instanciate
Even without viewbinding?
Not sure what you are reffering to?
yea
is different from custom view
Whats the issue with inflating the view?
a Custom view, inflates a view, but its a custom view
inflates a layout*
is not the same
I didnt same they were the same*, i asked what would be the issue with inflating
You are questioning basically every single android application in the world
This is a commum use case in Android, you can't run from it
In what sense?
saying that "is not required to use property injection"
Dependening on singletons is waiting for a disaster when android destroys and rebuilds the application
still does not understanding you are saying, there is no singletons when you use Koin in Android
What im saying is that there are work arounds to providing them in the normal sense which is seen throughout the provided API
you just startKoin on your Application class
Yes but a lot of the dependencies end up being "single"'s
the koin is bound to the Application, if the Application dies, everything dies with
Unaccounted shared state
The applications can continue inbetween after being destroyed sadly
You might not even rehit the point of "startKoin" I assume
As in when the battery manager temporarily kills the process
And reopens in the same state
Application class is not destroyed so easy
the Application class will run again, and the startKoin will also run again
Pretty sure Application is supposed to be similar to singletons
There is normally no need to subclass Application. In most situations, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), include Context.getApplicationContext() as a Context argument when invoking your singleton's getInstance() method.
They are, and what is the problem with that?
I assume they follow the same lifecycle if they were to recommend that
oh, I guess I get your point
The issue being the same, that state being lost when the user is in an activity or fragment that expects a dependency in a certain state
You mean: in any place I can find my Application class and uses my dependencies in their?
oh btw, what do you guys think about the idea of a plugin.yml like Bukkit's anyway?
This is not a problem for DI, this is a problem with Android, you should use saveInstanceState for that
still thinking actually whether I should just use annotations tbh
saveInstanceState wouldnt work for the injected dependecies I assume?
I don't can't your point with losing state, this happen alot, but DI does not have anything with that
Im not saying DI has to do with it
I should not work with
Im saying relying* on DI will lead to places where a few expectations break
Koin uses Kotlin Delegate for the dependencies
Atleast in the form of injecting that way
Yea
Yes
that's different
but, I should be a KotlinBukkitAPI instance or not find it
if there is some plugin with KotlinBukkitAPI name
if that returns null, you can't cast it to a nullable type, since apparently, according to Kotlin, null is not nullable lol
actually wait what am I reading
lol that confused me
getPlugin can return null
yeah ik
if the Plugin instance is not KotlinBukkitAPI, I want the cast issue
so you cast to a nullable type
but, I would use a better error message to do that
anyway, what do you guys think of me using a plugin.yml btw?
No, do it like Sponge does
yes
also, if I was going to use annotations, I could literally remove the use for any whacky loading logic anyway I swear
yeah the annotations get a bit whack with a lot of dependencies and big info text
and that, yeah
like: publish with a commit version
also, should I do a Bukkit and require a main entry in the plugin.yml
I mean, the only other option I really have is classpath scanning I guess
which would be fucking slow to do at runtime
right, main it is then
Release it with a Gradle Plugin, needing to write a plugin.yml sucks
guess I could take the project name and version and use those to generate a plugin.yml?
or maybe just ```gradle
plugins {
id 'org.kryptonmc.plugin-config' version '1.0'
}
group 'me.lucko'
version '1.0'
pluginConfig {
name 'LuckPerms' // defaults to project name
main 'me.lucko.luckperms.krypton.KryptonLuckPerms'
version '1.0' // defaults to project version
}
TOML doesn't deal with nested structures very well
and JSON would be annoying to write
also, what's wrong with YAML anyway?
I mean, I can say that the YAML specification can be very lenient sometimes, but for the most part, I think it's really nice
I will support a multitude of formats for configuration
Hocon good
TOML sucks!
korm
TOML is good for anything without nested structures
e.g. my current config is really clean with TOML
I can't think anything that does not have nested structures
# Krypton config version @version@ by BomBardyGamer
[server]
ip = "0.0.0.0" # The IP for the server to bind to. 0.0.0.0 means listen on all interfaces
port = 25565 # The port for the server to bind to. Defaults to 25565
online_mode = true # Whether the server is in online mode (authenticates users through Mojang)
compression_threshold = 256 # The threshold at which packets larger will be compressed (-1 to disable)
[status]
motd = "ὀffKrypton is a Minecraft server written in Kotlin!" # The MOTD. Supports legacy colors
max_players = 20 # The maximum amount of players the server can have (doesn't do anything yet, other than in the status)
[world]
# The name of the world folder (NOTE: you MUST use your own world, Krypton does not automatically generate worlds yet)
name = "world"
gamemode = "survival" # The default gamemode. Valid values are: 0, 1, 2, 3, survival, creative, adventure and spectator
difficulty = "normal" # The default difficulty. Valid values are:
hardcore = false
view_distance = 10
that is a beauty
everyone sleeping on ELON tho
maybe because ELON doesn't even exist
it does
yeah but there's no format specification 
i never claimed there was
yeah it's not bad
right fine, HOCON it is then
what's the extension for it btw? .hocon?
.conf
.elr I believe
maybe
jesus christ
and I thought YAML's specification was lenient lol
okay this is actually quite nice
how do arrays work in HOCON?
e.g. json "authors": [ "lucko", "BomBardyGamer" ] in JSON, or ```yaml
authors:
- lucko
- BomBardyGamer
is there a way to do something like that in HOCON?
how do you do arrays in HOCON?
actually nvm, got it
authors = [
"lucko",
"BomBardyGamer"
]
just write json for the parts in yaml you don't like
ok i will write json then
permissions {
"luckperms.*" {
default: false
children: {
"luckperms.commands.*" {
default: false
},
"luckperms.something_else" {
default: false
}
}
}
}
```looks like JSON ngl
looks like korm
also starts to get a bit messy ngl
Welcome to the Korm fields
use yaml
Average Korm hater Vs average Korm enjoyer
I mean, Korm isn't actually that bad tbh
vs average Sx
elon >> Korm
tbh, idk what's wrong with JSON or YAML personally
Lacks full interop with Elara
yaml beautiful
stfu Yugi
Precisely
You shall not silence the truth!!
name = "LuckPerms"
main = "me.lucko.luckperms.krypton.KryptonLuckPerms"
version = "1.0"
description = "An advanced permissions plugin"
authors = [
"lucko",
"BomBardyGamer"
]
dependencies = ["Vault"]
permissions {
"luckperms.*" {
default: false
children: {
"luckperms.commands.*" {
default: false
},
"luckperms.shit" {
default: false
}
}
}
}
```yeah not sure about this
think YAML might look better here tbh
Until you try copy paste an indented section and have to spend 20 minutes removing all of the broken spacing
toml.
if only that wasn't true 😭
or just properties file 
me working with Github Actions
TOML is great... until you start working with nesting
Yaml sucks ass
Devops is obsessed with it for some reason
"The more yaml you use, the more devops it is"
name = "LuckPerms"
main = "me.lucko.luckperms.krypton.KryptonLuckPerms"
version = "1.0"
description = "An advanced permissions plugin"
authors = [
"lucko",
"BomBardyGamer"
]
dependencies = ["Vault"]
[permissions]
[permissions."luckperms.*"]
default = false
[permissions."luckperms.*".children]
[permissions."luckperms.*".children."luckperms.commands.*"]
default = false
[permissions."luckperms.*".children."luckperms.shit"]
default = false
```... yeah...
or something like that
yeah I am
if TOML forced the use of indentation instead of some whacky . inheritance shit then it would be better imo
Until you try copy paste an indented section and have to spend 20 minutes removing all of the broken spacing
then shift + tab
and tab
oh, HOCON supports .
ez
like, both is the same:
plugin.someconfig.value = 30
plugin {
someconfig {
value = 30
}
}
permissions {
"luckperms.*" {
default: false
children: {
"luckperms.commands.*".default = false,
"luckperms.shit".default = false
}
}
}
```okay yeah that's actually pretty cool
not clean, but cool
also no one question the second child of luckperms.* please xD
yaml is cool until you set country: norway and your program dies
wot
lol what
you mean country: NO
sorry, yeah
not even kidding that's actually a thing that happened once
a company was setting locales, and they set the locale as NO for norway
its v funny
now, YAML's specification is so lenient that it will interpret the unquoted value NO to literally mean no, a.k.a false
💀
and PyYAML somehow also followed that
u have to do 'NO'
nah no shit sherlock
xD
right, anyway, what do we think of ```
name = "LuckPerms"
main = "me.lucko.luckperms.krypton.KryptonLuckPerms"
version = "1.0"
description = "An advanced permissions plugin"
authors = [
"lucko",
"BomBardyGamer"
]
dependencies = ["Vault"]
permissions {
"luckperms." {
default: false
children: {
"luckperms.commands." {
default = false
},
"luckperms.shit" {
default = false
}
}
}
}
it's basically Bukkit minus the useless crap
a.k.a database, load, the single author string, website, prefix, and commands
the things you don't need
load is going because there isn't two loading states like there is in Bukkit
what is prefix?
prefix changes the logger name
what is database?
e.g. ```
2021-03-09 18:19 - [MyPlugin] hello there!
something that should have been removed years ago
it's basically what happens when Bukkit tries to make an ORM for accessing SQL databases
and that went as well as you could expect
Using MySQL increases chances of server crashes unless the database is hosted externally. Your server(s) can crash from reaching maximum HDD space allocated to your server.
epic
as I said, useless feature that should've been removed years ago
since we've moved out of the time where databases were a pain to get hold of or run yourself
oh btw, does HOCON by any chance support optional lists?
because that would be perfect for the authors lol
e.g. you can either have it be a string (single element), or a list (multiple elements)
probably not, but idk lol
also, should I support all the default values Bukkit does for permissions btw?
or should that just be a boolean
I mean, do I really need default states like op and notop?
they seem pretty useless tbh
forget bukkit
right then, boolean it is

forget bukkit, use cljukkit
also, kinda considering your method now BM
but ```kotlin
class MyPlugin(
override val server: Server,
override val folder: File,
override val description: PluginDescriptionFile,
override val logger: Logger
) : Plugin(server, folder, description, logger)
ELON plz
don't you think that is a bit much though BM?
Looks suspiciously similar to bukkit
maybe because this is kinda based off of Bukkit because this is the part of Bukkit I like?
the Command stuff is based off of Bungee's command system because I love that too
if you pass it into the constructor it doesn't need to be an overridden val
true
Bukkkit.getServer
dkim leave
- singleton
getin Kotlin big ew
bukkit::server.ban(dkim)
Krypton.getServer() 🤮
Screw it, run them as separate applications and make them communicate over sockets
what would happen if I try and change a final variable 👀
Try and see
compiler error
wot
are you sure? 👀
yes
I am sure 👀
Formation of a Black Hole
k I'll try it myself and prove you all wrong 👀
it'll throw an exception
intellij wont let u compile
javac
fuck you too Dyno
eclipse
Eclipse would probably compile it
Look into "A Brief History of Time", every time you reassign a final variable, the world ends
wrong image
And a new one begins
exactly
Where the variable is once again final
I will drive you out of this server with pitch fork in hand if you ever mention that word again
I-
Enforced immutability
ok but let mut 🥰
The universe crashes
let mut > let
actually I can't agree with that anyway, since I use val more than var in Kotlin lol
We should work on rewriting specs and maybe improving some of the earlier idea tbf
yes
I do feel like we missed a lot of aspects
Yeah I agree
Having to use parentheses is kinda painful now I'm used to F# and Haskell
although that's a small issue lol
Yea we can remove that
right, so ```kotlin
class MyPlugin(server: Server, folder: File, description: PluginDescriptionFile, logger: Logger) : Plugin(server, folder, description, logger)
bit long that
You don't need val either
actually true
Or indentation
maybe I should just wrap those into a single PluginContext class or something
problem solved
Elara 2 preview
let factorial n = match n
1 => 1
_ => n * fact ( n - 1 )
omg
class MyPlugin(context: PluginContext) : Plugin(context) {
init {
context.server.sendMessage(Component.text("Hello World!")) // yes, Server extends ForwardingAudience so we can do this lol
}
}
now that's concise
Hope not
-_-
what
property access syntax exists
what is that
lol
;-;
plugins["LuckPerms"] instead of getPlugin("LuckPerms") smh
Yea that works
context.server.pluginManager.plugins["LuckPerms"] (dw, plugins will be immutable lol, no enabling and disabling other plugins without pain)
Best of both worlds
kotliners will see one syntax sugar feature and decide that it should be used literally everywhere
Pretty sure that was actually one of my first ideas lol
plugman for krypton when
If you look in #suggestions
Also bardy how are you going to do things like plugin.yml?
plugin.conf
permissions section is redundant and sucks
🥳
Yikes, i think that's pretty meh
I think a plugin annotation sounds better
it's basically Bukkit without the crap
yeah but 1. those get messy with a lot of dependencies and 2. CI/CD compatibility (Souza's point)
what
I first think the same way, but, for versions and stuff like that, it is better to have a file for CI
How is an annotation not compatible with CI
Change code in compilation is not a good idea and is not that easy
That's fair
Why would you need to change it tho?
For example versioning using currently Commit hash
But I'm was thinking @jovial warren , versioning I think should have on a file, but main class I don't think so
Aah good point
Agreed
I think it is not required at all
also, ```kotlin
@Plugin("luckperms", "LuckPerms", "1.0", arrayOf(@Dependency("vault")), "An advanced permissions plugin", authors = ["lucko", "BomBardyGamer"])
maybe I should use the JAR's manifest attribute to find the main class then?
Indentation exists
that sounds like the sensible thing
still messy with indentation
^
You can use [] instead of arrayOf, you why are you repeating "luckperms" twice
lol i thought that too
vault
one is id, the other is name
just what I copied from Sponge
id is what you use to depend on it
name is its name
ew
ew
idfk, Sponge
SPINGE
confusing
yeah we know you are
@Plugin(
name = "LuckPerms",
version = "1.0",
dependencies = [@Dependency("vault")],
description = "An advanced permissions plugin",
authors = ["lucko", "BomBardyGamer"])
._.
@Plugin(
name = "LuckPerms",
version = "1.0",
dependencies = [@Dependency("vault")],
description = "An advanced permissions plugin",
authors = ["lucko", "BomBardyGamer"]
)
tf is up with that highlighting
actually that's not bad
it's the double annotation I think
it gets confused
classic javascript
also, anyone who uses a 2 space indent should be shot
a real language wouldnt
what-
cough Adventure uses a 2 space indent lol cough
Your face is ew
just no
you indent your code?
yeah
pffft
Elara circlejerk incoming
nah
lol
asm circlejerk time
-_-
that word is weird
dont be ridiculous
circle... jerk
also, assembly has indentation
shut
it means exactly what you think it means
mmhm
jvm bytecode "indentation" 🙂
all good languages have indentation 😎
so php is good?
whitespace is great then, huh?
mhm php is good
no joke
yeah that's not what I said
I said all good languages have indentation, I didn't say all languages that have indentation are good
so brainfuck and jvm bytecode arent good?
also
in a "kotlin" language indentation is optional
JVM bytecode isn't exactly a "language" lol
it is
true
eh, true
jvm bytecode absolutely is
a chad language like f# makes indentation a requirement 🙂
absolutely chad language
rust makes bad memory impossible
meanwhile kotlin has messy "conventions" on how many spaces to use
cause the compiler will get on ur ass at the slightest notice
abstract class Plugin(val context: PluginContext)
data class PluginContext(
val server: Server,
val folder: File,
val description: PluginDescriptionFile,
val logger: Logger
)
```is that all I need btw?
You tell me
or does Plugin need some stuff
no successful compilation => no runtime errors. checkmate rust doubters
elon needs to tweet again
what if the Bukkit class was a monad
ffs you and your fucking monads
also, how should I deal with command registering btw?
just store a command map or something?
sexy
what part of "a monad is an endofunctor with two natural transformations" did you not understand?
haskell noob ```hs
do
input <- readline
if condition input then return 3
return 4
haskell pro: hahah, bro do you even monad???
kinda thinking ```kotlin
class MyPlugin(context: PluginContext) : Plugin(context) {
init {
registerCommand(CommandObject)
registerCommand(command("luckperms", "", "lp") {
sender.sendMessage(Component.text("LuckPerms version ${context.description.version} for Krypton ${context.server.info.version}"))
})
}
}
for example
average monad denier: "i dont understand them. they have no purpose. they are confusing. encapsulation is overrated. 👶 "
AVERAGE monad understnader: "i am at peace with the world, the sky is a monad, i hate myself, imperative languages are devil spawn 😌 "
"yes, i would love to listen to a 3 hour talk on the theological implications of the binding operator, why do you ask?"
the sky is an endofunctor with two natural transformations
so true!
feedback pls
where?
registerCommand 🙂
what's implied to be mutable?
well yeah ofc there's a mutable map
commandevent >
commandevent <
thread safety
ah yeah, true
we the people have the right to register commands from Coroutines-Worker-Thread-3
what are you gonna do?? can your "library" handle 1000 threads registering one billion commands at once??? huh???! didn't think so.
precisely!!
you mean Krypton-Command-Worker-3
or something like that
me wants own dispatcher 🙂
can it really be called "production ready" if it doesnt function under my biased test that doesnt represent a real world scenario?
can any software really be called "production ready"?
yes
I think not
? pdm is
^^
his face
you wish
the clever minds are working on a haskell port at the moment
sadly not
since there's not really any runtime loading stuff
there's no classes to load
lol
wtf even is a monad
maybe even too many
nobody knows
one of the great mysteries of life
what does PDM do
downloads things
w o t
homework folder
downloads your dependencies at runtime and injects them into classpath
mutates global state
boom
depends on external data
like luckperms
🙂
I don't know if a do a PR for PDM or refactor the hole thing
depends strongly on 3rd party websites
the Gradle plugin does not look so great
hole
yeah it is a huge mess
the Currently maven own library will not be required anymore
I think I will try to do everything from the ground and make a PR
okay ❤️
try to use the same PDM dependencies.json structure
but whi maven aether, it will not required anymore
you dont need to worry about backwards compatibility too much but yeah if you could that would be nice
In functional programming, a monad is an abstraction that allows structuring programs generically. Supporting languages may use monads to abstract away boilerplate code needed by the program logic. Monads achieve this by providing their own data type (a particular type for each type of monad), which represents a specific form of computation, along with two procedures:
One to wrap values of any basic type within the monad (yielding a monadic value);
Another to compose functions that output monadic values (called monadic functions).[1]
Optional in Java is technically a monad
I have a suggestion for PDM, allow us to set a "proxy" where PDM will search the libs from to download them, instead of searching them from their own repositories
Optional sucks!
(from Kotlin perspective)
Sponge API only use this for null safety
could you elaborate a bit?
that might already exist
you can already set what maven central mirror you want to use
the rest is just dictated by your buildscript
currently PDM looks all repositories to find where the libraries to in the future (running the plugin) search directly in this repository
What I know exists is your own host where you save that right?
My suggestion is to let users set their own
Like pdm.dependencyUrl = "https://mattstudios.me/dependencies/
hmm
well, the issue is java 16
that url would have to be a maven repository
you should have your own maven host
yes 😟
im still trying to figure out a good way
that is not a problem
fefo suggested of using a custom class loader
what happens in java 16?
just put repositories { maven("https://mattstudios.me/dependencies/") }
and you are good to go
pdm hacks break
yea
hacks?
Would it need to be a maven repo? Because my idea would be to have it be just a provider to download the jar
luckperms was using it and they had to switch to jarinjar
probably. since it needs to get specific versions, transitive dependencies etc
well, maven repo is the best you can use
