currently refactoring a lot

This commit is contained in:
kento2 2026-07-04 16:29:05 +02:00
parent a32805a623
commit 700b5d5d10
20 changed files with 406 additions and 292 deletions

93
.idea/workspace.xml generated
View file

@ -5,52 +5,26 @@
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="56c685a1-f609-4ffd-a951-849beb2a7f8d" name="Changes" comment="currently refactoring a lot"> <list default="true" id="56c685a1-f609-4ffd-a951-849beb2a7f8d" name="Changes" comment="currently refactoring a lot">
<change afterPath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/scheduler/Task.java" afterDir="false" /> <change afterPath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/scheduler/TaskState.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/scheduler/TaskImpl.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/scheduler/Tasks.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/command/CoinsCommand.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/command/CoinsGetLiteral.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/command/CoinsSetLiteral.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../build-logic/convention/src/main/kotlin/de/kentoj/scrow/DatabaseConvention.kt" beforeDir="false" afterPath="$PROJECT_DIR$/../build-logic/convention/src/main/kotlin/de/kentoj/scrow/DatabaseConvention.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-api/build.gradle.kts" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-api/build.gradle.kts" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/scheduler/Task.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/scheduler/Task.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/EconomyService.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/misc/EconomyService.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/scheduler/TaskImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/scheduler/TaskImpl.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/PlayerManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/misc/PlayerManager.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/scheduler/Tasks.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/scheduler/Tasks.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ScrowAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ScrowAPI.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/command/CoinsCommand.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/command/CoinsCommand.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/friends/FriendRequestService.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/friends/FriendRequestService.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/command/CoinsGetLiteral.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/command/CoinsGetLiteral.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/friends/FriendshipService.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/friends/FriendshipService.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/command/CoinsSetLiteral.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/command/CoinsSetLiteral.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/build.gradle.kts" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/build.gradle.kts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/CoreImplPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/CoreImplPlugin.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/ScrowAPISurface.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/ScrowAPISurface.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownDeployServerLiteral.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownDeployServerLiteral.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownDestroyServerLiteral.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownDestroyServerLiteral.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownListServersLiteral.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownListServersLiteral.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/CoinsCommand.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/InMemoryEconomyService.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/InMemoryEconomyService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/MongoEconomyService.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/PostgresEconomyService.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/PostgresEconomyService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendAddLiteral.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendAddLiteral.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendAddLiteral.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendAddLiteral.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendCommand.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendCommand.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendCommand.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendCommand.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendListLiteral.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendListLiteral.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendListLiteral.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendListLiteral.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendRemoveLiteral.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendRemoveLiteral.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendRemoveLiteral.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendRemoveLiteral.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendRequestsLiteral.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendRequestsLiteral.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendRequestsLiteral.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendRequestsLiteral.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/friendship/InMemoryFriendshipService.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/friendship/InMemoryFriendshipService.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/friendship/InMemoryFriendshipService.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/friendship/InMemoryFriendshipService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/friendship/MongoFriendshipService.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/friendship/PostgresFriendshipService.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/friendship/PostgresFriendshipService.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/friendship/PostgresFriendshipService.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/friendship/PostgresFriendshipService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/request/InMemoryFriendRequestService.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/request/InMemoryFriendRequestService.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/request/FriendRequestImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/request/FriendRequestImpl.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/request/MongoFriendRequestService.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/request/PostgresFriendRequestService.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/request/PostgresFriendRequestService.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/request/PostgresFriendRequestService.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/request/PostgresFriendRequestService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/playermanager/PlayerManagerImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/playermanager/PlayerManagerImpl.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/server/LobbyCommand.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/server/LobbyCommand.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/server/LobbyCommand.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/server/LobbyCommand.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/server/PlayCommand.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/server/PlayCommand.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/server/PlayCommand.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/server/PlayCommand.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-lib/build.gradle.kts" beforeDir="false" afterPath="$PROJECT_DIR$/core-lib/build.gradle.kts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/InstanceManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/InstanceManager.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/InstanceManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/InstanceManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/InstanceManagerImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/InstanceManagerImpl.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-velocity-api/build.gradle.kts" beforeDir="false" afterPath="$PROJECT_DIR$/core-velocity-api/build.gradle.kts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/command/OnlineCommand.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/command/OnlineCommand.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/privmsg/MsgCommand.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/privmsg/MsgCommand.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/privmsg/ReplyCommand.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/privmsg/ReplyCommand.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/server/ServerRegisterWatchdog.java" beforeDir="false" afterPath="$PROJECT_DIR$/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/server/ServerRegisterWatchdog.java" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -149,6 +123,9 @@
<component name="HighlightingSettingsPerFile"> <component name="HighlightingSettingsPerFile">
<setting file="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.projectreactor/reactor-core/3.8.5/ed6c3f423d84bf282e50a4f7432a8d65af321efb/reactor-core-3.8.5-sources.jar!/reactor/core/publisher/Mono.java" root0="SKIP_INSPECTION" /> <setting file="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.projectreactor/reactor-core/3.8.5/ed6c3f423d84bf282e50a4f7432a8d65af321efb/reactor-core-3.8.5-sources.jar!/reactor/core/publisher/Mono.java" root0="SKIP_INSPECTION" />
</component> </component>
<component name="ProblemsViewState">
<option name="autoscrollToSource" value="true" />
</component>
<component name="ProjectColorInfo">{ <component name="ProjectColorInfo">{
&quot;customColor&quot;: &quot;&quot;, &quot;customColor&quot;: &quot;&quot;,
&quot;associatedIndex&quot;: 0 &quot;associatedIndex&quot;: 0
@ -161,31 +138,31 @@
<option name="hideEmptyMiddlePackages" value="true" /> <option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" /> <option name="showLibraryContents" value="true" />
</component> </component>
<component name="PropertiesComponent">{ <component name="PropertiesComponent"><![CDATA[{
&quot;keyToString&quot;: { "keyToString": {
&quot;Gradle.Download Sources.executor&quot;: &quot;Run&quot;, "Gradle.Download Sources.executor": "Run",
&quot;Gradle.core [build].executor&quot;: &quot;Debug&quot;, "Gradle.core [build].executor": "Run",
&quot;Gradle.core [clean].executor&quot;: &quot;Run&quot;, "Gradle.core [clean].executor": "Run",
&quot;Gradle.core [publishAllPublicationsToScrowRepository].executor&quot;: &quot;Run&quot;, "Gradle.core [publishAllPublicationsToScrowRepository].executor": "Run",
&quot;Gradle.core [publishCoreLibPublicationToScrowRepository].executor&quot;: &quot;Run&quot;, "Gradle.core [publishCoreLibPublicationToScrowRepository].executor": "Run",
&quot;Gradle.core:core-bukkit-api [build].executor&quot;: &quot;Run&quot;, "Gradle.core:core-bukkit-api [build].executor": "Run",
&quot;Gradle.core:core-bukkit-api [clean].executor&quot;: &quot;Run&quot;, "Gradle.core:core-bukkit-api [clean].executor": "Run",
&quot;Gradle.core:core-lib [publishAllPublicationsToScrowRepository].executor&quot;: &quot;Run&quot;, "Gradle.core:core-lib [publishAllPublicationsToScrowRepository].executor": "Run",
&quot;Gradle.core:core-lib [publishCoreLibPublicationToMavenLocal].executor&quot;: &quot;Run&quot;, "Gradle.core:core-lib [publishCoreLibPublicationToMavenLocal].executor": "Run",
&quot;Gradle.core:core-lib [publishCoreLibPublicationToScrowRepository].executor&quot;: &quot;Run&quot;, "Gradle.core:core-lib [publishCoreLibPublicationToScrowRepository].executor": "Run",
&quot;ModuleVcsDetector.initialDetectionPerformed&quot;: &quot;true&quot;, "ModuleVcsDetector.initialDetectionPerformed": "true",
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;, "RunOnceActivity.ShowReadmeOnStart": "true",
&quot;RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252&quot;: &quot;true&quot;, "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
&quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;, "RunOnceActivity.git.unshallow": "true",
&quot;git-widget-placeholder&quot;: &quot;master&quot;, "git-widget-placeholder": "master",
&quot;kotlin-language-version-configured&quot;: &quot;true&quot;, "kotlin-language-version-configured": "true",
&quot;last_opened_file_path&quot;: &quot;/home/a/src/scrow&quot;, "last_opened_file_path": "/home/a/src/scrow",
&quot;project.structure.last.edited&quot;: &quot;Project&quot;, "project.structure.last.edited": "Project",
&quot;project.structure.proportion&quot;: &quot;0.15&quot;, "project.structure.proportion": "0.15",
&quot;project.structure.side.proportion&quot;: &quot;0.6268199&quot;, "project.structure.side.proportion": "0.6268199",
&quot;settings.editor.selected.configurable&quot;: &quot;preferences.pluginManager&quot; "settings.editor.selected.configurable": "preferences.pluginManager"
} }
}</component> }]]></component>
<component name="RecentsManager"> <component name="RecentsManager">
<key name="CreateClassDialog.RecentsKey"> <key name="CreateClassDialog.RecentsKey">
<recent name="de.kentoj.scrow.bukkit.economy.command" /> <recent name="de.kentoj.scrow.bukkit.economy.command" />

View file

@ -1,13 +1,15 @@
package de.kentoj.scrow.bukkit.scheduler; package de.kentoj.scrow.bukkit.scheduler;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier; import java.util.function.Supplier;
public interface Task<T> { public interface Task<T> {
CompletableFuture<T> asFuture(); CompletableFuture<T> toFuture();
default Task<?> runSync(Runnable task) { default Task<?> runSync(Runnable task) {
return mapSync(__ -> { return mapSync(__ -> {
@ -48,4 +50,17 @@ public interface Task<T> {
} }
<S> Task<S> mapAsync(Function<T, S> mapper); <S> Task<S> mapAsync(Function<T, S> mapper);
Task<T> yieldIf(Predicate<T> precondition);
default T await() {
try {
return toFuture().get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
} }

View file

@ -1,8 +1,10 @@
package de.kentoj.scrow.bukkit.scheduler; package de.kentoj.scrow.bukkit.scheduler;
import com.google.common.base.Preconditions;
import de.kentoj.scrow.bukkit.ScrowAPI; import de.kentoj.scrow.bukkit.ScrowAPI;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -10,47 +12,85 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier; import java.util.function.Supplier;
import static com.google.common.base.Preconditions.*;
/** /**
* A Task runs entirely async, when sync is used, a subtask is run on the main thread and the async thread * A Task runs entirely async, when sync is used, a subtask is run on the main thread and the async thread
* blocks until the subtask returns. * blocks until the subtask returns.
* *
* @param <T> type of computed result * @param <T> type of computed result
*/ */
@Slf4j
@RequiredArgsConstructor(access = AccessLevel.PACKAGE) @RequiredArgsConstructor(access = AccessLevel.PACKAGE)
public class TaskImpl<T> implements Task<T> { public class TaskImpl<T> implements Task<T> {
private static final ExecutorService EXECUTOR = Executors.newVirtualThreadPerTaskExecutor(); private static final ExecutorService EXECUTOR = Executors.newVirtualThreadPerTaskExecutor();
private final Supplier<T> compute; private final Supplier<TaskState<T>> compute;
private TaskState<T> cachedResult = null;
@Override @Override
public CompletableFuture<T> asFuture() { public CompletableFuture<T> toFuture() {
return CompletableFuture.supplyAsync(compute, EXECUTOR); return CompletableFuture.supplyAsync(() -> state().getValue(), EXECUTOR);
} }
/** /**
* Maps the last result on the main thread * Maps the last result on the main thread
*/ */
public <S> Task<S> mapSync(Function<T, S> mapper) { public <S> Task<S> mapSync(Function<T, S> mapper) {
Supplier<S> supplier = () -> { return new TaskImpl<>(() -> {
var s = state();
if (s.isYielded()) return yielded(s);
try { try {
return Bukkit.getScheduler().callSyncMethod(ScrowAPI.plugin, () -> mapper.apply(compute.get())).get(); return TaskState.completed(Bukkit.getScheduler()
.callSyncMethod(ScrowAPI.plugin, () -> mapper.apply(s.getValue()))
.get());
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (ExecutionException e) { } catch (ExecutionException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
}; });
return new TaskImpl<>(supplier);
} }
/** /**
* Maps the last result async * Maps the last result async
*/ */
public <S> Task<S> mapAsync(Function<T, S> mapper) { public <S> Task<S> mapAsync(Function<T, S> mapper) {
return new TaskImpl<>(() -> mapper.apply(compute.get())); return new TaskImpl<>(() -> {
var s = state();
if (s.isYielded()) return yielded(s);
return TaskState.completed(mapper.apply(state().getValue()));
});
}
@Override
public Task<T> yieldIf(Predicate<T> precondition) {
var s = state();
if (!s.isYielded() && precondition.test(s.getValue())) {
return new TaskImpl<>(() -> TaskState.yielded(s.getValue()));
}
return this;
}
@SuppressWarnings("unchecked")
private <S> TaskState<S> yielded(TaskState<T> state) {
try {
return (TaskState<S>) state;
} catch (ClassCastException ex) {
log.error("cannot yield when type of next task differs", ex);
throw ex;
}
}
private TaskState<T> state() {
if (cachedResult == null)
cachedResult = compute.get();
return cachedResult;
} }
} }

View file

@ -0,0 +1,20 @@
package de.kentoj.scrow.bukkit.scheduler;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.Nullable;
@Getter
@RequiredArgsConstructor
public class TaskState<T> {
private final @Nullable T value;
private final boolean yielded;
public static <T> TaskState<T> yielded(@Nullable T value) {
return new TaskState<>(value, true);
}
public static <T> TaskState<T> completed(@Nullable T value) {
return new TaskState<>(value, false);
}
}

View file

@ -5,13 +5,15 @@ import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.function.Supplier; import java.util.function.Supplier;
@NoArgsConstructor(access = AccessLevel.NONE) @NoArgsConstructor(access = AccessLevel.NONE)
public class Tasks { public class Tasks {
public static <T> Task<T> supplyAsync(Supplier<T> supplier) { public static <T> Task<T> supplyAsync(Supplier<T> supplier) {
return new TaskImpl<>(supplier); return new TaskImpl<>(() -> TaskState.completed(supplier.get()));
} }
public static Task<?> runAsync(Runnable task) { public static Task<?> runAsync(Runnable task) {
@ -24,7 +26,9 @@ public class Tasks {
public static <T> Task<T> supplySync(Supplier<T> supplier) { public static <T> Task<T> supplySync(Supplier<T> supplier) {
return new TaskImpl<>(() -> { return new TaskImpl<>(() -> {
try { try {
return Bukkit.getScheduler().callSyncMethod(ScrowAPI.plugin, supplier::get).get(); return TaskState.completed(Bukkit.getScheduler()
.callSyncMethod(ScrowAPI.plugin, supplier::get)
.get());
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
throw new RuntimeException(e); throw new RuntimeException(e);
@ -40,4 +44,11 @@ public class Tasks {
return null; return null;
}); });
} }
public static void awaitAll(Task<?>... tasks) {
var cfs = Arrays.stream(tasks)
.map(Task::toFuture)
.toArray(CompletableFuture[]::new);
CompletableFuture.allOf(cfs).join();
}
} }

View file

@ -8,18 +8,15 @@ import de.kentoj.kencommandapi.api.node.CommandNode;
import de.kentoj.kencommandapi.api.node.RootCommandNode; import de.kentoj.kencommandapi.api.node.RootCommandNode;
import de.kentoj.kencommandapi.api.platform.MessageStyle; import de.kentoj.kencommandapi.api.platform.MessageStyle;
import de.kentoj.scrow.bukkit.ScrowAPI; import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.ScrowAPISurface;
import de.kentoj.scrow.bukkit.scheduler.Tasks; import de.kentoj.scrow.bukkit.scheduler.Tasks;
import de.kentoj.scrowlib.convention.ScrowMessageStyle; import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@NoArgsConstructor(access = AccessLevel.NONE) @NoArgsConstructor(access = AccessLevel.NONE)
@ -50,7 +47,7 @@ public class CoinsCommand implements CommandExecutor<CommandSender> {
ScrowAPI.getEconomyService().getCoins(player.getUniqueId())) ScrowAPI.getEconomyService().getCoins(player.getUniqueId()))
.<Result<Object, String>>mapSync(amount -> { .<Result<Object, String>>mapSync(amount -> {
player.sendMessage(style.ok("You have " + amount + "$")); player.sendMessage(style.ok("You have " + amount + "$"));
return Results.success(Optional.empty()); return Results.success(new Object());
}).asFuture(); }).toFuture();
} }
} }

View file

@ -14,7 +14,6 @@ import lombok.Getter;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class CoinsGetLiteral implements CommandExecutor<CommandSender> { public class CoinsGetLiteral implements CommandExecutor<CommandSender> {
@ -43,8 +42,8 @@ public class CoinsGetLiteral implements CommandExecutor<CommandSender> {
ScrowAPI.getEconomyService().getCoins(player.getUniqueId())) ScrowAPI.getEconomyService().getCoins(player.getUniqueId()))
.<Result<Object, String>>mapSync(amount -> { .<Result<Object, String>>mapSync(amount -> {
ctx.getSender().sendMessage(style.ok(player.getName() + " has " + amount + "$")); ctx.getSender().sendMessage(style.ok(player.getName() + " has " + amount + "$"));
return Results.success(Optional.empty()); return Results.success(new Object());
}).asFuture(); }).toFuture();
} }
} }

View file

@ -15,7 +15,6 @@ import lombok.Getter;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class CoinsSetLiteral implements CommandExecutor<CommandSender> { public class CoinsSetLiteral implements CommandExecutor<CommandSender> {
@ -47,7 +46,7 @@ public class CoinsSetLiteral implements CommandExecutor<CommandSender> {
ScrowAPI.getEconomyService().setCoins(player.getUniqueId(), amount)) ScrowAPI.getEconomyService().setCoins(player.getUniqueId(), amount))
.<Result<Object, String>>supplySync(() -> { .<Result<Object, String>>supplySync(() -> {
ctx.getSender().sendMessage(style.ok(player.getName() + " now has " + amount + "$")); ctx.getSender().sendMessage(style.ok(player.getName() + " now has " + amount + "$"));
return Results.success(Optional.empty()); return Results.success(new Object());
}).asFuture(); }).toFuture();
} }
} }

View file

@ -1,106 +1,122 @@
package de.kentoj.scrow.bukkit.friends.command; package de.kentoj.scrow.bukkit.friends.command;
import de.kentoj.kencommandapi.api.node.CommandNode; import com.leakyabstractions.result.api.Result;
import com.leakyabstractions.result.core.Results;
import de.kentoj.kencommandapi.api.argument.CommandArgument; import de.kentoj.kencommandapi.api.argument.CommandArgument;
import de.kentoj.kencommandapi.api.invocation.CommandContext; import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.invocation.CommandExecutor; import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
import com.leakyabstractions.result.api.Result; import de.kentoj.kencommandapi.api.node.CommandNode;
import com.leakyabstractions.result.api.Results;
import de.kentoj.kencommandapi.type.OfflinePlayerArgumentType; import de.kentoj.kencommandapi.type.OfflinePlayerArgumentType;
import de.kentoj.scrow.bukkit.ScrowAPI; import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.friends.friendship.FriendshipImpl; import de.kentoj.scrow.bukkit.friends.friendship.FriendshipImpl;
import de.kentoj.scrow.bukkit.friends.request.FriendRequestImpl; import de.kentoj.scrow.bukkit.friends.request.FriendRequestImpl;
import de.kentoj.scrow.bukkit.scheduler.Task;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono;
import java.time.Instant; import java.time.Instant;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@RequiredArgsConstructor @RequiredArgsConstructor
public class FriendAddLiteral implements CommandExecutor<CommandSender> { public class FriendAddLiteral implements CommandExecutor<CommandSender> {
@Getter @Getter
private final CommandNode<CommandSender> rootNode; private final CommandNode<CommandSender> literal;
private final CommandArgument<CommandSender, OfflinePlayer> playerArg; private final CommandArgument<CommandSender, OfflinePlayer> playerArg;
private final ScrowMessageStyle style;
public FriendAddLiteral() { public FriendAddLiteral(ScrowMessageStyle style) {
this.style = style;
playerArg = CommandArgument.arg("player", OfflinePlayerArgumentType.getInstance()); playerArg = CommandArgument.arg("player", OfflinePlayerArgumentType.getInstance());
rootNode = CommandNode.node("add"); literal = CommandNode.node("add");
rootNode.addArgument(playerArg); literal.addArgument(playerArg);
rootNode.setExecutor(this); literal.setExecutor(this);
} }
@Override @Override
public CompletableFuture<Result<Object, String>> execute(CommandContext<CommandSender> ctx) { public CompletableFuture<Result<Object, String>> execute(CommandContext<CommandSender> ctx) {
var self = (Player) ctx.getSender(); var self = (Player) ctx.getSender();
var other = ctx.getArg(playerArg); var other = ctx.getArg(playerArg);
return findAction(self, other) return Tasks.supplyAsync(() -> findAction(self, other)
.flatMap(action -> executeAction(self, other, action)) .mapSuccess(action -> {
.toFuture(); if (action == AddAction.SEND_REQUEST) sendRequest(self, other);
else if (action == AddAction.ACCEPT_REQUEST) acceptRequest(self, other);
return new Object();
})
).toFuture();
} }
private Mono<@NotNull Result> executeAction(Player self, OfflinePlayer other, AddAction action) { private void sendRequest(Player self, OfflinePlayer other) {
return switch (action) { Tasks.runAsync(() -> ScrowAPI.getFriendRequestService()
case ERR_CAN_NOT_ADD_SELF -> Mono.just(Result.error("You can not add yourself")); .saveFriendRequest(new FriendRequestImpl(self.getUniqueId(), other.getUniqueId())))
case ERR_ALREADY_FRIENDS -> Mono.just(Result.error("You are already friends with " + other.getName())); .runSync(() -> {
case ERR_ALREADY_REQUESTED -> self.sendMessage(style.ok("Successfully sent " + other.getName() + " a friend request."));
Mono.just(Result.error("You already requested " + other.getName() + " to be friends with you"));
case SEND_REQUEST -> sendRequest(self, other);
case ACCEPT_REQUEST -> acceptRequest(self, other);
};
}
private Mono<@NotNull Result> sendRequest(Player self, OfflinePlayer other) {
return ScrowAPI.getFriendRequestService().saveFriendRequest(new FriendRequestImpl(self.getUniqueId(), other.getUniqueId(), Instant.now()))
.map(success -> {
if (!success) return Result.error("You already sent " + other.getName() + " a friend request");
self.sendMessage("Successfully sent " + other.getName() + " a friend request.");
var otherPlayer = other.getPlayer(); var otherPlayer = other.getPlayer();
if (otherPlayer != null) if (otherPlayer != null)
otherPlayer.sendMessage(" wants to be friends with you. Use '/f add " + self.getName() + "' to accept."); otherPlayer.sendMessage(style.ok(" wants to be friends with you. Use '/f add " + self.getName() + "' to accept."));
return Result.success();
}); });
} }
private Mono<@NotNull Result> acceptRequest(Player self, OfflinePlayer other) { private void acceptRequest(Player self, OfflinePlayer other) {
return Mono.when( Tasks.runAsync(() -> Tasks.awaitAll(
ScrowAPI.getFriendRequestService().deleteFriendRequest(self.getUniqueId(), other.getUniqueId()), Tasks.runAsync(() -> ScrowAPI.getFriendRequestService()
ScrowAPI.getFriendRequestService().deleteFriendRequest(other.getUniqueId(), self.getUniqueId()), .deleteFriendRequest(self.getUniqueId(), other.getUniqueId())),
ScrowAPI.getFriendshipService().saveFriendship(new FriendshipImpl(self.getUniqueId(), other.getUniqueId(), Instant.now())) Tasks.runAsync(() -> ScrowAPI.getFriendRequestService()
) .deleteFriendRequest(other.getUniqueId(), self.getUniqueId())),
.doOnNext(__ -> { Tasks.runAsync(() -> ScrowAPI.getFriendshipService()
self.sendMessage("You are now friends with " + other.getName()); .saveFriendship(new FriendshipImpl(self.getUniqueId(), other.getUniqueId(), Instant.now()))
)))
.runSync(() -> {
self.sendMessage(style.ok("You are now friends with " + other.getName()));
if (other.getPlayer() != null) if (other.getPlayer() != null)
other.getPlayer().sendMessage("You are now friends with " + self.getName()); other.getPlayer().sendMessage(style.ok("You are now friends with " + self.getName()));
}) });
.then(Mono.just(Result.success()));
} }
private Mono<@NotNull AddAction> findAction(Player self, OfflinePlayer other) { private Result<AddAction, String> findAction(Player self, OfflinePlayer other) {
if (self.getUniqueId() == other.getUniqueId()) return Mono.just(AddAction.ERR_CAN_NOT_ADD_SELF); if (self.getUniqueId() == other.getUniqueId())
return ScrowAPI.getFriendshipService().getFriendship(self.getUniqueId(), other.getUniqueId()) return Results.failure("You cannot add yourself.");
.map(f -> AddAction.ERR_ALREADY_FRIENDS)
.switchIfEmpty( var isAlreadyFriendTask = checkAlreadyFriends(self, other);
ScrowAPI.getFriendRequestService().getFriendRequest(self.getUniqueId(), other.getUniqueId()) var isAlreadySent = checkAlreadySent(self.getUniqueId(), other.getUniqueId());
.map(r -> AddAction.ERR_ALREADY_REQUESTED) var isShouldAccept = checkShouldAccept(self, other);
.switchIfEmpty( Tasks.awaitAll(isAlreadyFriendTask, isAlreadyFriendTask, isShouldAccept);
ScrowAPI.getFriendRequestService().getFriendRequest(other.getUniqueId(), self.getUniqueId())
.map(r -> AddAction.ACCEPT_REQUEST) if (isAlreadyFriendTask.await())
.switchIfEmpty(Mono.just(AddAction.SEND_REQUEST)) return Results.failure("You are already friends with " + other.getName() + ".");
) if (isAlreadySent.await())
); return Results.failure("You've already sent " + other + " a friend request.");
if (isShouldAccept.await())
return Results.success(AddAction.ACCEPT_REQUEST);
return Results.success(AddAction.SEND_REQUEST);
}
private static Task<Boolean> checkShouldAccept(Player self, OfflinePlayer other) {
return Tasks.supplyAsync(() ->
ScrowAPI.getFriendRequestService().getFriendRequest(other.getUniqueId(), self.getUniqueId()))
.mapSync(Objects::nonNull);
}
private static Task<Boolean> checkAlreadyFriends(Player self, OfflinePlayer other) {
return Tasks.supplyAsync(() ->
ScrowAPI.getFriendshipService().getFriendship(self.getUniqueId(), other.getUniqueId()))
.mapSync(Objects::nonNull);
}
private static Task<Boolean> checkAlreadySent(UUID self, UUID other) {
return Tasks.supplyAsync(() ->
ScrowAPI.getFriendRequestService().getFriendRequest(self, other))
.mapSync(Objects::nonNull);
} }
private enum AddAction { private enum AddAction {
ERR_ALREADY_FRIENDS,
ERR_ALREADY_REQUESTED,
ERR_CAN_NOT_ADD_SELF,
SEND_REQUEST, SEND_REQUEST,
ACCEPT_REQUEST ACCEPT_REQUEST
} }

View file

@ -12,10 +12,10 @@ import org.bukkit.command.CommandSender;
public class FriendCommand { public class FriendCommand {
public static RootCommandNode<CommandSender> create() { public static RootCommandNode<CommandSender> create() {
var style = new ScrowMessageStyle("Friends", NamedTextColor.GREEN); var style = new ScrowMessageStyle("Friends", NamedTextColor.GREEN);
var rootNode = CommandNode.rootNode(style, "f", "friend"); RootCommandNode<CommandSender> rootNode = CommandNode.rootNode(style, "f", "friend");
rootNode.addLiteral(new FriendListLiteral(style).getRootNode()); rootNode.addLiteral(new FriendListLiteral(style).getLiteral());
rootNode.addLiteral(new FriendAddLiteral(style).getRootNode()); rootNode.addLiteral(new FriendAddLiteral(style).getLiteral());
rootNode.addLiteral(new FriendRemoveLiteral(style).getRootNode()); rootNode.addLiteral(new FriendRemoveLiteral(style).getRootNode());
rootNode.addLiteral(new FriendRequestsLiteral(style).getRootNode()); rootNode.addLiteral(new FriendRequestsLiteral(style).getLiteral());
} }
} }

View file

@ -5,58 +5,51 @@ import com.leakyabstractions.result.core.Results;
import de.kentoj.kencommandapi.api.invocation.CommandContext; import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.invocation.CommandExecutor; import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
import de.kentoj.kencommandapi.api.node.CommandNode; import de.kentoj.kencommandapi.api.node.CommandNode;
import de.kentoj.kencommandapi.api.platform.MessageStyle;
import de.kentoj.scrow.bukkit.ScrowAPI; import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import lombok.Getter; import lombok.Getter;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import static java.util.Objects.*;
import static net.kyori.adventure.text.Component.text;
public class FriendListLiteral implements CommandExecutor<CommandSender> { public class FriendListLiteral implements CommandExecutor<CommandSender> {
@Getter @Getter
private final CommandNode<CommandSender> rootNode; private final CommandNode<CommandSender> literal;
private final MessageStyle style; private final ScrowMessageStyle style;
public FriendListLiteral(MessageStyle style) { public FriendListLiteral(ScrowMessageStyle style) {
this.style = style; this.style = style;
this.rootNode = CommandNode.node("list"); this.literal = CommandNode.node("list");
rootNode.setExecutor(this); literal.setExecutor(this);
} }
@Override @Override
public CompletableFuture<Result<Object, String>> execute(CommandContext<CommandSender> ctx) { public CompletableFuture<Result<Object, String>> execute(CommandContext<CommandSender> ctx) {
var sender = (Player) ctx.getSender(); var sender = (Player) ctx.getSender();
var ownUid = sender.getUniqueId(); return Tasks.supplyAsync(() ->
return CompletableFuture.supplyAsync(() -> ScrowAPI.getFriendshipService().getFriendships(sender.getUniqueId()))
ScrowAPI.getFriendshipService().getFriendships(ownUid)) .<Result<Object, String>>mapSync(friendships -> {
.thenApply(friendships -> ScrowAPI.getScheduler().sync(() -> { var friends = friendships.stream()
var list = friendships.stream() .map(friendship -> Bukkit.getOfflinePlayer(friendship.getUuids().getOther(sender.getUniqueId())))
.map(friendship -> Bukkit.getOfflinePlayer(friendship.getUuids().getOther(ownUid)))
.sorted(this::compareByOnlineStatus) .sorted(this::compareByOnlineStatus)
.toList(); .toList();
if (list.isEmpty()) return Results.failure("You have no friends. Use /friend add <player>"); if (friends.isEmpty()) return Results.failure("You have no friends. Use /friend add <player>");
var message = "§7You have §3" + list.size() + "§7" + ("§" + sender.sendMessage(formatList(friends));
.append(Component.text(list.size() == 1 ? " friend:" : " friends:")); return Results.success(new Object());
for (var friend : list) { }).toFuture();
message = message.appendNewline();
var status = Component.text("(").append(
friend.isOnline()
? Component.text("online").color(NamedTextColor.GRAY)
: Component.text("offline").color(NamedTextColor.RED))
.append(Component.text(")"));
message = message.append(Component.text("").color(NamedTextColor.AQUA));
}
sender.sendMessage(msg);
return Result.success();
});
} }
private int compareByOnlineStatus(OfflinePlayer p1, OfflinePlayer p2) { private int compareByOnlineStatus(OfflinePlayer p1, OfflinePlayer p2) {
@ -64,4 +57,20 @@ public class FriendListLiteral implements CommandExecutor<CommandSender> {
if (!p1.isOnline() && p2.isOnline()) return -1; if (!p1.isOnline() && p2.isOnline()) return -1;
return 0; return 0;
} }
private Component formatList(List<OfflinePlayer> friends) {
var message = style.ok(MiniMessage.miniMessage().deserialize("Your friends:"));
for (var friend : friends) {
var status = text("(").append(friend.isOnline()
? text("online").color(NamedTextColor.GRAY)
: text("offline").color(NamedTextColor.RED))
.append(text(")"));
message = message
.appendNewline()
.append(text("").color(NamedTextColor.AQUA))
.append(text(requireNonNull(friend.getName())))
.append(status);
}
return message;
}
} }

View file

@ -9,22 +9,22 @@ import de.kentoj.kencommandapi.api.node.CommandNode;
import de.kentoj.kencommandapi.type.OfflinePlayerArgumentType; import de.kentoj.kencommandapi.type.OfflinePlayerArgumentType;
import de.kentoj.scrow.bukkit.ScrowAPI; import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.scheduler.Tasks; import de.kentoj.scrow.bukkit.scheduler.Tasks;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import lombok.Getter; import lombok.Getter;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class FriendRemoveLiteral implements CommandExecutor<CommandSender> { public class FriendRemoveLiteral implements CommandExecutor<CommandSender> {
@Getter @Getter
private final CommandNode<CommandSender> rootNode; private final CommandNode<CommandSender> rootNode;
private final CommandArgument<CommandSender, OfflinePlayer> playerArg; private final CommandArgument<CommandSender, OfflinePlayer> playerArg;
private final ScrowMessageStyle style;
private final Scheduler scheduler = ScrowAPI.getScheduler(); public FriendRemoveLiteral(ScrowMessageStyle style) {
this.style = style;
public FriendRemoveLiteral() {
this.playerArg = CommandArgument.arg("player", OfflinePlayerArgumentType.getInstance()); this.playerArg = CommandArgument.arg("player", OfflinePlayerArgumentType.getInstance());
this.rootNode = CommandNode.node("remove"); this.rootNode = CommandNode.node("remove");
this.rootNode.addArgument(playerArg); this.rootNode.addArgument(playerArg);
@ -40,8 +40,8 @@ public class FriendRemoveLiteral implements CommandExecutor<CommandSender> {
.<Result<Object, String>>mapSync(deleted -> { .<Result<Object, String>>mapSync(deleted -> {
if (!deleted) if (!deleted)
return Results.failure("You are not friends with " + friend.getName()); return Results.failure("You are not friends with " + friend.getName());
ctx.getSender().sendMessage("You have ended the friendship with " + friend.getName()); ctx.getSender().sendMessage(style.ok("You have ended the friendship with " + friend.getName()));
return Results.success(Optional.empty()); return Results.success(new Object());
}).asFuture(); }).toFuture();
} }
} }

View file

@ -1,45 +1,65 @@
package de.kentoj.scrow.bukkit.friends.command; package de.kentoj.scrow.bukkit.friends.command;
import de.kentoj.kencommandapi.api.node.CommandNode; import com.leakyabstractions.result.api.Result;
import com.leakyabstractions.result.core.Results;
import de.kentoj.kencommandapi.api.invocation.CommandContext; import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.invocation.CommandExecutor; import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
import com.leakyabstractions.result.api.Result; import de.kentoj.kencommandapi.api.node.CommandNode;
import com.leakyabstractions.result.api.Results;
import de.kentoj.scrow.bukkit.ScrowAPI; import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.friends.FriendRequest; import de.kentoj.scrow.bukkit.friends.FriendRequest;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import lombok.Getter; import lombok.Getter;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import static net.kyori.adventure.text.Component.text;
public class FriendRequestsLiteral implements CommandExecutor<CommandSender> { public class FriendRequestsLiteral implements CommandExecutor<CommandSender> {
@Getter @Getter
private final CommandNode<CommandSender> rootNode; private final CommandNode<CommandSender> literal;
private final ScrowMessageStyle style;
public FriendRequestsLiteral() { public FriendRequestsLiteral(ScrowMessageStyle style) {
this.rootNode = CommandNode.node("requests", "list-requests"); this.style = style;
rootNode.setExecutor(this); literal = CommandNode.node("requests", "list-requests");
literal.setExecutor(this);
} }
@Override @Override
public CompletableFuture<Result<Object, String>> execute(CommandContext<CommandSender> ctx) { public CompletableFuture<Result<Object, String>> execute(CommandContext<CommandSender> ctx) {
var sender = (Player) ctx.getSender(); var sender = (Player) ctx.getSender();
return ScrowAPI.getFriendRequestService().getFriendRequestsTo(sender.getUniqueId()) return Tasks.supplyAsync(() ->
.collectList() ScrowAPI.getFriendRequestService().getFriendRequestsTo(sender.getUniqueId()))
.map(list -> { .<Result<Object, String>>mapAsync(list -> {
if (list.isEmpty()) return Result.error("You have no friend requests"); if (list.isEmpty()) return Results.failure("You have no friend requests");
var requesters = list.stream().sorted(this::compareByAge).map(fr -> Bukkit.getOfflinePlayer(fr.getFrom()).getName());
var msg = "§3§lFriends§r§7 ☆ You have §3" + list.size() + "§7 open friend request"; sender.sendMessage(formatList(requesters.toList()));
if (list.size() > 1) msg += "s"; return Results.success(new Object());
msg += ":§r\n";
for (FriendRequest friendRequest : list) {
msg += "§c≫ §7" + friendRequest.getFrom() + "\n";
}
sender.sendMessage(msg);
return Result.success();
}).toFuture(); }).toFuture();
} }
private int compareByAge(FriendRequest a, FriendRequest b) {
return a.getCreatedAt().isAfter(b.getCreatedAt()) ? 1 : -1;
}
private Component formatList(List<String> requesters) {
var message = style.ok(MiniMessage.miniMessage().deserialize("Open friend requests:"));
for (String requester : requesters) {
message = message
.appendNewline()
.append(text("").color(NamedTextColor.AQUA))
.append(Component.text(requester));
}
return message;
}
} }

View file

@ -1,7 +1,5 @@
package de.kentoj.scrow.bukkit.friends.friendship; package de.kentoj.scrow.bukkit.friends.friendship;
import com.leakyabstractions.result.api.Result;
import com.leakyabstractions.result.core.Results;
import de.kentoj.scrow.bukkit.friends.Friendship; import de.kentoj.scrow.bukkit.friends.Friendship;
import de.kentoj.scrow.bukkit.friends.FriendshipService; import de.kentoj.scrow.bukkit.friends.FriendshipService;
import de.kentoj.scrow.bukkit.friends.OrderedUUIDPair; import de.kentoj.scrow.bukkit.friends.OrderedUUIDPair;
@ -16,27 +14,27 @@ public class InMemoryFriendshipService implements FriendshipService {
private final Map<OrderedUUIDPair, Friendship> friendships = new HashMap<>(); private final Map<OrderedUUIDPair, Friendship> friendships = new HashMap<>();
@Override @Override
public Result<Friendship, String> getFriendship(UUID uuid1, UUID uuid2) { public Friendship getFriendship(UUID uuid1, UUID uuid2) {
return Results.success(friendships.get(new OrderedUUIDPair(uuid1, uuid2))); return friendships.get(new OrderedUUIDPair(uuid1, uuid2));
} }
@Override @Override
public Result<List<Friendship>, String> getFriendships(UUID playerId) { public List<Friendship> getFriendships(UUID playerId) {
return Results.success(friendships.entrySet().stream() return friendships.entrySet().stream()
.filter(ent -> .filter(ent ->
ent.getKey().getFirst().equals(playerId) || ent.getKey().getSecond().equals(playerId) ent.getKey().getFirst().equals(playerId) || ent.getKey().getSecond().equals(playerId)
) )
.map(Map.Entry::getValue) .map(Map.Entry::getValue)
.toList()); .toList();
} }
@Override @Override
public Result<Boolean, String> saveFriendship(Friendship friendship) { public boolean saveFriendship(Friendship friendship) {
return Results.success(friendships.putIfAbsent(friendship.getUuids(), friendship) == null); return friendships.putIfAbsent(friendship.getUuids(), friendship) == null;
} }
@Override @Override
public Result<Boolean, String> deleteFriendship(UUID uuid1, UUID uuid2) { public boolean deleteFriendship(UUID uuid1, UUID uuid2) {
return Results.success(friendships.remove(new OrderedUUIDPair(uuid1, uuid2)) != null); return friendships.remove(new OrderedUUIDPair(uuid1, uuid2)) != null;
} }
} }

View file

@ -1,23 +1,31 @@
package de.kentoj.scrow.bukkit.friends.friendship; package de.kentoj.scrow.bukkit.friends.friendship;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.friends.FriendRequest;
import de.kentoj.scrow.bukkit.friends.Friendship; import de.kentoj.scrow.bukkit.friends.Friendship;
import de.kentoj.scrow.bukkit.friends.FriendshipService; import de.kentoj.scrow.bukkit.friends.FriendshipService;
import de.kentoj.scrow.bukkit.friends.OrderedUUIDPair; import de.kentoj.scrow.bukkit.friends.OrderedUUIDPair;
import de.kentoj.scrowlib.connection.DatabaseConnectionFactory; import de.kentoj.scrow.bukkit.friends.request.FriendRequestImpl;
import org.jetbrains.annotations.NotNull; import org.jdbi.v3.core.Jdbi;
import reactor.core.publisher.Flux; import org.jdbi.v3.core.statement.StatementContext;
import reactor.core.publisher.Mono; import org.jetbrains.annotations.Nullable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.Instant; import java.time.Instant;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import static com.google.common.base.Preconditions.checkNotNull;
public class PostgresFriendshipService implements FriendshipService { public class PostgresFriendshipService implements FriendshipService {
private final DatabaseConnectionFactory dbConFactory; private final Jdbi jdbi;
public PostgresFriendshipService(DatabaseConnectionFactory dbConFactory) { public PostgresFriendshipService() {
this.dbConFactory = dbConFactory; checkNotNull(ScrowAPI.getJdbi());
this.dbConFactory.create().sql(""" jdbi = ScrowAPI.getJdbi();
jdbi.useHandle(h -> h.execute("""
CREATE TABLE IF NOT EXISTS friendships ( CREATE TABLE IF NOT EXISTS friendships (
first_uuid UUID NOT NULL, first_uuid UUID NOT NULL,
second_uuid UUID NOT NULL, second_uuid UUID NOT NULL,
@ -26,47 +34,39 @@ public class PostgresFriendshipService implements FriendshipService {
CONSTRAINT friendship_no_self_friendship CONSTRAINT friendship_no_self_friendship
CHECK (first_uuid <> second_uuid) CHECK (first_uuid <> second_uuid)
) )
""").then().block(); """));
} }
@Override @Override
public Result<Friendship, String> getFriendship(UUID uuid1, UUID uuid2) { public @Nullable Friendship getFriendship(UUID uuid1, UUID uuid2) {
var uuids = new OrderedUUIDPair(uuid1, uuid2); var uuids = new OrderedUUIDPair(uuid1, uuid2);
return dbConFactory.create().sql(""" return jdbi.withHandle(h -> h.createQuery("""
SELECT first_uuid, second_uuid, created_at SELECT first_uuid, second_uuid, created_at
FROM friendships FROM friendships
WHERE first_uuid = :first AND second_uuid = :second WHERE first_uuid = :first AND second_uuid = :second
""") """)
.bind("first", uuids.getFirst()) .bind("first", uuids.getFirst())
.bind("second", uuids.getSecond()) .bind("second", uuids.getSecond())
.map(row -> (Friendship) new FriendshipImpl( .map(this::parseFriendship)
row.get("first_uuid", UUID.class), .findFirst().orElse(null));
row.get("second_uuid", UUID.class),
row.get("created_at", Instant.class)
))
.one();
} }
@Override @Override
public Result<List<Friendship>, String> getFriendships(UUID playerId) { public List<Friendship> getFriendships(UUID playerId) {
return dbConFactory.create().sql(""" return jdbi.withHandle(h -> h.createQuery("""
SELECT first_uuid, second_uuid, created_at SELECT first_uuid, second_uuid, created_at
FROM friendships FROM friendships
WHERE first_uuid = :playerId OR second_uuid = :playerId WHERE first_uuid = :playerId OR second_uuid = :playerId
""") """)
.bind("playerId", playerId) .bind("playerId", playerId)
.map((row, meta) -> (Friendship) new FriendshipImpl( .map(this::parseFriendship)
row.get("first_uuid", UUID.class), .list());
row.get("second_uuid", UUID.class),
row.get("created_at", Instant.class)
))
.all();
} }
@Override @Override
public Result<Boolean, String> saveFriendship(Friendship friendship) { public boolean saveFriendship(Friendship friendship) {
return dbConFactory.create().sql(""" return jdbi.withHandle(h -> h.createUpdate("""
INSERT INTO friendships (first_uuid, second_uuid, created_at) INSERT INTO friendships (first_uuid, second_uuid, created_at)
VALUES (:first, :second, :createdAt) VALUES (:first, :second, :createdAt)
ON CONFLICT (first_uuid, second_uuid) DO NOTHING ON CONFLICT (first_uuid, second_uuid) DO NOTHING
@ -74,23 +74,26 @@ public class PostgresFriendshipService implements FriendshipService {
.bind("first", friendship.getUuids().getFirst()) .bind("first", friendship.getUuids().getFirst())
.bind("second", friendship.getUuids().getSecond()) .bind("second", friendship.getUuids().getSecond())
.bind("createdAt", friendship.getCreatedAt()) .bind("createdAt", friendship.getCreatedAt())
.fetch() .execute() > 0);
.rowsUpdated()
.map(rows -> rows > 0);
} }
@Override @Override
public Result<Boolean, String> deleteFriendship(UUID uuid1, UUID uuid2) { public boolean deleteFriendship(UUID uuid1, UUID uuid2) {
var uuids = new OrderedUUIDPair(uuid1, uuid2); var uuids = new OrderedUUIDPair(uuid1, uuid2);
return jdbi.withHandle(h -> h.createUpdate("""
return dbConFactory.create().sql("""
DELETE FROM friendships DELETE FROM friendships
WHERE first_uuid = :first AND second_uuid = :second WHERE first_uuid = :first AND second_uuid = :second
""") """)
.bind("first", uuids.getFirst()) .bind("first", uuids.getFirst())
.bind("second", uuids.getSecond()) .bind("second", uuids.getSecond())
.fetch() .execute() > 0);
.rowsUpdated() }
.map(rows -> rows > 0);
private Friendship parseFriendship(ResultSet rs, StatementContext __) throws SQLException {
return new FriendshipImpl(
rs.getObject("first_uuid", UUID.class),
rs.getObject("second_uuid", UUID.class),
rs.getObject("created_at", Instant.class)
);
} }
} }

View file

@ -1,14 +1,20 @@
package de.kentoj.scrow.bukkit.friends.request; package de.kentoj.scrow.bukkit.friends.request;
import de.kentoj.scrow.bukkit.friends.FriendRequest; import de.kentoj.scrow.bukkit.friends.FriendRequest;
import lombok.AllArgsConstructor;
import lombok.Value; import lombok.Value;
import java.time.Instant; import java.time.Instant;
import java.util.UUID; import java.util.UUID;
@Value @Value
@AllArgsConstructor
public class FriendRequestImpl implements FriendRequest { public class FriendRequestImpl implements FriendRequest {
UUID from; UUID from;
UUID to; UUID to;
Instant createdAt; Instant createdAt;
public FriendRequestImpl(UUID from, UUID to) {
this(from, to, Instant.now());
}
} }

View file

@ -1,24 +1,30 @@
package de.kentoj.scrow.bukkit.friends.request; package de.kentoj.scrow.bukkit.friends.request;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.friends.FriendRequest; import de.kentoj.scrow.bukkit.friends.FriendRequest;
import de.kentoj.scrow.bukkit.friends.FriendRequestService; import de.kentoj.scrow.bukkit.friends.FriendRequestService;
import de.kentoj.scrowlib.connection.DatabaseConnectionFactory; import org.jdbi.v3.core.Jdbi;
import io.r2dbc.spi.Readable; import org.jdbi.v3.core.statement.StatementContext;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable;
import org.springframework.r2dbc.core.DatabaseClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import javax.swing.tree.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.Instant; import java.time.Instant;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import static com.google.common.base.Preconditions.checkNotNull;
public class PostgresFriendRequestService implements FriendRequestService { public class PostgresFriendRequestService implements FriendRequestService {
private final DatabaseConnectionFactory conFactory; private final Jdbi jdbi;
public PostgresFriendRequestService(DatabaseConnectionFactory conFactory) { public PostgresFriendRequestService() {
this.conFactory = conFactory; checkNotNull(ScrowAPI.getJdbi());
conFactory.create().sql(""" jdbi = ScrowAPI.getJdbi();
jdbi.useHandle(h -> h.execute("""
CREATE TABLE IF NOT EXISTS friend-requests ( CREATE TABLE IF NOT EXISTS friend-requests (
from_uuid UUID NOT NULL, from_uuid UUID NOT NULL,
to_uuid UUID NOT NULL, to_uuid UUID NOT NULL,
@ -27,12 +33,12 @@ public class PostgresFriendRequestService implements FriendRequestService {
CONSTRAINT friendship_no_self_friendship CONSTRAINT friendship_no_self_friendship
CHECK (first_uuid <> second_uuid) CHECK (first_uuid <> second_uuid)
) )
""").then().block(); """));
} }
@Override @Override
public Result<FriendRequest, String> getFriendRequest(UUID from, UUID to) { public @Nullable FriendRequest getFriendRequest(UUID from, UUID to) {
return conFactory.create().sql(""" return jdbi.withHandle(h -> h.createQuery("""
SELECT * SELECT *
FROM friend-requests FROM friend-requests
WHERE from_uuid = :from AND to_uuid = :to WHERE from_uuid = :from AND to_uuid = :to
@ -40,65 +46,62 @@ public class PostgresFriendRequestService implements FriendRequestService {
.bind("from", from) .bind("from", from)
.bind("to", to) .bind("to", to)
.map(this::parseFriendRequest) .map(this::parseFriendRequest)
.one(); .findFirst()
.orElse(null));
} }
@Override @Override
public Result<Boolean, String> saveFriendRequest(FriendRequest friendRequest) { public boolean saveFriendRequest(FriendRequest friendRequest) {
return conFactory.create().sql(""" return jdbi.withHandle(h -> h.createUpdate("""
INSERT INTO friend-requests (from_uuid, to_uuid, created_at) INSERT INTO friend-requests (from_uuid, to_uuid, created_at)
VALUES (:from, :to, :created_at) VALUES (:from, :to, :created_at)
""") """)
.bind("from", friendRequest.getFrom()) .bind("from", friendRequest.getFrom())
.bind("to", friendRequest.getTo()) .bind("to", friendRequest.getTo())
.fetch() .execute() > 0);
.rowsUpdated()
.map(cnt -> cnt > 0);
} }
@Override @Override
public Result<List<FriendRequest>, String> getFriendRequestsTo(UUID playerId) { public List<FriendRequest> getFriendRequestsTo(UUID playerId) {
return conFactory.create().sql(""" return jdbi.withHandle(h -> h.createQuery("""
SELECT * SELECT *
FROM friend-requests FROM friend-requests
WHERE to_uuid = :to WHERE to_uuid = :to
""") """)
.bind("to", playerId) .bind("to", playerId)
.map(this::parseFriendRequest) .map(this::parseFriendRequest)
.all(); .collectIntoList());
} }
@Override @Override
public Result<List<FriendRequest>, String> getFriendRequestsFrom(UUID playerId) { public List<FriendRequest> getFriendRequestsFrom(UUID playerId) {
return conFactory.create().sql(""" return jdbi.withHandle(h -> h.createQuery("""
SELECT * SELECT *
FROM friend-requests FROM friend-requests
WHERE from_uuid = :from WHERE from_uuid = :from
""") """)
.bind("from", playerId) .bind("from", playerId)
.map(this::parseFriendRequest) .map(this::parseFriendRequest)
.all(); .collectIntoList());
} }
@Override @Override
public Result<Boolean, String> deleteFriendRequest(UUID from, UUID to) { public boolean deleteFriendRequest(UUID from, UUID to) {
return conFactory.create().sql(""" return jdbi.withHandle(h -> h.createUpdate("""
DELETE DELETE
FROM friend-requests FROM friend-requests
WHERE from_uuid = :from AND to_uuid = :to WHERE from_uuid = :from AND to_uuid = :to
""") """)
.bind("from", from) .bind("from", from)
.bind("to", to) .bind("to", to)
.fetch() .execute() > 0);
.rowsUpdated()
.map(deleted -> deleted > 0);
} }
private FriendRequest parseFriendRequest(Readable row) { private FriendRequest parseFriendRequest(ResultSet rs, StatementContext __) throws SQLException {
return new FriendRequestImpl( return new FriendRequestImpl(
row.get("from_uuid", UUID.class), rs.getObject("from_uuid", UUID.class),
row.get("to_uuid", UUID.class), rs.getObject("to_uuid", UUID.class),
row.get("created_at", Instant.class) rs.getObject("created_at", Instant.class)
); );
} }
} }

View file

@ -24,6 +24,6 @@ public class LobbyCommand implements CommandExecutor<CommandSender> {
@Override @Override
public CompletableFuture<Result<Object, String>> execute(CommandContext<CommandSender> ctx) { public CompletableFuture<Result<Object, String>> execute(CommandContext<CommandSender> ctx) {
Bukkit.dispatchCommand(ctx.getSender(), "play lobby"); Bukkit.dispatchCommand(ctx.getSender(), "play lobby");
return CompletableFuture.completedFuture(Results.success(null)); return CompletableFuture.completedFuture(Results.success(new Object()));
} }
} }

View file

@ -8,6 +8,7 @@ import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.invocation.CommandExecutor; import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
import de.kentoj.kencommandapi.api.node.CommandNode; import de.kentoj.kencommandapi.api.node.CommandNode;
import de.kentoj.scrow.bukkit.ScrowAPI; import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import lombok.Getter; import lombok.Getter;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -31,8 +32,8 @@ public class PlayCommand implements CommandExecutor<CommandSender> {
public CompletableFuture<Result<Object, String>> execute(CommandContext<CommandSender> ctx) { public CompletableFuture<Result<Object, String>> execute(CommandContext<CommandSender> ctx) {
var gamemode = ctx.getArg(gamemodeArg); var gamemode = ctx.getArg(gamemodeArg);
var player = (Player) ctx.getSender(); var player = (Player) ctx.getSender();
return CompletableFuture.supplyAsync(() -> ScrowAPI.getInstanceManager().getInstances() return Tasks.supplyAsync(() -> ScrowAPI.getInstanceManager().getInstances()
.flatMapSuccess(instances -> { .mapSuccess(instances -> {
var instance = instances.stream() var instance = instances.stream()
.filter(inst -> inst.getTemplate().equals(gamemode)) .filter(inst -> inst.getTemplate().equals(gamemode))
.findFirst() .findFirst()

View file

@ -1,23 +1,23 @@
package de.kentoj.scrowlib.servermanager; package de.kentoj.scrowlib.servermanager;
import com.leakyabstractions.result.api.Result;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
import java.util.List; import java.util.List;
public interface InstanceManager { public interface InstanceManager {
/** ServerInstance deployInstance(String template);
* @return Mono with handle of deployed server
*/
Result<ServerInstance, String> deployInstance(String template);
Result<Object, String> destroyInstance(String handle); /**
* @return if the instance was found
*/
boolean destroyInstance(String handle);
/** /**
* @return Flux with handles of running servers * @return Flux with handles of running servers
*/ */
Result<List<ServerInstance>, String> getInstances(); List<ServerInstance> getInstances();
Result<@Nullable ServerInstance, String> getInstance(String handle); @Nullable
ServerInstance getInstance(String handle);
} }