Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixxing Crash Exploits #69

Open
wants to merge 105 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
05e1ef4
Fixed NPE when KommonCommand fails to parse the command
DSeeLP Apr 29, 2021
d38b3d6
Fixed maven build
DSeeLP Apr 29, 2021
6d84225
Fixed issue that only the root node could be executed.
DSeeLP Apr 29, 2021
daa447f
Added Tab-Completion
DSeeLP Apr 29, 2021
7a06038
Added boolean argument to KTestCommand
DSeeLP Apr 29, 2021
edfbafc
Fixed issue that the complete function always returned nothing
DSeeLP Apr 29, 2021
ffc7d70
Bumped KommonCommand version to 0.1.1
DSeeLP May 2, 2021
0465faf
Command completer now respects the checkAccess method
DSeeLP May 4, 2021
e9a3be4
Bumped Kotlin version to 1.5.0
DSeeLP May 6, 2021
b98a695
Bumped KommonCommand to version 0.2.2
DSeeLP May 13, 2021
653ab38
Merge branch 'command' into development
PXAV May 24, 2021
597ad46
Merge branch 'development' into development
PXAV May 24, 2021
b485ccd
Merge pull request #65 from DSeeLP/development
PXAV May 24, 2021
97b546f
Fix lowercase checks in CommandDispatcher
PXAV May 24, 2021
8fc62bf
Remove duplicated compiler plugin
PXAV May 24, 2021
a1c750b
Bump Kotlin version 1.5.0 again (deleted on merge by accident)
PXAV May 24, 2021
4d05af0
Remove redundant field from NpcToggleSneakEvent
PXAV May 25, 2021
fb70ee4
refactor: Rename NpcInteractAction to EntityInteractAction
PXAV May 25, 2021
211197b
refactor: Move EntityInteractAction to general event package
PXAV May 25, 2021
23b7d6f
Add ImageChar class representing chars for an image message
PXAV May 25, 2021
adc9011
Add ImageMessage class building chat messages from images
PXAV May 25, 2021
95dd0f9
Remove writeLog feature from Kelp logger
PXAV May 26, 2021
70e9182
Kelp loggers are now registered for each application on startup
PXAV May 26, 2021
2d4d69f
Adjust version implementation logger name in KelpPlugin
PXAV May 26, 2021
9f2df3d
Apply new logger syntax in code module
PXAV May 26, 2021
0245fb5
Debug mode config is now obeyed by KelpLogger
PXAV May 26, 2021
524b466
Remove LogLevel.java enum
PXAV May 26, 2021
2336efc
Use new logging system in v1.8 implementation
PXAV May 26, 2021
f00b903
Fix player constructor in entity type implementation
PXAV May 26, 2021
14e6164
Add documentation to KelpLogger
PXAV May 26, 2021
336dbf9
Add documentation to KelpPotionEffect
PXAV May 26, 2021
f087d76
Add documentation to PotionListener
PXAV May 26, 2021
a503e46
Add documentation to MinecraftPotion
PXAV May 26, 2021
a62df3a
ImageMessage now accepts RGB colors for 1.16+ servers
PXAV May 26, 2021
3104467
Merge image char values into DefaultFontSize enum
PXAV May 26, 2021
0f1b7dc
refactor: Rename DefaultFontSize.java to DefaultFont
PXAV May 26, 2021
f69c296
Color is now a subclass of java.awt.color and has more util methods f…
PXAV May 26, 2021
b383154
Apply builder design to ImageMessage
PXAV May 26, 2021
a152033
You can now insert components in an InteractiveMessage
PXAV May 27, 2021
c53ce36
Add method to get the text displayed by an InteractiveMessage
PXAV May 27, 2021
1494185
Remove logger artifacts from KelpPlayerRepository
PXAV May 27, 2021
07fc448
You can now also append text with interactive messages in an ImageMes…
PXAV May 27, 2021
c556bff
Add documentation to ImageMessage
PXAV May 27, 2021
9e1cb12
Add basic hologram class
PXAV May 30, 2021
75b9603
Add basic hologram components for text and items
PXAV May 30, 2021
1ba17b4
Add some more advanced hologram text components
PXAV May 30, 2021
d3976f9
You can now spawn holograms
PXAV May 30, 2021
a5dbfa4
Add method to modify the spacing between hologram lines
PXAV May 30, 2021
745ef71
Implement despawn mechanics in VersionedHologram
PXAV May 31, 2021
9b7273e
Holograms are now player-dependent as they are rendered client-side a…
PXAV May 31, 2021
9d0c57d
Add HologramRepository adding auto-spawn activities to Holograms
PXAV May 31, 2021
858c271
Add equals and hashCode to KelpHologram
PXAV May 31, 2021
72d8ef0
Add documentation to ReflectionUtil
PXAV May 31, 2021
ab32aac
Fix bug that clime could not be cast to MobileEntity
PXAV Jun 1, 2021
d8ef493
You can now enable/disable gravity for every entity with a small work…
PXAV Jun 1, 2021
b10bd43
Make contains() method of CuboidRegion a bit more efficient
PXAV Aug 3, 2021
3936407
Fix ParticleLineEffect by changing default particleDensity to 0.1
PXAV Aug 9, 2021
ca13045
You can now get an entity's bounding box/hitbox as a cuboid region
PXAV Aug 9, 2021
fa11f95
Add classes to visualize specific things with particles
PXAV Aug 9, 2021
8c9a1e8
The boundaries of a KelpRegion can now be visualized with particles
PXAV Aug 9, 2021
45dfe20
You can now get the entities inside a specific KelpChunk
PXAV Aug 9, 2021
b573752
Implement getEntities method of KelpChunk for 1.8 with reflection and…
PXAV Aug 9, 2021
9ce3f00
Make ParticleLineEffect cloneable
PXAV Aug 9, 2021
97db6b0
Add base credits to ImageMessage documentation
PXAV Aug 9, 2021
c3347e5
Remove ParticleEffectFactory.java as every effect now as an own stati…
PXAV Aug 9, 2021
0bb8d28
Add two 16x16 demo images to resources folder allowing to easily test…
PXAV Aug 9, 2021
2ec4c54
Add method to get the KelpWorld object of a KelpLocation
PXAV Aug 9, 2021
4980c00
Implement basic raycast mechanics
PXAV Aug 9, 2021
c626a41
Remove debug message 'is living entity' from VersionedEntityType
PXAV Aug 9, 2021
3077326
Fix entity type of SilverfishEntity
PXAV Aug 14, 2021
4f85d0d
Introduce custom Vector3 type offering a version-independent alternat…
PXAV Aug 14, 2021
2c73cbe
Remove CardinalDirection.java enum as it is redundant
PXAV Aug 14, 2021
b217f4b
Add method to get the bounding box of a KelpBlock
PXAV Aug 14, 2021
df77932
Add getPosition() and isOnLine() functions to Vector3
PXAV Aug 14, 2021
904badd
Rename length methods of Vector3 to magnitude
PXAV Aug 14, 2021
29c416e
Fix bug that contains(KelpLocation) method returned incorrect results
PXAV Aug 14, 2021
d01c53c
Implement ParticleVisualizable for Rays
PXAV Aug 15, 2021
78131c5
Add ray implementation scanning for entities
PXAV Aug 15, 2021
bb104e3
calling getType() on KelpPlayer now actually returns PLAYER
PXAV Aug 15, 2021
a0b52af
Add method to KelpWorld to check whether a chunk is loaded or not bef…
PXAV Aug 15, 2021
094436a
Make Rays generic for fluent builder design
PXAV Aug 15, 2021
9adb515
Replace type ignore lists with a list of predicates that have to be f…
PXAV Aug 15, 2021
89815c8
Add a method to set values of the parent class of an object to Reflec…
PXAV Aug 15, 2021
ac164dd
Add sameEntity() method to KelpEntity offering a replacement for an e…
PXAV Aug 15, 2021
57fc414
Fix bug that hitDistance of EntityRay was always equal to the distanc…
PXAV Aug 15, 2021
c6ba0cf
Add method to RaycastHit giving information about which ray (type) hi…
PXAV Aug 15, 2021
8cadff0
You can now configure the accuary of EntityRay checks
PXAV Aug 15, 2021
256a144
Do some optimization to GlobalPacketListener
PXAV Aug 15, 2021
5db2089
Small code cleanup of ParticleLineEffect
PXAV Aug 15, 2021
8dfc821
Add base class for AnimatedMessages
PXAV Aug 15, 2021
3a034bd
Add base class for block raycasting
PXAV Aug 15, 2021
5460bdc
Apply refactor changes of EntityInteractAction to NpcInteractEvent
PXAV Aug 15, 2021
2f615e2
Remove component system of hologram library
PXAV Aug 15, 2021
6b1ad52
Add base event classes for different hologram events
PXAV Aug 15, 2021
1f83589
HologramRepository is now using Kelp's concurrent multimaps
PXAV Aug 15, 2021
0ded6c1
KelpHologram is now using lines instead of components
PXAV Aug 15, 2021
3af5ae1
Add base interface for hologram lines
PXAV Aug 15, 2021
d952a50
Add text hologram line, which is able to display simple strings in a …
PXAV Aug 15, 2021
03e58d8
Add item hologram line displaying phantom items inside a hologram
PXAV Aug 15, 2021
992446b
Add dummy hologram line used for generating empty space between lines
PXAV Aug 15, 2021
de43d8d
Add incomplete changelog for hologram release
PXAV Aug 15, 2021
ab6a076
Implement new logger system in testing module
PXAV Aug 15, 2021
f4661d4
Fix bug when entering an out-of-range bossbar progress in correspondi…
PXAV Aug 15, 2021
cf1f5ed
Apply EntityInteractAction refactor to NpcSpawnCommand of testing module
PXAV Aug 15, 2021
3238a48
Implement new line-based hologram system for 1.8 servers
PXAV Aug 15, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
58 changes: 58 additions & 0 deletions CHANGELOG/kelp-v0.4.1.md
@@ -0,0 +1,58 @@
# v0.5.0
> Release date: unknown

**The hologram and raycasting update**:

* Change `KelpLogger` to be more compact and simple:
* Remove own logging files and folder. During development, this custom folder has not proven as useful and just ate resources that could have been used better.
* `KelpLogger` is now a subclass of `java.util.logger.Logger` and therefore Java's default logging methods are used.
* Remove `LogLevel` enum as Java's log levels are now used, where `FINE`, `FINER`, `FINEST`, and `CONFIG` are only shown in debug mode.
* Properly link loggers to their corresponding kelp applications: `KelpLogger.of(YourPluginMainClass.class).info(...)`
* When logging from the core module, use `KelpLogger.of(KelpApplication.class)...`
* This way you don't have to let Guice inject the logger for you, reducing boilerplate dependencies.
* Add Raycasting library. You can create a new Raycast using `Raycast.create()`. For more info, check the corresponding wiki page.
* You can now insert components at a specific index in an `InteractiveMessage`, which required to change the component list type from `Collection<...>` to `List<...>`. **If your plugin used `getComponents()`, then you will have to recompile it to update the method signature!**
* The raw text (excluding color codes) of `InteractiveMessages` can now be queried using `getRawText()`
* Add `ImageMessage` allowing you to display image files in the chat.
* Gravity can now be disabled for all entities. This is a native feature in newer versions, for 1.8 a workaround has been made by spawning no-gravity armor stands and setting the entity as passenger.
* Fix bug that `SlimeEntity` could not be spawned because it could not be cast to a mob/creature in `1.8`.
* Add `getEntities()` method to `KelpChunk`
* Fix bug that `getPlayers()` method of `KelpChunk` threw a `NoSuchFieldError`
* This was because the CraftBukkit API and the NMS code of the spigot server differed and had different method signatures of `entitySlice` (the way how entities within a chunk are represented)
* So now the `entitySlice` is accessed via reflection, which might negatively impact performance of methods depending on it (currently `getPlayers` and `getEntities`)
* Add debug tool to particle library: `ParticleVisualizable`
* It can be implemented by any class that can be visualized in the in-game world with particles such as regions or raycasts.
* You can apply different color schemes by using another `ParticleVisualizerProfile`
* Rename `getOuterCorners()` of `KelpRegion` to `getCuboidOuterCorners()`
* The cuboid outer corners now have a defined order used by the `visualize` methods of regions
* Therefore, there should be no confusion with the cuboid outer corners and custom implementations such as in a `MergerdRegion`
* You can now get an entities hitbox/bounding box as a `CuboidRegion`
* You can now get a block's collision or selection bounding box as `CuboidRegion`
* Particle effects such as `ParticleLineEffect` are now cloneable and have static factories instead of a separate factory class
* Remove `CardinalDirection` and replace it with `KelpBlockFace` wherever it was used. It was basically the same as `KelpBlockFace` with lower accuracy and is therefore considered redundant.
* Create own `Vector3` class offering a version-independent alternative to bukkit's normal `Vector` class.
* Add a method (`setValue(Class, Object, String, Object)`) to `ReflectionUtil` allowing to set the value of a field declared in any parent class of the given object.
* You can now compare two entities using `KelpEntity#sameEntity(Object)` offering an alternative to the `equals()` method, which can not be overridden due to language limitations.























115 changes: 59 additions & 56 deletions core/pom.xml
Expand Up @@ -81,65 +81,68 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>kotlin-compile</id>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<jvmTarget>1.8</jvmTarget>
<sourceDirs>
<sourceDir>${project.basedir}/src/main/java</sourceDir>
</sourceDirs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<executions>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
<execution>
<id>compile</id>
<phase>compile</phase>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>kotlin-compile</id>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
<goal>compile</goal>
</goals>
</execution>
</executions>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<jvmTarget>1.8</jvmTarget>
<sourceDirs>
<sourceDir>${project.basedir}/src/main/java</sourceDir>
</sourceDirs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<executions>
<!-- Replacing default-compile as it is treated specially by maven -->
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<!-- Replacing default-testCompile as it is treated specially by maven -->
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>java-test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>

<resources>
Expand Down
18 changes: 12 additions & 6 deletions core/src/main/java/de/dseelp/kommon/command/CommandBuilder.kt
Expand Up @@ -66,10 +66,6 @@ class CommandBuilder<S: Any>(
childs += CommandBuilder<S>(argument = argument).apply(block).build()
}

/*fun argument(argument: Argument<*>) {
arguments+=argument
}*/

fun build(): CommandNode<S> {
if (name == null && argument == null) throw IllegalStateException("An command node must have a name or an argument!")
if (target != null && childs.isNotEmpty()) throw IllegalStateException("Cannot forward a node with children")
Expand All @@ -81,7 +77,7 @@ class CommandBuilder<S: Any>(
this.apply(block)
}

fun <I: Any, O: Any?> map(name: String, mapper: CommandContext<S>.(input: I) -> O) {
fun <I : Any, O : Any?> map(name: String, mapper: CommandContext<S>.(input: I) -> O) {
@Suppress("UNCHECKED_CAST")
mappers = mappers + (name to mapper as CommandContext<S>.(input: Any) -> Any?)
}
Expand All @@ -90,4 +86,14 @@ class CommandBuilder<S: Any>(
private set
}

fun <T: Any> command(name: String, block: CommandBuilder<T>.() -> Unit): CommandNode<T> = CommandBuilder<T>(name).apply(block).build()
@Deprecated(
message = "This deprecated in favor of literal and will be removed in the future",
replaceWith = ReplaceWith("literal(name, block)")
)
fun <S : Any> command(name: String, block: CommandBuilder<S>.() -> Unit): CommandNode<S> = literal(name, block)

fun <S : Any> literal(name: String, block: CommandBuilder<S>.() -> Unit): CommandNode<S> =
CommandBuilder<S>(name).apply(block).build()

fun <T : Any> argument(argument: Argument<T, *>, block: CommandBuilder<T>.() -> Unit): CommandNode<T> =
CommandBuilder<T>(argument = argument).apply(block).build()
14 changes: 7 additions & 7 deletions core/src/main/java/de/dseelp/kommon/command/CommandDispatcher.kt
@@ -1,6 +1,7 @@
package de.dseelp.kommon.command

import de.dseelp.kommon.command.arguments.ParsedArgument
import java.util.*

/**
* @author DSeeLP
Expand All @@ -14,7 +15,7 @@ class CommandDispatcher<S : Any> {
}

fun register(name: String, block: CommandBuilder<S>.() -> Unit) {
register(command(name, block))
register(literal(name, block))
}

fun register(builder: JavaCommandBuilder<S>) {
Expand All @@ -27,12 +28,12 @@ class CommandDispatcher<S : Any> {
}

fun getNode(name: String, useAliases: Boolean = false): CommandNode<S>? {
val lowercaseName = name.toLowerCase()
val lowercaseName = name.toLowerCase(Locale.getDefault())
for (node in nodes) {
if (node.name!!.toLowerCase() == lowercaseName) return node
if (node.name!!.toString().toLowerCase(Locale.getDefault()) == lowercaseName) return node
if (useAliases) {
for (alias in node.aliases) {
if (alias.toLowerCase() == lowercaseName) return node
if (alias.toLowerCase(Locale.getDefault()) == lowercaseName) return node
}
}
}
Expand Down Expand Up @@ -255,14 +256,13 @@ class CommandDispatcher<S : Any> {
if (newArgs.isEmpty()) {
val strings = mutableSetOf<String>()
node.childs
.filter { it.checkAccess.invoke(context) }
.mapNotNull { it.argumentIdentifier }
.map { it.complete(context, current) }
.forEach { strings.addAll(it) }
node.childs.filter { it.argumentIdentifier == null }.forEach { strings.addAll(it.aliases + it.name!!) }
node.childs.filter { it.checkAccess.invoke(context) }.filter { it.argumentIdentifier == null }.forEach { strings.addAll(it.aliases + it.name!!) }
return strings.toTypedArray()
}
return arrayOf()
}


}
@@ -1,6 +1,9 @@
package de.dseelp.kommon.command;

import de.dseelp.kommon.command.arguments.*;
import kotlin.jvm.functions.Function1;

import java.util.UUID;

/**
* @author DSeeLP
Expand Down Expand Up @@ -32,13 +35,41 @@ public static IntArgument integerArgument(String name) {
return new IntArgument(name);
}

public static IntArgument integerArgument(String name, Function1<CommandContext, Integer[]> completer) {
return new IntArgument(name, completer);
}

public static DoubleArgument doubleArgument(String name) {
return new DoubleArgument(name);
}

public static DoubleArgument doubleArgument(String name, Function1<CommandContext, Double[]> completer) {
return new DoubleArgument(name, completer);
}

public static LongArgument longArgument(String name) {
return new LongArgument(name);
}

public static LongArgument longArgument(String name, Function1<CommandContext, Long[]> completer) {
return new LongArgument(name, completer);
}


public static UUIDArgument uniqueIdArgument(String name) {
return new UUIDArgument(name);
}

public static UUIDArgument uniqueIdArgument(String name, Function1<CommandContext, UUID[]> completer) {
return new UUIDArgument(name, completer);
}


public static StringArgument stringArgument(String name) {
return new StringArgument(name);
}

public static StringArgument stringArgument(String name, Function1<CommandContext, String[]> completer) {
return new StringArgument(name, completer);
}
}
Expand Up @@ -5,13 +5,17 @@ import de.dseelp.kommon.command.CommandContext
/**
* @author DSeeLP
*/
class BooleanArgument<S: Any>(name: String, trueString: String = "true", falseString: String = "false") : Argument<S, Boolean>(name) {
constructor(name: String): this(name, trueString = "true")

class BooleanArgument<S : Any> @JvmOverloads constructor(
name: String,
trueString: String = "true",
falseString: String = "false"
) : Argument<S, Boolean>(name) {
override fun get(value: String): Boolean? = value.toBooleanOrNull()
override fun getErrorMessage(): String = "%s is not a boolean"
private val possibleValues = arrayOf(trueString, falseString)
override fun complete(context: CommandContext<S>, value: String): Array<String> = possibleValues.filter { value.toLowerCase().startsWith(it) }.toTypedArray()
override fun complete(context: CommandContext<S>, value: String): Array<String> =
possibleValues.filter { it.toLowerCase().startsWith(value) }.toTypedArray()
}

fun String.toBooleanOrNull(trueString: String = "true", falseString: String = "false"): Boolean? = if (toLowerCase() == trueString) true else if (toLowerCase() == falseString) false else null
fun String.toBooleanOrNull(trueString: String = "true", falseString: String = "false"): Boolean? =
if (toLowerCase() == trueString) true else if (toLowerCase() == falseString) false else null
Expand Up @@ -5,8 +5,12 @@ import de.dseelp.kommon.command.CommandContext
/**
* @author DSeeLP
*/
class DoubleArgument<S: Any>(name: String) : Argument<S, Double>(name) {
class DoubleArgument<S : Any> @JvmOverloads constructor(
name: String,
val completer: CommandContext<S>.() -> Array<Double> = { arrayOf() }
) : Argument<S, Double>(name) {
override fun get(value: String): Double? = value.toDoubleOrNull()
override fun getErrorMessage(): String = "%s is not an Double"
override fun complete(context: CommandContext<S>, value: String): Array<String> = arrayOf()
override fun complete(context: CommandContext<S>, value: String): Array<String> =
completer.invoke(context).map { it.toString() }.filter { value.startsWith(it, true) }.toTypedArray()
}
Expand Up @@ -5,10 +5,14 @@ import de.dseelp.kommon.command.CommandContext
/**
* @author DSeeLP
*/
class IntArgument<S: Any>(name: String, val completer: CommandContext<S>.() -> Array<Int> = { arrayOf() }) : Argument<S, Int>(name) {
constructor(name: String): this(name, { arrayOf() })
class IntArgument<S : Any> @JvmOverloads constructor(
name: String,
val completer: CommandContext<S>.() -> Array<Int> = { arrayOf() }
) :
Argument<S, Int>(name) {

override fun get(value: String): Int? = value.toIntOrNull()
override fun getErrorMessage(): String = "%s is not an Integer"
override fun complete(context: CommandContext<S>, value: String): Array<String> = completer.invoke(context).map { it.toString() }.filter { value.startsWith(it, true) }.toTypedArray()
override fun complete(context: CommandContext<S>, value: String): Array<String> =
completer.invoke(context).map { it.toString() }.filter { value.startsWith(it, true) }.toTypedArray()
}