├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── buildSrc ├── build.gradle.kts └── src │ └── main │ └── kotlin │ ├── buildlogic.java-conventions.gradle.kts │ └── extensions.kt ├── core ├── build.gradle.kts └── src │ └── main │ ├── java │ └── dev │ │ └── pgm │ │ └── community │ │ ├── Community.java │ │ ├── CommunityCommand.java │ │ ├── CommunityConfig.java │ │ ├── CommunityPermissions.java │ │ ├── assistance │ │ ├── AssistanceRequest.java │ │ ├── PlayerHelpRequest.java │ │ ├── Report.java │ │ ├── ReportConfig.java │ │ ├── commands │ │ │ ├── PlayerHelpCommand.java │ │ │ └── ReportCommands.java │ │ ├── feature │ │ │ ├── AssistanceFeature.java │ │ │ ├── AssistanceFeatureBase.java │ │ │ └── types │ │ │ │ ├── NoDBAssistanceFeature.java │ │ │ │ └── SQLAssistanceFeature.java │ │ ├── menu │ │ │ ├── ReportCategory.java │ │ │ ├── ReportCategoryMenu.java │ │ │ ├── ReportReason.java │ │ │ └── ReportReasonsMenu.java │ │ └── services │ │ │ ├── AssistanceQuery.java │ │ │ └── SQLAssistanceService.java │ │ ├── broadcast │ │ ├── BroadcastCommand.java │ │ ├── BroadcastConfig.java │ │ └── BroadcastFeature.java │ │ ├── chat │ │ ├── management │ │ │ ├── ChatManagementCommand.java │ │ │ ├── ChatManagementConfig.java │ │ │ └── ChatManagementFeature.java │ │ └── network │ │ │ ├── NetworkChatConfig.java │ │ │ ├── NetworkChatFeature.java │ │ │ └── NetworkChatMessage.java │ │ ├── commands │ │ ├── CommunityPluginCommand.java │ │ ├── ContainerCommand.java │ │ ├── FlightCommand.java │ │ ├── GamemodeCommand.java │ │ ├── ServerInfoCommand.java │ │ ├── StaffCommand.java │ │ ├── SudoCommand.java │ │ ├── VanishedCommand.java │ │ ├── graph │ │ │ └── CommunityCommandGraph.java │ │ ├── injectors │ │ │ └── CommandAudienceProvider.java │ │ ├── player │ │ │ └── TargetPlayer.java │ │ └── providers │ │ │ ├── GameModeParser.java │ │ │ └── TargetPlayerParser.java │ │ ├── database │ │ ├── DatabaseConfig.java │ │ ├── DatabaseConnection.java │ │ ├── Query.java │ │ └── Savable.java │ │ ├── events │ │ ├── CommunityEvent.java │ │ ├── PlayerHelpRequestEvent.java │ │ ├── PlayerPunishmentEvent.java │ │ ├── PlayerReportEvent.java │ │ └── UserProfileLoadEvent.java │ │ ├── feature │ │ ├── Feature.java │ │ ├── FeatureBase.java │ │ ├── FeatureManager.java │ │ ├── SQLFeature.java │ │ ├── SQLFeatureBase.java │ │ └── config │ │ │ ├── FeatureConfig.java │ │ │ └── FeatureConfigImpl.java │ │ ├── freeze │ │ ├── FreezeCommand.java │ │ ├── FreezeConfig.java │ │ ├── FreezeFeature.java │ │ └── FreezeManager.java │ │ ├── friends │ │ ├── FriendRequestStatus.java │ │ ├── Friendship.java │ │ ├── FriendshipConfig.java │ │ ├── commands │ │ │ └── FriendshipCommand.java │ │ ├── feature │ │ │ ├── FriendshipFeature.java │ │ │ ├── FriendshipFeatureBase.java │ │ │ ├── PGMFriendIntegration.java │ │ │ └── types │ │ │ │ └── SQLFriendshipFeature.java │ │ └── services │ │ │ ├── FriendshipQuery.java │ │ │ └── SQLFriendshipService.java │ │ ├── history │ │ ├── MatchHistoryCommand.java │ │ ├── MatchHistoryConfig.java │ │ ├── MatchHistoryEntry.java │ │ └── MatchHistoryFeature.java │ │ ├── info │ │ ├── InfoCommandConfig.java │ │ ├── InfoCommandData.java │ │ └── InfoCommandsFeature.java │ │ ├── menu │ │ ├── CommunityInventoryProvider.java │ │ ├── MapSelectionMenu.java │ │ ├── MenuItem.java │ │ ├── PageableInventory.java │ │ ├── PlayerSelectionProvider.java │ │ └── StaticMenuItem.java │ │ ├── mobs │ │ ├── MobCommand.java │ │ ├── MobConfig.java │ │ └── MobFeature.java │ │ ├── moderation │ │ ├── ModerationConfig.java │ │ ├── commands │ │ │ ├── BanCommand.java │ │ │ ├── BlockGlitchCommand.java │ │ │ ├── KickCommand.java │ │ │ ├── MuteCommand.java │ │ │ ├── PunishmentCommand.java │ │ │ ├── ToolCommand.java │ │ │ └── WarnCommand.java │ │ ├── feature │ │ │ ├── ModerationFeature.java │ │ │ ├── ModerationFeatureBase.java │ │ │ ├── PGMPunishmentIntegration.java │ │ │ ├── loggers │ │ │ │ ├── BlockGlitchLogger.java │ │ │ │ └── SignLogger.java │ │ │ └── types │ │ │ │ └── SQLModerationFeature.java │ │ ├── punishments │ │ │ ├── NetworkPunishment.java │ │ │ ├── Punishment.java │ │ │ ├── PunishmentFormats.java │ │ │ ├── PunishmentType.java │ │ │ └── types │ │ │ │ ├── BanPunishment.java │ │ │ │ ├── ExpirablePunishment.java │ │ │ │ ├── KickPunishment.java │ │ │ │ ├── MutePunishment.java │ │ │ │ ├── TempBanPunishment.java │ │ │ │ ├── UsernameBanPunishment.java │ │ │ │ └── WarnPunishment.java │ │ ├── services │ │ │ ├── ModerationQuery.java │ │ │ └── SQLModerationService.java │ │ └── tools │ │ │ ├── ModerationTools.java │ │ │ ├── Tool.java │ │ │ ├── ToolBase.java │ │ │ ├── buttons │ │ │ ├── ToolButton.java │ │ │ ├── ToolButtonBase.java │ │ │ ├── TranslatableToolButton.java │ │ │ └── types │ │ │ │ ├── GamemodeButton.java │ │ │ │ ├── NightVisionButton.java │ │ │ │ ├── ObserverVisibilityButton.java │ │ │ │ └── SpeedButton.java │ │ │ ├── menu │ │ │ ├── ModerationToolsMenu.java │ │ │ └── TeleportTargetMenu.java │ │ │ └── types │ │ │ ├── LookupSign.java │ │ │ ├── ModerationMenuTool.java │ │ │ └── TeleportHook.java │ │ ├── motd │ │ ├── MotdConfig.java │ │ └── MotdFeature.java │ │ ├── mutations │ │ ├── Mutation.java │ │ ├── MutationBase.java │ │ ├── MutationConfig.java │ │ ├── MutationType.java │ │ ├── commands │ │ │ └── MutationCommands.java │ │ ├── feature │ │ │ └── MutationFeature.java │ │ ├── menu │ │ │ ├── MutationOptionsMenu.java │ │ │ └── MutationToggleMenu.java │ │ ├── options │ │ │ ├── MutationBooleanOption.java │ │ │ ├── MutationListOption.java │ │ │ ├── MutationOption.java │ │ │ └── MutationRangeOption.java │ │ └── types │ │ │ ├── BowMutation.java │ │ │ ├── KitMutationBase.java │ │ │ ├── ScheduledMutationBase.java │ │ │ ├── arrows │ │ │ ├── EnderpearlMutation.java │ │ │ ├── FireballBowMutation.java │ │ │ ├── TNTBowMutation.java │ │ │ └── WebSlingersMutation.java │ │ │ ├── gameplay │ │ │ ├── BlitzMutation.java │ │ │ ├── GhostMutation.java │ │ │ └── RageMutation.java │ │ │ ├── items │ │ │ ├── BreadMutation.java │ │ │ ├── CannonSuppliesMutation.java │ │ │ ├── ExplosionMutation.java │ │ │ ├── FireworkMutation.java │ │ │ ├── GrapplingHookMutation.java │ │ │ ├── NoSpawnKitMutation.java │ │ │ └── PotionMutation.java │ │ │ ├── mapdev │ │ │ └── ProximityEffectsMutation.java │ │ │ ├── mechanics │ │ │ ├── BlindMutation.java │ │ │ ├── DoubleJumpMutation.java │ │ │ ├── FlyMutation.java │ │ │ ├── FriendlyFireMutation.java │ │ │ ├── HealthMutation.java │ │ │ ├── KnockbackMutation.java │ │ │ └── MobMutation.java │ │ │ └── world │ │ │ ├── BlockDecayMutation.java │ │ │ ├── StormMutation.java │ │ │ └── TNTRainMutation.java │ │ ├── network │ │ ├── Channels.java │ │ ├── NetworkConfig.java │ │ ├── feature │ │ │ ├── NetworkFeature.java │ │ │ └── NetworkFeatureBase.java │ │ ├── subs │ │ │ ├── NetworkSubscriber.java │ │ │ └── types │ │ │ │ ├── AssistanceSubscriber.java │ │ │ │ ├── ChatSubscriber.java │ │ │ │ ├── PunishmentSubscriber.java │ │ │ │ └── RefreshPunishmentSubscriber.java │ │ ├── types │ │ │ └── RedisNetworkFeature.java │ │ └── updates │ │ │ ├── NetworkUpdate.java │ │ │ ├── NetworkUpdateBase.java │ │ │ └── types │ │ │ ├── AssistUpdate.java │ │ │ ├── ChatUpdate.java │ │ │ ├── PunishmentUpdate.java │ │ │ └── RefreshPunishmentUpdate.java │ │ ├── nick │ │ ├── Nick.java │ │ ├── NickConfig.java │ │ ├── NickImpl.java │ │ ├── commands │ │ │ └── NickCommands.java │ │ ├── data │ │ │ └── NickSelection.java │ │ ├── feature │ │ │ ├── NickFeature.java │ │ │ ├── NickFeatureBase.java │ │ │ ├── PGMNickIntegration.java │ │ │ └── types │ │ │ │ └── SQLNickFeature.java │ │ ├── services │ │ │ ├── NickQuery.java │ │ │ └── SQLNickService.java │ │ └── skin │ │ │ ├── SkinCache.java │ │ │ └── SkinManager.java │ │ ├── party │ │ ├── MapParty.java │ │ ├── MapPartyBase.java │ │ ├── MapPartyCommands.java │ │ ├── MapPartyConfig.java │ │ ├── MapPartyMessages.java │ │ ├── MapPartyStatusType.java │ │ ├── MapPartyType.java │ │ ├── broadcasts │ │ │ └── MapPartyBroadcastManager.java │ │ ├── events │ │ │ ├── MapPartyCreateEvent.java │ │ │ ├── MapPartyEndEvent.java │ │ │ ├── MapPartyEvent.java │ │ │ ├── MapPartyRestartEvent.java │ │ │ └── MapPartyStartEvent.java │ │ ├── exceptions │ │ │ ├── MapPartyException.java │ │ │ └── MapPartySetupException.java │ │ ├── feature │ │ │ └── MapPartyFeature.java │ │ ├── hosts │ │ │ └── MapPartyHosts.java │ │ ├── menu │ │ │ ├── MapPartyMainMenu.java │ │ │ ├── MapPartyMenu.java │ │ │ ├── MapPartyTypeSelectionMenu.java │ │ │ ├── hosts │ │ │ │ ├── HostAddMenu.java │ │ │ │ └── HostMenu.java │ │ │ ├── maps │ │ │ │ ├── MapAddMenu.java │ │ │ │ └── MapMenu.java │ │ │ ├── modifiers │ │ │ │ └── MapPartyModifierMenu.java │ │ │ └── settings │ │ │ │ └── MapPartySettingsMenu.java │ │ ├── presets │ │ │ └── MapPartyPreset.java │ │ ├── settings │ │ │ ├── MapPartySettings.java │ │ │ ├── PartyBooleanSetting.java │ │ │ └── PartySetting.java │ │ └── types │ │ │ ├── CustomPoolParty.java │ │ │ └── RegularPoolParty.java │ │ ├── polls │ │ ├── Poll.java │ │ ├── PollBuilder.java │ │ ├── PollComponents.java │ │ ├── PollConfig.java │ │ ├── PollEditAlerter.java │ │ ├── PollThreshold.java │ │ ├── commands │ │ │ ├── PollManagementCommands.java │ │ │ └── PollVoteCommands.java │ │ ├── ending │ │ │ ├── EndAction.java │ │ │ └── types │ │ │ │ ├── CommandEndAction.java │ │ │ │ ├── KickPlayerEndAction.java │ │ │ │ ├── MapEndAction.java │ │ │ │ ├── MutationEndAction.java │ │ │ │ └── NullEndAction.java │ │ ├── events │ │ │ ├── PollEndEvent.java │ │ │ ├── PollEvent.java │ │ │ ├── PollStartEvent.java │ │ │ └── PollVoteEvent.java │ │ ├── feature │ │ │ └── PollFeature.java │ │ ├── response │ │ │ ├── MultiChoiceResponseConverter.java │ │ │ └── SingleChoiceResponseConverter.java │ │ └── types │ │ │ ├── BasicPoll.java │ │ │ ├── MultiChoicePoll.java │ │ │ └── SingleChoicePoll.java │ │ ├── requests │ │ ├── MapCooldown.java │ │ ├── RequestConfig.java │ │ ├── RequestProfile.java │ │ ├── SponsorRequest.java │ │ ├── commands │ │ │ ├── RequestCommands.java │ │ │ ├── sponsor │ │ │ │ ├── SponsorCommands.java │ │ │ │ └── TokenCommands.java │ │ │ └── supervotes │ │ │ │ ├── SuperVoteAdminCommands.java │ │ │ │ └── SuperVoteCommand.java │ │ ├── feature │ │ │ ├── RequestFeature.java │ │ │ ├── RequestFeatureBase.java │ │ │ ├── SponsorVotingBookCreator.java │ │ │ └── types │ │ │ │ ├── NoDBRequestFeature.java │ │ │ │ └── SQLRequestFeature.java │ │ ├── menu │ │ │ └── SponsorMenu.java │ │ ├── services │ │ │ ├── RequestQuery.java │ │ │ └── SQLRequestService.java │ │ ├── sponsor │ │ │ ├── SponsorComponents.java │ │ │ └── SponsorManager.java │ │ └── supervotes │ │ │ ├── SuperVoteComponents.java │ │ │ └── SuperVoteManager.java │ │ ├── sessions │ │ ├── Session.java │ │ ├── SessionQuery.java │ │ ├── VanishedSessionListener.java │ │ ├── feature │ │ │ ├── SessionFeature.java │ │ │ ├── SessionFeatureBase.java │ │ │ └── types │ │ │ │ └── SQLSessionFeature.java │ │ └── services │ │ │ ├── SQLSessionService.java │ │ │ └── SessionDataQuery.java │ │ ├── squads │ │ ├── Squad.java │ │ ├── SquadChannel.java │ │ ├── SquadCommands.java │ │ ├── SquadConfig.java │ │ └── SquadFeature.java │ │ ├── teleports │ │ ├── TeleportCommand.java │ │ ├── TeleportConfig.java │ │ ├── TeleportFeature.java │ │ └── TeleportFeatureBase.java │ │ ├── text │ │ ├── TextTranslations.java │ │ └── UTF8Control.java │ │ ├── users │ │ ├── UserProfile.java │ │ ├── UserProfileImpl.java │ │ ├── UserProfileWithSessionCallback.java │ │ ├── UsersConfig.java │ │ ├── commands │ │ │ └── UserInfoCommands.java │ │ ├── feature │ │ │ ├── UsersFeature.java │ │ │ ├── UsersFeatureBase.java │ │ │ └── types │ │ │ │ ├── NoDBUsersFeature.java │ │ │ │ └── SQLUsersFeature.java │ │ ├── listeners │ │ │ └── UserProfileLoginListener.java │ │ └── services │ │ │ ├── AddressHistoryService.java │ │ │ ├── AddressQuery.java │ │ │ ├── SQLUserService.java │ │ │ └── UserQuery.java │ │ └── utils │ │ ├── AFKDetection.java │ │ ├── BroadcastUtils.java │ │ ├── CenterUtils.java │ │ ├── CommandAudience.java │ │ ├── DatabaseUtils.java │ │ ├── ImportUtils.java │ │ ├── MessageUtils.java │ │ ├── NameUtils.java │ │ ├── NetworkUtils.java │ │ ├── PGMUtils.java │ │ ├── PaginatedComponentResults.java │ │ ├── SkullUtils.java │ │ ├── Sounds.java │ │ ├── VisibilityUtils.java │ │ ├── WebUtils.java │ │ ├── compatibility │ │ ├── Enchantments.java │ │ ├── EntityTypes.java │ │ ├── Materials.java │ │ └── PotionEffects.java │ │ ├── gson │ │ ├── GsonProvider.java │ │ └── types │ │ │ └── DurationConverter.java │ │ └── ranks │ │ ├── RankUtils.java │ │ └── RanksConfig.java │ └── resources │ ├── config.yml │ ├── plugin.yml │ └── strings.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew └── settings.gradle.kts /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | pull_request: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - dev 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: checkout 13 | uses: actions/checkout@v4 14 | with: 15 | fetch-depth: 0 16 | - name: setup 17 | uses: actions/setup-java@v4 18 | with: 19 | java-version: 21 20 | distribution: temurin 21 | # Configures gradle with caching 22 | - name: Setup Gradle 23 | uses: gradle/actions/setup-gradle@v4 24 | # Run "gradlew publish" for origin/dev and "gradlew build" for PRs or elsewhere 25 | - name: Execute Gradle ${{ (github.repository == 'PGMDev/Community' && github.ref == 'refs/heads/dev') && 'Publish' || 'Build' }} 26 | run: ./gradlew ${{ (github.repository == 'PGMDev/Community' && github.ref == 'refs/heads/dev') && 'publish' || 'build' }} 27 | env: 28 | GITHUB_TOKEN: ${{ (github.repository == 'PGMDev/Community' && github.ref == 'refs/heads/dev') && secrets.GITHUB_TOKEN || '' }} 29 | - name: artifact 30 | uses: actions/upload-artifact@v4 31 | with: 32 | name: Community.jar 33 | path: build/libs/Community.jar 34 | if-no-files-found: error 35 | 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | pom.xml.tag 3 | pom.xml.releaseBackup 4 | pom.xml.versionsBackup 5 | pom.xml.next 6 | release.properties 7 | dependency-reduced-pom.xml 8 | buildNumber.properties 9 | .mvn/timing.properties 10 | # https://github.com/takari/maven-wrapper#usage-without-binary-jar 11 | .mvn/wrapper/maven-wrapper.jar 12 | bin/ 13 | *.class 14 | *.log 15 | *.ctxt 16 | *.war 17 | *.nar 18 | *.ear 19 | *.zip 20 | *.tar.gz 21 | *.rar 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | # IntelliJ files 25 | .idea 26 | *.iml 27 | # Eclipse 28 | .classpath 29 | .project 30 | .settings 31 | build 32 | .gradle 33 | .DS_Store 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Community 2 | A PGM companion plugin for effortless community management 3 | 4 | # Introduction 5 | Community offers an all-in-one solution for managing Minecraft PGM server communities. It is designed specifically to work with PGM, but can also be used independently. This project aims to provide a comprehensive yet user-friendly platform for server administrators to manage players, track accounts, and offer a wide range of useful features. The plugin will continuously evolve, with new features being added regularly. 6 | 7 | # Key Features: 8 | - Robust Moderation Tools 9 | - Account Tracking 10 | - Teleportation 11 | - User Assistance/Reporting System 12 | - User-friendly Friendship System 13 | - Nickname System 14 | - Map Party System 15 | - Match Mutations 16 | - Player Party/Squad System 17 | - Polls 18 | - Cross-Server Chat & Report Functionality 19 | - Utility Commands 20 | 21 | ## Governance 22 | This project is maintained by [applenick](https://github.com/applenick), with assistance from [Electroid](https://github.com/Electroid) and other PGMDev developers. 23 | -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | // Support convention plugins written in Kotlin. Convention plugins are build scripts in 'src/main' that automatically become available as plugins in the main build. 3 | `kotlin-dsl` 4 | } 5 | 6 | repositories { 7 | // Use the plugin portal to apply community plugins in convention plugins. 8 | gradlePluginPortal() 9 | } 10 | 11 | dependencies { 12 | implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.0") 13 | implementation("com.diffplug.spotless:spotless-plugin-gradle:7.0.0.BETA4") 14 | implementation("de.skuzzle.restrictimports:restrict-imports-gradle-plugin:2.6.0") 15 | } 16 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/extensions.kt: -------------------------------------------------------------------------------- 1 | import org.gradle.api.Project 2 | import java.io.ByteArrayOutputStream 3 | 4 | 5 | fun Project.latestCommitHash(): String { 6 | return runGitCommand(listOf("rev-parse", "--short", "HEAD")) 7 | } 8 | 9 | fun Project.runGitCommand(args: List): String { 10 | val byteOut = ByteArrayOutputStream() 11 | exec { 12 | commandLine = listOf("git") + args 13 | standardOutput = byteOut 14 | } 15 | return byteOut.toString(Charsets.UTF_8.name()).trim() 16 | } -------------------------------------------------------------------------------- /core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar 2 | 3 | plugins { 4 | id("buildlogic.java-conventions") 5 | `maven-publish` 6 | id("com.gradleup.shadow") 7 | } 8 | 9 | tasks.named("shadowJar") { 10 | archiveFileName = "Community.jar" 11 | archiveClassifier.set("") 12 | destinationDirectory = rootProject.projectDir.resolve("build/libs") 13 | 14 | minimize() 15 | 16 | dependencies { 17 | exclude(dependency("org.jetbrains:annotations")) 18 | } 19 | 20 | exclude("META-INF/**") 21 | } 22 | 23 | publishing { 24 | publications.create("community") { 25 | groupId = project.group as String 26 | artifactId = project.name 27 | version = project.version as String 28 | 29 | artifact(tasks["shadowJar"]) 30 | } 31 | repositories { 32 | maven { 33 | name = "ghPackages" 34 | url = uri("https://maven.pkg.github.com/PGMDev/Community") 35 | credentials { 36 | username = System.getenv("GITHUB_ACTOR") 37 | password = System.getenv("GITHUB_TOKEN") 38 | } 39 | } 40 | } 41 | } 42 | 43 | tasks { 44 | processResources { 45 | filesMatching(listOf("plugin.yml")) { 46 | expand( 47 | "name" to project.name, 48 | "description" to project.description, 49 | "mainClass" to "dev.pgm.community.Community", 50 | "version" to project.version, 51 | "commitHash" to project.latestCommitHash(), 52 | "author" to "applenick", 53 | "url" to "https://pgm.dev/") 54 | } 55 | } 56 | 57 | named("build") { 58 | dependsOn(shadowJar) 59 | } 60 | } -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/CommunityConfig.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community; 2 | 3 | import dev.pgm.community.utils.NetworkUtils; 4 | import dev.pgm.community.utils.ranks.RanksConfig; 5 | import org.bukkit.configuration.Configuration; 6 | import tc.oc.occ.environment.Environment; 7 | 8 | public class CommunityConfig { 9 | 10 | private String serverDisplayName; 11 | private String serverId; 12 | private boolean useEnvironment; 13 | private String environmentServerIdKey; 14 | private RanksConfig ranks; 15 | private String storeLink; 16 | 17 | public CommunityConfig(Configuration config) { 18 | reload(config); 19 | } 20 | 21 | public void reload(Configuration config) { 22 | this.ranks = new RanksConfig(config); 23 | this.serverDisplayName = config.getString("general.server-name", ""); 24 | this.serverId = config.getString("general.server-id", ""); 25 | this.useEnvironment = config.getBoolean("general.use-environment"); 26 | this.environmentServerIdKey = config.getString("general.environment-server-id"); 27 | this.storeLink = config.getString("general.store-link"); 28 | } 29 | 30 | public String getServerDisplayName() { 31 | return serverDisplayName; 32 | } 33 | 34 | public String getServerId() { 35 | if (useEnvironment) { 36 | String serverId = Environment.get().getString(environmentServerIdKey); 37 | if (serverId != null && !serverId.isEmpty()) { 38 | return serverId; 39 | } 40 | } 41 | return NetworkUtils.getServerVar(serverId); 42 | } 43 | 44 | public boolean isEnvironmentEnabled() { 45 | return useEnvironment && Environment.get() != null; 46 | } 47 | 48 | public RanksConfig getRanksConfig() { 49 | return ranks; 50 | } 51 | 52 | public String getStoreLink() { 53 | return storeLink; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/assistance/AssistanceRequest.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.assistance; 2 | 3 | import java.time.Instant; 4 | import java.util.UUID; 5 | 6 | // Represents a request for staff help by a player 7 | public class AssistanceRequest { 8 | 9 | private UUID senderId; 10 | private UUID targetId; 11 | private long time; 12 | private String reason; 13 | private String server; 14 | private RequestType type; 15 | 16 | public AssistanceRequest() {} 17 | 18 | public AssistanceRequest( 19 | UUID senderId, UUID targetId, long time, String reason, String server, RequestType type) { 20 | this.senderId = senderId; 21 | this.targetId = targetId; 22 | this.time = time; 23 | this.reason = reason; 24 | this.server = server; 25 | this.type = type; 26 | } 27 | 28 | public UUID getSenderId() { 29 | return senderId; 30 | } 31 | 32 | public UUID getTargetId() { 33 | return targetId; 34 | } 35 | 36 | public Instant getTime() { 37 | return Instant.ofEpochMilli(time); 38 | } 39 | 40 | public String getReason() { 41 | return reason; 42 | } 43 | 44 | public String getServer() { 45 | return server; 46 | } 47 | 48 | public RequestType getType() { 49 | return type; 50 | } 51 | 52 | public static enum RequestType { 53 | PLAYER_HELP, 54 | REPORT; 55 | } 56 | 57 | @Override 58 | public String toString() { 59 | return String.format( 60 | "{target: %s, sender: %s, reason:%s, time:%s, server:%s, type: %s}", 61 | getTargetId().toString(), 62 | getSenderId().toString(), 63 | getReason(), 64 | getTime(), 65 | getServer(), 66 | getType().name()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/assistance/PlayerHelpRequest.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.assistance; 2 | 3 | import java.time.Instant; 4 | import java.util.UUID; 5 | import org.bukkit.entity.Player; 6 | 7 | public class PlayerHelpRequest extends AssistanceRequest { 8 | 9 | public PlayerHelpRequest(Player player, String reason, String server) { 10 | this(player.getUniqueId(), reason, Instant.now().toEpochMilli(), server); 11 | } 12 | 13 | public PlayerHelpRequest(UUID playerId, String reason, long time, String server) { 14 | super(playerId, playerId, time, reason, server, RequestType.PLAYER_HELP); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/assistance/Report.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.assistance; 2 | 3 | import java.util.UUID; 4 | 5 | public class Report extends AssistanceRequest implements Comparable { 6 | 7 | private final UUID reportId; 8 | private boolean notifiedSender; 9 | 10 | /** 11 | * Report Holds information related to a report 12 | * 13 | * @param reportedId UUID of reported player 14 | * @param reporterId UUID of reporting player 15 | * @param reason reason for report 16 | * @param time time reported 17 | * @param name of current server 18 | */ 19 | public Report(UUID reportedId, UUID reporterId, String reason, long time, String server) { 20 | this(UUID.randomUUID(), reportedId, reporterId, reason, time, server); 21 | } 22 | 23 | public Report( 24 | UUID reportId, UUID reportedId, UUID reporterId, String reason, long time, String server) { 25 | super(reporterId, reportedId, time, reason, server, RequestType.REPORT); 26 | this.reportId = reportId; 27 | this.notifiedSender = false; 28 | } 29 | 30 | /** 31 | * Get the {@link UUID} which identifies the report 32 | * 33 | * @return report id 34 | */ 35 | public UUID getId() { 36 | return reportId; 37 | } 38 | 39 | public void setNotified(boolean notified) { 40 | this.notifiedSender = notified; 41 | } 42 | 43 | public boolean hasNotified() { 44 | return notifiedSender; 45 | } 46 | 47 | @Override 48 | public int compareTo(Report o) { 49 | return -getTime().compareTo(o.getTime()); 50 | } 51 | 52 | @Override 53 | public boolean equals(Object other) { 54 | if (!(other instanceof Report)) return false; 55 | Report otherReport = (Report) other; 56 | return getId().equals(otherReport.getId()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/assistance/commands/PlayerHelpCommand.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.assistance.commands; 2 | 3 | import dev.pgm.community.Community; 4 | import dev.pgm.community.CommunityCommand; 5 | import dev.pgm.community.assistance.feature.AssistanceFeature; 6 | import dev.pgm.community.moderation.feature.ModerationFeature; 7 | import dev.pgm.community.moderation.punishments.types.MutePunishment; 8 | import dev.pgm.community.utils.CommandAudience; 9 | import java.util.Optional; 10 | import org.bukkit.entity.Player; 11 | import tc.oc.pgm.lib.org.incendo.cloud.annotation.specifier.Greedy; 12 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Argument; 13 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Command; 14 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.CommandDescription; 15 | 16 | public class PlayerHelpCommand extends CommunityCommand { 17 | 18 | private AssistanceFeature assistance; 19 | private ModerationFeature moderation; 20 | 21 | public PlayerHelpCommand() { 22 | this.assistance = Community.get().getFeatures().getReports(); 23 | this.moderation = Community.get().getFeatures().getModeration(); 24 | } 25 | 26 | @Command("assistance|assist|helpop|helpme ") 27 | @CommandDescription("Request help from a staff member") 28 | public void assistanceCommand( 29 | CommandAudience viewer, Player player, @Argument("reason") @Greedy String reason) { 30 | Optional mute = moderation.getCachedMute(player.getUniqueId()); 31 | if (mute.isPresent()) { 32 | viewer.sendWarning(mute.get().getChatMuteMessage()); 33 | return; 34 | } 35 | 36 | if (!assistance.canRequest(player.getUniqueId())) { 37 | int cooldown = assistance.getCooldownSeconds(player.getUniqueId()); 38 | if (cooldown > 0) { 39 | viewer.sendWarning(assistance.getCooldownMessage(player.getUniqueId())); 40 | return; 41 | } 42 | } 43 | assistance.assist(player, reason); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/assistance/feature/AssistanceFeature.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.assistance.feature; 2 | 3 | import dev.pgm.community.assistance.AssistanceRequest; 4 | import dev.pgm.community.assistance.Report; 5 | import dev.pgm.community.feature.Feature; 6 | import java.util.List; 7 | import java.util.Set; 8 | import java.util.UUID; 9 | import java.util.concurrent.CompletableFuture; 10 | import net.kyori.adventure.text.Component; 11 | import org.bukkit.entity.Player; 12 | 13 | /** 14 | * AssistanceFeature - Features which allow players to request assistance or report troublemakers * 15 | */ 16 | public interface AssistanceFeature extends Feature { 17 | 18 | void requestAssistance(Player sender, Player target, String reason); 19 | 20 | void assist(Player sender, String reason); 21 | 22 | Report report(Player sender, Player target, String reason); 23 | 24 | CompletableFuture> query(String target); 25 | 26 | Set getRecentReports(); 27 | 28 | boolean canRequest(UUID playerId); 29 | 30 | int getCooldownSeconds(UUID playerId); 31 | 32 | Component getCooldownMessage(UUID playerId); 33 | 34 | void invalidate(UUID playerId); 35 | 36 | void sendUpdate(AssistanceRequest request); 37 | 38 | void recieveUpdate(AssistanceRequest request); 39 | 40 | void openReportsMenu(Player sender, Player target); 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/assistance/feature/types/NoDBAssistanceFeature.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.assistance.feature.types; 2 | 3 | import com.google.common.collect.Lists; 4 | import dev.pgm.community.assistance.Report; 5 | import dev.pgm.community.assistance.ReportConfig; 6 | import dev.pgm.community.assistance.feature.AssistanceFeatureBase; 7 | import dev.pgm.community.network.feature.NetworkFeature; 8 | import dev.pgm.community.users.feature.UsersFeature; 9 | import fr.minuskube.inv.InventoryManager; 10 | import java.util.List; 11 | import java.util.UUID; 12 | import java.util.concurrent.CompletableFuture; 13 | import java.util.logging.Logger; 14 | import org.bukkit.configuration.Configuration; 15 | 16 | public class NoDBAssistanceFeature extends AssistanceFeatureBase { 17 | 18 | public NoDBAssistanceFeature( 19 | Configuration config, 20 | Logger logger, 21 | NetworkFeature network, 22 | UsersFeature users, 23 | InventoryManager inventory) { 24 | super(new ReportConfig(config), logger, "Assistance (No Database)", network, users, inventory); 25 | } 26 | 27 | @Override 28 | public CompletableFuture> query(String target) { 29 | return CompletableFuture.completedFuture(Lists.newArrayList()); 30 | } 31 | 32 | @Override 33 | public void invalidate(UUID playerId) { 34 | // No-op 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/assistance/menu/ReportCategory.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.assistance.menu; 2 | 3 | import dev.pgm.community.menu.MenuItem; 4 | import java.util.List; 5 | import org.bukkit.Material; 6 | 7 | public class ReportCategory extends MenuItem { 8 | 9 | private final List reasons; 10 | 11 | public ReportCategory( 12 | String name, List description, Material icon, List reasons) { 13 | super(icon, name, description); 14 | this.reasons = reasons; 15 | } 16 | 17 | public List getReasons() { 18 | return reasons; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/assistance/menu/ReportReason.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.assistance.menu; 2 | 3 | import dev.pgm.community.menu.MenuItem; 4 | import java.util.List; 5 | import org.bukkit.Material; 6 | 7 | public class ReportReason extends MenuItem { 8 | 9 | public ReportReason(String name, List description, Material icon) { 10 | super(icon, name, description); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/assistance/menu/ReportReasonsMenu.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.assistance.menu; 2 | 3 | import dev.pgm.community.assistance.feature.AssistanceFeature; 4 | import dev.pgm.community.menu.CommunityInventoryProvider; 5 | import fr.minuskube.inv.content.InventoryContents; 6 | import java.util.function.Consumer; 7 | import org.bukkit.ChatColor; 8 | import org.bukkit.Material; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.event.inventory.InventoryClickEvent; 11 | import org.bukkit.inventory.ItemFlag; 12 | import org.bukkit.inventory.ItemStack; 13 | import tc.oc.pgm.util.bukkit.BukkitUtils; 14 | import tc.oc.pgm.util.inventory.ItemBuilder; 15 | 16 | public class ReportReasonsMenu extends CommunityInventoryProvider { 17 | 18 | private AssistanceFeature feature; 19 | private ReportCategory category; 20 | private Player target; 21 | 22 | public ReportReasonsMenu(AssistanceFeature feature, Player target, ReportCategory category) { 23 | super(category.getReasons()); 24 | this.feature = feature; 25 | this.target = target; 26 | this.category = category; 27 | } 28 | 29 | @Override 30 | public Consumer getClickAction( 31 | ReportReason reason, Player viewer, InventoryContents contents) { 32 | return e -> { 33 | feature.report( 34 | viewer, 35 | target, 36 | ChatColor.stripColor(String.format("%s - %s", category.getName(), reason.getName()))); 37 | viewer.closeInventory(); 38 | }; 39 | } 40 | 41 | @Override 42 | protected ItemStack getNoResultsItem() { 43 | return new ItemBuilder() 44 | .material(Material.BARRIER) 45 | .name(BukkitUtils.colorize("&c&lNo Reasons found")) 46 | .lore(BukkitUtils.colorize("&7No reasons provided in config for " + category.getName())) 47 | .flags(ItemFlag.values()) 48 | .build(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/assistance/services/AssistanceQuery.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.assistance.services; 2 | 3 | public interface AssistanceQuery { 4 | 5 | static final String TABLE_NAME = "reports"; 6 | static final String TABLE_FIELDS = 7 | "(id VARCHAR(36) PRIMARY KEY, " 8 | + "sender VARCHAR(36), " 9 | + "reported VARCHAR(36), " 10 | + "reason VARCHAR(255), " 11 | + "time LONG, " 12 | + "server VARCHAR(255))"; 13 | static final String INSERT_REPORT_QUERY = 14 | "INSERT INTO " 15 | + TABLE_NAME 16 | + "(id, sender, reported, reason, time, server) VALUES (?, ?, ?, ?, ?, ?)"; 17 | static final String SELECT_REPORT_QUERY = 18 | "SELECT id, sender, reason, time FROM " + TABLE_NAME + " WHERE reported = ?"; 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/broadcast/BroadcastCommand.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.broadcast; 2 | 3 | import dev.pgm.community.Community; 4 | import dev.pgm.community.CommunityCommand; 5 | import dev.pgm.community.CommunityPermissions; 6 | import tc.oc.pgm.lib.org.incendo.cloud.annotation.specifier.FlagYielding; 7 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Argument; 8 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Command; 9 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.CommandDescription; 10 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Flag; 11 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Permission; 12 | 13 | public class BroadcastCommand extends CommunityCommand { 14 | 15 | private final BroadcastFeature broadcast; 16 | 17 | public BroadcastCommand() { 18 | this.broadcast = Community.get().getFeatures().getBroadcast(); 19 | } 20 | 21 | @Command("broadcast|announce|bc ") 22 | @CommandDescription("Broadcast an announcement to everyone") 23 | @Permission(CommunityPermissions.BROADCAST) 24 | public void broadcastChat( 25 | @Argument("message") @FlagYielding String message, 26 | @Flag(value = "title", aliases = "t") boolean title) { 27 | broadcast.broadcast(message, title); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/chat/management/ChatManagementConfig.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.chat.management; 2 | 3 | import static tc.oc.pgm.util.text.TextParser.parseDuration; 4 | 5 | import com.google.common.cache.Cache; 6 | import com.google.common.cache.CacheBuilder; 7 | import dev.pgm.community.feature.config.FeatureConfigImpl; 8 | import java.time.Duration; 9 | import java.time.Instant; 10 | import java.util.UUID; 11 | import java.util.concurrent.TimeUnit; 12 | import org.bukkit.configuration.Configuration; 13 | 14 | /** Configuration related to chat management features */ 15 | public class ChatManagementConfig extends FeatureConfigImpl { 16 | 17 | public static final String KEY = "chat"; 18 | 19 | private int slowmodeSpeed; 20 | private boolean loginAlerts; 21 | private boolean blockRepeatedMessages; 22 | private Duration expireRepeatedMessages; 23 | 24 | private Cache lastSentMessage; 25 | 26 | public ChatManagementConfig(Configuration config) { 27 | super(KEY, config); 28 | } 29 | 30 | public int getSlowmodeSpeed() { 31 | return slowmodeSpeed; 32 | } 33 | 34 | public Cache getLastMessageCache() { 35 | return lastSentMessage; 36 | } 37 | 38 | public boolean isLoginAlertsEnabled() { 39 | return loginAlerts; 40 | } 41 | 42 | public boolean isBlockRepeatedMessagesEnabled() { 43 | return blockRepeatedMessages; 44 | } 45 | 46 | public Duration getRepeatedMessagesExpireDuration() { 47 | return expireRepeatedMessages; 48 | } 49 | 50 | @Override 51 | public void reload(Configuration config) { 52 | super.reload(config); 53 | this.slowmodeSpeed = config.getInt(KEY + ".slowmode-speed"); 54 | this.loginAlerts = config.getBoolean(KEY + ".login-alert"); 55 | this.lastSentMessage = 56 | CacheBuilder.newBuilder().expireAfterWrite(slowmodeSpeed, TimeUnit.SECONDS).build(); 57 | this.blockRepeatedMessages = config.getBoolean(KEY + ".block-repeated-messages"); 58 | this.expireRepeatedMessages = 59 | parseDuration(config.getString(KEY + ".expire-repeated-messages")); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/chat/network/NetworkChatConfig.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.chat.network; 2 | 3 | import dev.pgm.community.feature.config.FeatureConfigImpl; 4 | import org.bukkit.configuration.Configuration; 5 | 6 | public class NetworkChatConfig extends FeatureConfigImpl { 7 | 8 | private static final String KEY = "network.chat"; 9 | 10 | public NetworkChatConfig(Configuration config) { 11 | super(KEY, config); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/chat/network/NetworkChatMessage.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.chat.network; 2 | 3 | import static net.kyori.adventure.text.Component.text; 4 | import static tc.oc.pgm.util.player.PlayerComponent.player; 5 | 6 | import net.kyori.adventure.text.Component; 7 | import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; 8 | import tc.oc.pgm.api.event.ChannelMessageEvent; 9 | import tc.oc.pgm.util.Audience; 10 | import tc.oc.pgm.util.named.NameStyle; 11 | import tc.oc.pgm.util.text.TextTranslations; 12 | 13 | public class NetworkChatMessage { 14 | 15 | private String message; 16 | private String sender; 17 | private String server; 18 | private String channel; 19 | 20 | public NetworkChatMessage(ChannelMessageEvent event, String server) { 21 | this.message = toMinecraftGson(text(event.getMessage())); 22 | this.sender = toMinecraftGson(player(event.getSender(), NameStyle.FANCY)); 23 | this.channel = event.getChannel().getDisplayName(); 24 | this.server = server; 25 | } 26 | 27 | public Component getMessage() { 28 | return GsonComponentSerializer.colorDownsamplingGson().deserialize(message); 29 | } 30 | 31 | public Component getSender() { 32 | return GsonComponentSerializer.colorDownsamplingGson().deserialize(sender); 33 | } 34 | 35 | public String getServer() { 36 | return server; 37 | } 38 | 39 | public String getChannel() { 40 | return channel; 41 | } 42 | 43 | private static String toMinecraftGson(Component component) { 44 | Component translated = TextTranslations.translate(component, Audience.empty()); 45 | return GsonComponentSerializer.colorDownsamplingGson().serialize(translated); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/commands/ServerInfoCommand.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.commands; 2 | 3 | import static net.kyori.adventure.text.Component.text; 4 | 5 | import dev.pgm.community.CommunityCommand; 6 | import dev.pgm.community.utils.CommandAudience; 7 | import java.time.Duration; 8 | import java.time.Instant; 9 | import net.kyori.adventure.text.format.NamedTextColor; 10 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Command; 11 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.CommandDescription; 12 | import tc.oc.pgm.util.text.TemporalComponent; 13 | 14 | public class ServerInfoCommand extends CommunityCommand { 15 | 16 | private final Instant startTime; 17 | 18 | public ServerInfoCommand() { 19 | this.startTime = Instant.now(); 20 | } 21 | 22 | @Command("uptime") 23 | @CommandDescription("View how long the server has been online") 24 | public void uptime(CommandAudience sender) { 25 | Duration uptime = Duration.between(startTime, Instant.now()); 26 | sender.sendMessage( 27 | text() 28 | .append(text("Server has been online for ")) 29 | .append(TemporalComponent.duration(uptime, NamedTextColor.GREEN)) 30 | .color(NamedTextColor.GRAY) 31 | .build()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/commands/StaffCommand.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.commands; 2 | 3 | import static net.kyori.adventure.text.Component.text; 4 | import static net.kyori.adventure.text.Component.translatable; 5 | 6 | import dev.pgm.community.CommunityCommand; 7 | import dev.pgm.community.CommunityPermissions; 8 | import dev.pgm.community.utils.CommandAudience; 9 | import java.util.List; 10 | import java.util.stream.Collectors; 11 | import net.kyori.adventure.text.Component; 12 | import net.kyori.adventure.text.format.NamedTextColor; 13 | import org.bukkit.Bukkit; 14 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Command; 15 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.CommandDescription; 16 | import tc.oc.pgm.util.named.NameStyle; 17 | import tc.oc.pgm.util.player.PlayerComponent; 18 | import tc.oc.pgm.util.text.TextFormatter; 19 | 20 | public class StaffCommand extends CommunityCommand { 21 | 22 | @Command("staff|mods|admins|ops") 23 | @CommandDescription("View a list of online staff members") 24 | public void staff(CommandAudience viewer) { 25 | List onlineStaff = 26 | Bukkit.getOnlinePlayers().stream() 27 | .filter( 28 | player -> 29 | (player.hasPermission(CommunityPermissions.STAFF) 30 | && (!isDisguised(player) 31 | || viewer.hasPermission(CommunityPermissions.STAFF)))) 32 | .map(player -> PlayerComponent.player(player, NameStyle.VERBOSE)) 33 | .collect(Collectors.toList()); 34 | 35 | // FORMAT: Online Staff ({count}): {names} 36 | Component staffCount = 37 | text(Integer.toString(onlineStaff.size())) 38 | .color(onlineStaff.isEmpty() ? NamedTextColor.RED : NamedTextColor.AQUA); 39 | 40 | Component content = 41 | onlineStaff.isEmpty() 42 | ? translatable("moderation.staff.empty") 43 | : TextFormatter.list(onlineStaff, NamedTextColor.GRAY); 44 | 45 | Component staff = 46 | translatable("moderation.staff.name", NamedTextColor.GRAY, staffCount, content); 47 | 48 | viewer.sendMessage(staff); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/commands/SudoCommand.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.commands; 2 | 3 | import static net.kyori.adventure.text.Component.text; 4 | 5 | import dev.pgm.community.CommunityCommand; 6 | import dev.pgm.community.CommunityPermissions; 7 | import dev.pgm.community.utils.CommandAudience; 8 | import net.kyori.adventure.text.format.NamedTextColor; 9 | import tc.oc.pgm.lib.org.incendo.cloud.annotation.specifier.Greedy; 10 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Argument; 11 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Command; 12 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.CommandDescription; 13 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Permission; 14 | 15 | public class SudoCommand extends CommunityCommand { 16 | 17 | @Command("sudo|force ") 18 | @CommandDescription("Force targets to perform given command") 19 | @Permission(CommunityPermissions.ADMIN) 20 | public void sudo( 21 | CommandAudience sender, 22 | @Argument("targets") String targets, 23 | @Argument("command") @Greedy String command) { 24 | if (sender.isPlayer() && !sender.getPlayer().isOp()) { 25 | sender.sendWarning(text("This command is reserved for administrators")); 26 | return; 27 | } 28 | 29 | PlayerSelection selection = getPlayers(sender, targets); 30 | if (!selection.getPlayers().isEmpty()) { 31 | final String targetCommand = command.startsWith("/") ? command.substring(1) : command; 32 | selection.getPlayers().forEach(player -> player.performCommand(targetCommand)); 33 | sender.sendMessage( 34 | text() 35 | .append(text("Forcing ")) 36 | .append(selection.getText()) 37 | .append(text(" to run ")) 38 | .append(text("/", NamedTextColor.AQUA)) 39 | .append(text(targetCommand, NamedTextColor.AQUA)) 40 | .color(NamedTextColor.GRAY) 41 | .build()); 42 | } else { 43 | selection.sendNoPlayerComponent(sender); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/commands/VanishedCommand.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.commands; 2 | 3 | import static net.kyori.adventure.text.Component.text; 4 | 5 | import dev.pgm.community.CommunityCommand; 6 | import dev.pgm.community.CommunityPermissions; 7 | import dev.pgm.community.utils.CommandAudience; 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | import net.kyori.adventure.text.Component; 11 | import net.kyori.adventure.text.format.NamedTextColor; 12 | import org.bukkit.Bukkit; 13 | import tc.oc.pgm.api.integration.Integration; 14 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Command; 15 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.CommandDescription; 16 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Permission; 17 | import tc.oc.pgm.util.named.NameStyle; 18 | import tc.oc.pgm.util.player.PlayerComponent; 19 | import tc.oc.pgm.util.text.TextFormatter; 20 | 21 | public class VanishedCommand extends CommunityCommand { 22 | @Command("vanished") 23 | @CommandDescription("View a list of online vanished players") 24 | @Permission(CommunityPermissions.VIEW_VANISHED) 25 | public void viewVanished(CommandAudience viewer) { 26 | List vanishedNames = 27 | Bukkit.getOnlinePlayers().stream() 28 | .filter(Integration::isVanished) 29 | .map(player -> PlayerComponent.player(player, NameStyle.VERBOSE)) 30 | .collect(Collectors.toList()); 31 | 32 | if (vanishedNames.isEmpty()) { 33 | viewer.sendWarning(text("No online players are vanished!")); 34 | return; 35 | } 36 | 37 | Component count = 38 | text() 39 | .append(text("Vanished", NamedTextColor.DARK_AQUA)) 40 | .append(text(": ")) 41 | .append(text(vanishedNames.size())) 42 | .build(); 43 | Component nameList = TextFormatter.list(vanishedNames, NamedTextColor.GRAY); 44 | 45 | viewer.sendMessage(count); 46 | viewer.sendMessage(nameList); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/commands/injectors/CommandAudienceProvider.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.commands.injectors; 2 | 3 | import dev.pgm.community.utils.CommandAudience; 4 | import org.bukkit.command.CommandSender; 5 | import org.jetbrains.annotations.NotNull; 6 | import tc.oc.pgm.lib.org.incendo.cloud.context.CommandContext; 7 | import tc.oc.pgm.lib.org.incendo.cloud.injection.ParameterInjector; 8 | import tc.oc.pgm.lib.org.incendo.cloud.util.annotation.AnnotationAccessor; 9 | 10 | public final class CommandAudienceProvider 11 | implements ParameterInjector { 12 | 13 | @Override 14 | public @NotNull CommandAudience create( 15 | CommandContext context, @NotNull AnnotationAccessor annotations) { 16 | return new CommandAudience(context.sender()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/commands/player/TargetPlayer.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.commands.player; 2 | 3 | import static tc.oc.pgm.util.Assert.assertNotNull; 4 | import static tc.oc.pgm.util.text.TextException.exception; 5 | 6 | import dev.pgm.community.utils.NameUtils; 7 | import java.util.Optional; 8 | import java.util.UUID; 9 | import org.bukkit.Bukkit; 10 | import org.bukkit.command.CommandSender; 11 | import org.bukkit.entity.Player; 12 | import tc.oc.pgm.util.text.TextException; 13 | import tc.oc.pgm.util.text.TextParser; 14 | 15 | public final class TargetPlayer { 16 | 17 | private Optional playerId = Optional.empty(); 18 | private Optional name = Optional.empty(); 19 | 20 | public TargetPlayer(Player player) { 21 | assertNotNull(player); 22 | this.playerId = Optional.of(player.getUniqueId()); 23 | this.name = Optional.of(player.getName()); 24 | } 25 | 26 | public TargetPlayer(CommandSender viewer, String input) throws TextException { 27 | if (input == null || !NameUtils.isIdentifier(input)) { 28 | throw exception("Invalid player identifier: " + input); 29 | } 30 | 31 | if (NameUtils.isPlayerId(input)) { 32 | this.playerId = Optional.of(TextParser.parseUuid(input)); 33 | Player player = Bukkit.getPlayer(playerId.get()); 34 | if (player != null) { 35 | this.name = Optional.of(player.getName()); 36 | } 37 | } else { 38 | this.name = Optional.of(input); 39 | Player player = Bukkit.getPlayer(input); 40 | if (player != null) { 41 | this.playerId = Optional.of(player.getUniqueId()); 42 | } 43 | } 44 | } 45 | 46 | public Optional getUUID() { 47 | return this.playerId; 48 | } 49 | 50 | public Optional getName() { 51 | return this.name; 52 | } 53 | 54 | public String getIdentifier() { 55 | return getUUID().map(UUID::toString).orElse(getName().orElse(null)); 56 | } 57 | 58 | public Player getPlayer() { 59 | if (getUUID().isPresent()) { 60 | return Bukkit.getPlayer(getUUID().get()); 61 | } 62 | 63 | if (getName().isPresent()) { 64 | return Bukkit.getPlayer(getName().get()); 65 | } 66 | 67 | return null; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/commands/providers/GameModeParser.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.commands.providers; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import org.apache.commons.lang.StringUtils; 6 | import org.bukkit.GameMode; 7 | import org.bukkit.command.CommandSender; 8 | import tc.oc.pgm.command.parsers.EnumParser; 9 | import tc.oc.pgm.lib.org.incendo.cloud.context.CommandContext; 10 | import tc.oc.pgm.lib.org.incendo.cloud.context.CommandInput; 11 | import tc.oc.pgm.lib.org.incendo.cloud.suggestion.BlockingSuggestionProvider; 12 | 13 | public class GameModeParser extends EnumParser 14 | implements BlockingSuggestionProvider.Strings { 15 | 16 | public GameModeParser() { 17 | super(GameMode.class); 18 | } 19 | 20 | @Override 21 | protected GameMode bestMatch(CommandContext context, String input) { 22 | if (StringUtils.isNumeric(input)) { 23 | int index = Integer.parseInt(input); 24 | GameMode[] enumValues = enumClass.getEnumConstants(); 25 | 26 | if (index >= 0 && index < enumValues.length) { 27 | return GameMode.getByValue(index); 28 | } 29 | } 30 | 31 | return super.bestMatch(context, input); 32 | } 33 | 34 | @Override 35 | public List stringSuggestions(CommandContext context, CommandInput input) { 36 | int totalGamemodes = GameMode.values().length; 37 | List suggestions = super.stringSuggestions(context, input); 38 | List indexedSuggestions = new ArrayList<>(totalGamemodes * 2); 39 | 40 | // Add gamemode names 41 | indexedSuggestions.addAll(suggestions); 42 | 43 | // Add index values 44 | for (int i = 0; i < totalGamemodes; i++) { 45 | indexedSuggestions.add(String.valueOf(i)); 46 | } 47 | 48 | return indexedSuggestions; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/database/DatabaseConfig.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.database; 2 | 3 | import org.bukkit.configuration.Configuration; 4 | 5 | public class DatabaseConfig { 6 | 7 | private boolean enabled; 8 | private String username; 9 | private String password; 10 | private String host; 11 | private String databaseName; 12 | private String timezone; 13 | private int maxConnections; 14 | private String sqliteFileName; 15 | 16 | public DatabaseConfig(Configuration config) { 17 | reload(config); 18 | } 19 | 20 | public void reload(Configuration config) { 21 | this.enabled = config.getBoolean("database.enabled", true); 22 | this.username = config.getString("database.username"); 23 | this.password = config.getString("database.password"); 24 | this.host = config.getString("database.host"); 25 | this.databaseName = config.getString("database.databaseName"); 26 | this.timezone = config.getString("database.timezone"); 27 | this.maxConnections = config.getInt("database.max-connections"); 28 | this.sqliteFileName = config.getString("database.sqlite-file"); 29 | } 30 | 31 | public boolean isEnabled() { 32 | return enabled; 33 | } 34 | 35 | public String getUsername() { 36 | return username; 37 | } 38 | 39 | public String getPassword() { 40 | return password; 41 | } 42 | 43 | public String getHost() { 44 | return host; 45 | } 46 | 47 | public String getDatabaseName() { 48 | return databaseName; 49 | } 50 | 51 | public String getTimezone() { 52 | return timezone; 53 | } 54 | 55 | public int getMaxDatabaseConnections() { 56 | return isEnabled() ? maxConnections : 1; 57 | } 58 | 59 | public String getSQLiteFileName() { 60 | return sqliteFileName; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/database/DatabaseConnection.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.database; 2 | 3 | import co.aikar.idb.BukkitDB; 4 | import co.aikar.idb.DatabaseOptions; 5 | import co.aikar.idb.DatabaseOptions.DatabaseOptionsBuilder; 6 | import co.aikar.idb.PooledDatabaseOptions; 7 | import co.aikar.idb.PooledDatabaseOptions.PooledDatabaseOptionsBuilder; 8 | import com.google.common.collect.Maps; 9 | import dev.pgm.community.Community; 10 | import java.util.Map; 11 | 12 | public class DatabaseConnection { 13 | 14 | private DatabaseConfig config; 15 | 16 | public DatabaseConnection(Community plugin) { 17 | this.config = new DatabaseConfig(plugin.getConfig()); 18 | 19 | Map extraOptions = Maps.newHashMap(); 20 | extraOptions.put("serverTimezone", config.getTimezone()); 21 | 22 | DatabaseOptionsBuilder builder = DatabaseOptions.builder() 23 | .poolName(plugin.getDescription().getName() + " DB") 24 | .logger(plugin.getLogger()); 25 | 26 | if (config.isEnabled()) { 27 | builder.mysql( 28 | config.getUsername(), config.getPassword(), config.getDatabaseName(), config.getHost()); 29 | } else { 30 | builder.sqlite(config.getSQLiteFileName()); 31 | builder.minAsyncThreads(1); 32 | builder.maxAsyncThreads(1); 33 | } 34 | 35 | PooledDatabaseOptionsBuilder poolBuilder = PooledDatabaseOptions.builder() 36 | .options(builder.build()) 37 | .maxConnections(config.getMaxDatabaseConnections()); 38 | 39 | // Apply extra MySQL options 40 | if (config.isEnabled()) { 41 | poolBuilder.dataSourceProperties(extraOptions); 42 | } 43 | 44 | // Setup the main global DB 45 | BukkitDB.createHikariDatabase(plugin, poolBuilder.build()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/database/Query.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.database; 2 | 3 | import static tc.oc.pgm.util.Assert.assertNotNull; 4 | 5 | public class Query { 6 | 7 | public static String createTable(String tableName, String fields) { 8 | assertNotNull(tableName); 9 | assertNotNull(fields); 10 | 11 | return String.format("CREATE TABLE IF NOT EXISTS %s %s", tableName, fields); 12 | } 13 | 14 | public static String countTable(String tableName) { 15 | assertNotNull(tableName); 16 | return String.format("SELECT count(*) from %s", tableName); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/database/Savable.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.database; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.CompletableFuture; 5 | 6 | public interface Savable { 7 | 8 | void save(T t); 9 | 10 | CompletableFuture> queryList(R target); 11 | 12 | CompletableFuture query(R target); 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/events/CommunityEvent.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.events; 2 | 3 | import org.bukkit.event.Event; 4 | import org.bukkit.event.HandlerList; 5 | 6 | /** The foundation for all Community Events */ 7 | public class CommunityEvent extends Event { 8 | 9 | private static final HandlerList handlers = new HandlerList(); 10 | 11 | @Override 12 | public HandlerList getHandlers() { 13 | return handlers; 14 | } 15 | 16 | public static HandlerList getHandlerList() { 17 | return handlers; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/events/PlayerHelpRequestEvent.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.events; 2 | 3 | import dev.pgm.community.assistance.PlayerHelpRequest; 4 | 5 | public class PlayerHelpRequestEvent extends CommunityEvent { 6 | 7 | private final PlayerHelpRequest request; 8 | 9 | public PlayerHelpRequestEvent(PlayerHelpRequest request) { 10 | this.request = request; 11 | } 12 | 13 | public PlayerHelpRequest getRequest() { 14 | return request; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/events/PlayerPunishmentEvent.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.events; 2 | 3 | import dev.pgm.community.moderation.punishments.Punishment; 4 | import dev.pgm.community.utils.CommandAudience; 5 | 6 | /** PlayerPunishmentEvent - Called when a punishment is issued to a player */ 7 | public class PlayerPunishmentEvent extends CommunityEvent { 8 | 9 | private final CommandAudience sender; 10 | private final Punishment punishment; 11 | private final boolean silent; 12 | 13 | public PlayerPunishmentEvent(CommandAudience audience, Punishment punishment, boolean silent) { 14 | this.sender = audience; 15 | this.punishment = punishment; 16 | this.silent = silent; 17 | } 18 | 19 | public CommandAudience getSender() { 20 | return sender; 21 | } 22 | 23 | public Punishment getPunishment() { 24 | return punishment; 25 | } 26 | 27 | public boolean isSilent() { 28 | return silent; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/events/PlayerReportEvent.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.events; 2 | 3 | import dev.pgm.community.assistance.Report; 4 | 5 | /** PlayerReportEvent - Called when a report is created */ 6 | public class PlayerReportEvent extends CommunityEvent { 7 | 8 | private final Report report; 9 | 10 | public PlayerReportEvent(Report report) { 11 | this.report = report; 12 | } 13 | 14 | public Report getReport() { 15 | return report; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/events/UserProfileLoadEvent.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.events; 2 | 3 | import dev.pgm.community.users.UserProfile; 4 | 5 | public class UserProfileLoadEvent extends CommunityEvent { 6 | 7 | private UserProfile profile; 8 | 9 | public UserProfileLoadEvent(UserProfile profile) { 10 | this.profile = profile; 11 | } 12 | 13 | public UserProfile getUser() { 14 | return profile; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/feature/Feature.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.feature; 2 | 3 | import dev.pgm.community.feature.config.FeatureConfig; 4 | import java.util.concurrent.CompletableFuture; 5 | 6 | /** A Feature is something can be enabled/disabled, may contain commands, and a config */ 7 | public interface Feature { 8 | 9 | boolean isEnabled(); 10 | 11 | void setEnabled(boolean on); 12 | 13 | void enable(); 14 | 15 | void disable(); 16 | 17 | FeatureConfig getConfig(); 18 | 19 | default CompletableFuture count() { 20 | return CompletableFuture.completedFuture(0); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/feature/FeatureBase.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.feature; 2 | 3 | import dev.pgm.community.Community; 4 | import dev.pgm.community.feature.config.FeatureConfig; 5 | import java.util.logging.Logger; 6 | import org.bukkit.event.HandlerList; 7 | import org.bukkit.event.Listener; 8 | 9 | /** A base implementation of a {@link Feature} - Can enable/disable listeners */ 10 | public abstract class FeatureBase implements Feature, Listener { 11 | 12 | protected final Logger logger; 13 | private final FeatureConfig config; 14 | private final String featureName; 15 | 16 | public FeatureBase(FeatureConfig config, Logger logger, String featureName) { 17 | this.config = config; 18 | this.logger = logger; 19 | this.featureName = featureName; 20 | } 21 | 22 | @Override 23 | public void enable() { 24 | Community.get().registerListener(this); 25 | logger.info(featureName + " has been enabled"); 26 | } 27 | 28 | @Override 29 | public void disable() { 30 | HandlerList.unregisterAll(this); 31 | logger.info(featureName + " has been disabled"); 32 | } 33 | 34 | @Override 35 | public boolean isEnabled() { 36 | return config.isEnabled(); 37 | } 38 | 39 | @Override 40 | public void setEnabled(boolean yes) { 41 | config.setEnabled(yes); 42 | } 43 | 44 | @Override 45 | public FeatureConfig getConfig() { 46 | return config; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/feature/SQLFeature.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.feature; 2 | 3 | import dev.pgm.community.database.Savable; 4 | 5 | public interface SQLFeature extends Savable { 6 | 7 | /** Create the SQL table for a data set */ 8 | void createTable(); 9 | } 10 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/feature/SQLFeatureBase.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.feature; 2 | 3 | import co.aikar.idb.DB; 4 | import dev.pgm.community.database.Query; 5 | import java.util.concurrent.CompletableFuture; 6 | 7 | /** Base implementation of {@link SQLFeature} * */ 8 | public abstract class SQLFeatureBase implements SQLFeature { 9 | 10 | private final String tableName; 11 | private final String fields; 12 | 13 | public SQLFeatureBase(String tableName, String fields) { 14 | this.tableName = tableName; 15 | this.fields = fields; 16 | createTable(); 17 | } 18 | 19 | @Override 20 | public void createTable() { 21 | DB.executeUpdateAsync(Query.createTable(tableName, fields)); 22 | } 23 | 24 | public CompletableFuture count() { 25 | return DB.getFirstColumnAsync(Query.countTable(tableName)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/feature/config/FeatureConfig.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.feature.config; 2 | 3 | import dev.pgm.community.assistance.feature.AssistanceFeature; 4 | import org.bukkit.configuration.Configuration; 5 | 6 | public interface FeatureConfig { 7 | 8 | /** Reloads config values with those from the file */ 9 | void reload(Configuration config); 10 | 11 | /** 12 | * The key associated with the feature e.g "reports" for {@link AssistanceFeature} 13 | * 14 | * @return the string key 15 | */ 16 | String getKey(); 17 | 18 | /** 19 | * Enables or disables the feature 20 | * 21 | * @param yes whether to enable or disable 22 | */ 23 | void setEnabled(boolean yes); 24 | 25 | /** 26 | * Gets whether the feature is enabled or disabled 27 | * 28 | * @return whether enabled 29 | */ 30 | boolean isEnabled(); 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/feature/config/FeatureConfigImpl.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.feature.config; 2 | 3 | import org.bukkit.configuration.Configuration; 4 | 5 | /** An implementation of {@link FeatureConfig} * */ 6 | public abstract class FeatureConfigImpl implements FeatureConfig { 7 | 8 | private final String key; 9 | 10 | private boolean enabled; 11 | 12 | public FeatureConfigImpl(String key, Configuration config) { 13 | this.key = key; 14 | reload(config); 15 | } 16 | 17 | @Override 18 | public String getKey() { 19 | return key; 20 | } 21 | 22 | @Override 23 | public boolean isEnabled() { 24 | return enabled; 25 | } 26 | 27 | @Override 28 | public void setEnabled(boolean yes) { 29 | this.enabled = yes; 30 | } 31 | 32 | @Override 33 | public void reload(Configuration config) { 34 | this.enabled = config.getBoolean(getEnabledKey(key)); 35 | } 36 | 37 | protected String getEnabledKey(String key) { 38 | return key + ".enabled"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/freeze/FreezeConfig.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.freeze; 2 | 3 | import dev.pgm.community.feature.config.FeatureConfigImpl; 4 | import org.bukkit.configuration.Configuration; 5 | 6 | public class FreezeConfig extends FeatureConfigImpl { 7 | 8 | private static final String KEY = "freeze"; 9 | 10 | private boolean pgmIntegration; 11 | private int itemSlot; 12 | 13 | public FreezeConfig(Configuration config) { 14 | super(KEY, config); 15 | } 16 | 17 | public boolean isIntegrationEnabled() { 18 | return pgmIntegration; 19 | } 20 | 21 | public int getItemSlot() { 22 | return itemSlot; 23 | } 24 | 25 | @Override 26 | public void reload(Configuration config) { 27 | super.reload(config); 28 | this.pgmIntegration = config.getBoolean(getKey() + ".pgm-integration"); 29 | this.itemSlot = config.getInt(getKey() + ".item-slot"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/friends/FriendRequestStatus.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.friends; 2 | 3 | // Status code returned when adding a friend 4 | public enum FriendRequestStatus { 5 | ACCEPTED_EXISTING, // The target had already sent a friend request, so request was auto accepted 6 | PENDING, // Target and sender have no prior requests 7 | EXISTING; // The sender has already sent a friend request 8 | } 9 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/friends/FriendshipConfig.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.friends; 2 | 3 | import dev.pgm.community.feature.config.FeatureConfigImpl; 4 | import org.bukkit.configuration.Configuration; 5 | 6 | public class FriendshipConfig extends FeatureConfigImpl { 7 | 8 | public static final String KEY = "friends"; 9 | 10 | private boolean pgmIntegration; 11 | 12 | public FriendshipConfig(Configuration config) { 13 | super(KEY, config); 14 | } 15 | 16 | public boolean isIntegrationEnabled() { 17 | return pgmIntegration; 18 | } 19 | 20 | @Override 21 | public void reload(Configuration config) { 22 | super.reload(config); 23 | this.pgmIntegration = config.getBoolean(getKey() + ".pgm-integration"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/friends/feature/PGMFriendIntegration.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.friends.feature; 2 | 3 | import com.google.common.collect.Maps; 4 | import com.google.common.collect.Sets; 5 | import dev.pgm.community.Community; 6 | import java.util.Map; 7 | import java.util.Set; 8 | import java.util.UUID; 9 | import org.bukkit.Bukkit; 10 | import org.bukkit.entity.Player; 11 | import tc.oc.pgm.api.event.NameDecorationChangeEvent; 12 | import tc.oc.pgm.api.integration.FriendIntegration; 13 | import tc.oc.pgm.api.integration.Integration; 14 | 15 | public class PGMFriendIntegration implements FriendIntegration { 16 | 17 | private Map> friends; 18 | 19 | public PGMFriendIntegration() { 20 | this.friends = Maps.newHashMap(); 21 | enable(); 22 | } 23 | 24 | public void enable() { 25 | Integration.setFriendIntegration(this); 26 | } 27 | 28 | public void setFriends(UUID playerId, Set friends) { 29 | this.friends.put(playerId, friends); 30 | } 31 | 32 | @Override 33 | public boolean isFriend(Player a, Player b) { 34 | return isFriend(a.getUniqueId(), b.getUniqueId()); 35 | } 36 | 37 | public boolean isFriend(UUID playerId, UUID friendId) { 38 | return friends.getOrDefault(playerId, Sets.newHashSet()).contains(friendId); 39 | } 40 | 41 | public void callUpdateEvents(UUID playerId, Set friendIds) { 42 | callUpdateEvent(playerId); 43 | friendIds.forEach(this::callUpdateEvent); 44 | } 45 | 46 | private void callUpdateEvent(UUID playerId) { 47 | Player online = Bukkit.getPlayer(playerId); 48 | if (online != null) { 49 | Community.get() 50 | .getServer() 51 | .getPluginManager() 52 | .callEvent(new NameDecorationChangeEvent(playerId)); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/friends/services/FriendshipQuery.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.friends.services; 2 | 3 | public interface FriendshipQuery { 4 | 5 | static final String TABLE_NAME = "friendships"; 6 | static final String TABLE_FIELDS = 7 | "(id VARCHAR(36) PRIMARY KEY, " 8 | + "requester VARCHAR(36), " 9 | + "requested VARCHAR(36), " 10 | + "status VARCHAR(8), " 11 | + "requestDate LONG, " 12 | + "updateDate LONG)"; 13 | 14 | static final String INSERT_FRIENDSHIP_QUERY = 15 | "INSERT INTO " 16 | + TABLE_NAME 17 | + "(id, requester, requested, status, requestDate, updateDate) VALUES (?, ?, ?, ?, ?, ?)"; 18 | 19 | static final String SELECT_FRIENDSHIPS_QUERY = 20 | "SELECT * from " + TABLE_NAME + " where (requester = ? OR requested = ?)"; 21 | 22 | static final String UPDATE_FRIENDSHIP_QUERY = 23 | "UPDATE " + TABLE_NAME + " SET status = ?, updateDate = ? WHERE id = ? "; 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/history/MatchHistoryCommand.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.history; 2 | 3 | import static tc.oc.pgm.util.text.TextException.exception; 4 | 5 | import dev.pgm.community.Community; 6 | import dev.pgm.community.CommunityPermissions; 7 | import dev.pgm.community.utils.CommandAudience; 8 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Argument; 9 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Command; 10 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.CommandDescription; 11 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Default; 12 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Flag; 13 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Permission; 14 | 15 | @Command("matchhistory|mh") 16 | public class MatchHistoryCommand { 17 | 18 | private final MatchHistoryFeature manager; 19 | 20 | public MatchHistoryCommand() { 21 | this.manager = Community.get().getFeatures().getHistory(); 22 | } 23 | 24 | @Command("[page]") 25 | @CommandDescription("Display match history") 26 | @Permission(CommunityPermissions.MATCH_HISTORY) 27 | public void sendHistory( 28 | CommandAudience sender, 29 | @Argument("page") @Default("1") int page, 30 | @Flag(value = "verbose", aliases = "v") boolean verbose) { 31 | checkEnabled(); 32 | manager.sendHistory(sender, page, verbose); 33 | } 34 | 35 | private void checkEnabled() { 36 | if (!manager.isEnabled()) { 37 | throw exception("Match History is not enabled"); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/history/MatchHistoryConfig.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.history; 2 | 3 | import dev.pgm.community.feature.config.FeatureConfigImpl; 4 | import org.bukkit.configuration.Configuration; 5 | 6 | public class MatchHistoryConfig extends FeatureConfigImpl { 7 | 8 | private static final String KEY = "history"; 9 | 10 | public MatchHistoryConfig(Configuration config) { 11 | super(KEY, config); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/info/InfoCommandConfig.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.info; 2 | 3 | import dev.pgm.community.feature.config.FeatureConfigImpl; 4 | import java.util.Set; 5 | import java.util.stream.Collectors; 6 | import org.bukkit.configuration.Configuration; 7 | 8 | /** InfoCommandConfig - Configuration related to custom info commands * */ 9 | public class InfoCommandConfig extends FeatureConfigImpl { 10 | 11 | private static final String KEY = "commands"; 12 | 13 | private Set commands; 14 | 15 | public InfoCommandConfig(Configuration config) { 16 | super(KEY, config); 17 | } 18 | 19 | public Set getInfoCommands() { 20 | return commands; 21 | } 22 | 23 | @Override 24 | public void reload(Configuration config) { 25 | super.reload(config); 26 | this.commands = 27 | config.getConfigurationSection(KEY).getKeys(false).stream() 28 | .map(key -> InfoCommandData.of(config.getConfigurationSection(KEY + "." + key))) 29 | .collect(Collectors.toSet()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/info/InfoCommandData.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.info; 2 | 3 | import static net.kyori.adventure.text.Component.text; 4 | 5 | import dev.pgm.community.utils.MessageUtils; 6 | import java.util.List; 7 | import java.util.stream.Collectors; 8 | import net.kyori.adventure.text.Component; 9 | import org.bukkit.command.CommandSender; 10 | import org.bukkit.configuration.ConfigurationSection; 11 | import tc.oc.pgm.util.Audience; 12 | 13 | public class InfoCommandData { 14 | 15 | private static final String LINES_KEY = "lines"; 16 | private static final String PERMISSION_KEY = "permission"; 17 | 18 | private String name; 19 | private List lines; 20 | private String permission; 21 | 22 | public InfoCommandData(String name, List lines, String permission) { 23 | this.name = name; 24 | this.lines = lines; 25 | this.permission = permission; 26 | } 27 | 28 | public static InfoCommandData of(ConfigurationSection section) { 29 | return new InfoCommandData( 30 | section.getName(), 31 | section.getStringList(LINES_KEY).stream() 32 | .map(MessageUtils::parseComponentWithURL) 33 | .collect(Collectors.toList()), 34 | section.getString(PERMISSION_KEY)); 35 | } 36 | 37 | public String getName() { 38 | return name; 39 | } 40 | 41 | public List getLines() { 42 | return lines; 43 | } 44 | 45 | public String getPermission() { 46 | return permission; 47 | } 48 | 49 | public void sendCommand(CommandSender sender) { 50 | Audience viewer = Audience.get(sender); 51 | 52 | if (getPermission() != null && !getPermission().isEmpty()) { 53 | if (!sender.hasPermission(getPermission())) { 54 | viewer.sendWarning(text("You do not have permission for this command")); 55 | return; // TODO: Translate 56 | } 57 | } 58 | 59 | getLines().forEach(viewer::sendMessage); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/info/InfoCommandsFeature.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.info; 2 | 3 | import dev.pgm.community.feature.FeatureBase; 4 | import java.util.concurrent.CompletableFuture; 5 | import java.util.logging.Logger; 6 | import org.bukkit.configuration.Configuration; 7 | import org.bukkit.event.EventHandler; 8 | import org.bukkit.event.player.PlayerCommandPreprocessEvent; 9 | 10 | /** InfoCommandsFeature - Allows for commands via the config to be defined and used * */ 11 | public class InfoCommandsFeature extends FeatureBase { 12 | 13 | public InfoCommandsFeature(Configuration config, Logger logger) { 14 | super(new InfoCommandConfig(config), logger, "Info Commands"); 15 | enable(); 16 | } 17 | 18 | public InfoCommandConfig getInfoConfig() { 19 | return (InfoCommandConfig) getConfig(); 20 | } 21 | 22 | @EventHandler 23 | public void onPlayerCommandProcess(PlayerCommandPreprocessEvent event) { 24 | // We dynamically check for defined commands, and send the related feedback 25 | getInfoConfig().getInfoCommands().stream() 26 | .filter(c -> event.getMessage().toLowerCase().startsWith("/" + c.getName().toLowerCase())) 27 | .findAny() 28 | .ifPresent( 29 | command -> { 30 | command.sendCommand(event.getPlayer()); 31 | event.setCancelled(true); 32 | }); 33 | } 34 | 35 | @Override 36 | public CompletableFuture count() { 37 | return CompletableFuture.completedFuture(getInfoConfig().getInfoCommands().size()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/menu/CommunityInventoryProvider.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.menu; 2 | 3 | import fr.minuskube.inv.ClickableItem; 4 | import fr.minuskube.inv.content.InventoryContents; 5 | import fr.minuskube.inv.content.InventoryProvider; 6 | import java.util.List; 7 | import java.util.function.Consumer; 8 | import org.bukkit.entity.Player; 9 | import org.bukkit.event.inventory.InventoryClickEvent; 10 | import org.bukkit.inventory.ItemStack; 11 | 12 | public abstract class CommunityInventoryProvider implements InventoryProvider { 13 | 14 | private List items; 15 | 16 | public CommunityInventoryProvider(List items) { 17 | this.items = items; 18 | } 19 | 20 | @Override 21 | public void init(Player player, InventoryContents contents) { 22 | int slot = getStartingSlot(items.size()); 23 | if (items.isEmpty()) { 24 | contents.set(0, 4, ClickableItem.empty(getNoResultsItem())); 25 | } 26 | for (T item : items) { 27 | contents.set(0, slot, item.getMenuItem(getClickAction(item, player, contents))); 28 | slot += 2; 29 | } 30 | } 31 | 32 | @Override 33 | public void update(Player player, InventoryContents contents) {} 34 | 35 | public abstract Consumer getClickAction( 36 | T item, Player viewer, InventoryContents contents); 37 | 38 | protected abstract ItemStack getNoResultsItem(); 39 | 40 | protected int getStartingSlot(int categorySize) { 41 | switch (categorySize) { 42 | case 3: 43 | return 2; 44 | case 4: 45 | return 1; 46 | default: 47 | return 0; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/menu/MenuItem.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.menu; 2 | 3 | import static tc.oc.pgm.util.bukkit.BukkitUtils.colorize; 4 | 5 | import fr.minuskube.inv.ClickableItem; 6 | import java.util.List; 7 | import java.util.function.Consumer; 8 | import org.bukkit.Material; 9 | import org.bukkit.event.inventory.InventoryClickEvent; 10 | import org.bukkit.inventory.ItemFlag; 11 | import org.bukkit.inventory.ItemStack; 12 | import tc.oc.pgm.util.inventory.ItemBuilder; 13 | 14 | public abstract class MenuItem { 15 | 16 | private final String name; 17 | private final Material icon; 18 | private final String[] description; 19 | 20 | public MenuItem(Material icon, String name, List description) { 21 | this(icon, name, description.toArray(new String[description.size()])); 22 | } 23 | 24 | public MenuItem(Material icon, String name, String... description) { 25 | this.name = colorize(name); 26 | this.description = colorizeList(description); 27 | this.icon = icon; 28 | } 29 | 30 | public String getName() { 31 | return name; 32 | } 33 | 34 | public ClickableItem getMenuItem(Consumer event) { 35 | return ClickableItem.of(getItemStack(), event); 36 | } 37 | 38 | public ItemStack getItemStack() { 39 | return new ItemBuilder() 40 | .material(icon) 41 | .name(name) 42 | .lore(description) 43 | .flags(ItemFlag.values()) 44 | .build(); 45 | } 46 | 47 | private String[] colorizeList(String... desc) { 48 | String[] colorArray = new String[desc.length]; 49 | for (int i = 0; i < desc.length; i++) { 50 | colorArray[i] = colorize(desc[i]); 51 | } 52 | return colorArray; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/menu/PageableInventory.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.menu; 2 | 3 | import static tc.oc.pgm.util.bukkit.BukkitUtils.colorize; 4 | 5 | import fr.minuskube.inv.ClickableItem; 6 | import org.bukkit.Material; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.inventory.ItemFlag; 9 | import org.bukkit.inventory.ItemStack; 10 | import org.bukkit.inventory.meta.ItemMeta; 11 | 12 | public interface PageableInventory { 13 | 14 | default ClickableItem getNextPageItem(Player player, int nextPage) { 15 | return getPageItem(player, nextPage, getPageIcon("&e&lNext Page", nextPage + 1)); 16 | } 17 | 18 | default ClickableItem getPrevPageItem(Player player, int prevPage) { 19 | return getPageItem(player, prevPage, getPageIcon("&e&lPrevious Page", prevPage + 1)); 20 | } 21 | 22 | ClickableItem getPageItem(Player player, int page, ItemStack icon); 23 | 24 | default ItemStack getPageIcon(String text, int page) { 25 | return getNamedItem(text, Material.ARROW, page); 26 | } 27 | 28 | default ItemStack getNamedItem(String text, Material material, int amount) { 29 | ItemStack stack = new ItemStack(material, amount); 30 | ItemMeta meta = stack.getItemMeta(); 31 | meta.setDisplayName(colorize(text)); 32 | meta.addItemFlags(ItemFlag.values()); 33 | stack.setItemMeta(meta); 34 | return stack; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/menu/StaticMenuItem.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.menu; 2 | 3 | import java.util.List; 4 | import org.bukkit.Material; 5 | 6 | public class StaticMenuItem extends MenuItem { 7 | 8 | public StaticMenuItem(Material icon, String name, List description) { 9 | super(icon, name, description); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mobs/MobConfig.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mobs; 2 | 3 | import dev.pgm.community.feature.config.FeatureConfigImpl; 4 | import org.bukkit.configuration.Configuration; 5 | 6 | public class MobConfig extends FeatureConfigImpl { 7 | 8 | private static final String KEY = "mobs"; 9 | 10 | public MobConfig(Configuration config) { 11 | super(KEY, config); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/commands/ToolCommand.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.commands; 2 | 3 | import static net.kyori.adventure.text.Component.text; 4 | 5 | import dev.pgm.community.Community; 6 | import dev.pgm.community.CommunityCommand; 7 | import dev.pgm.community.CommunityPermissions; 8 | import dev.pgm.community.moderation.tools.ModerationTools; 9 | import dev.pgm.community.utils.CommandAudience; 10 | import dev.pgm.community.utils.PGMUtils; 11 | import org.bukkit.entity.Player; 12 | import tc.oc.pgm.api.match.Match; 13 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Argument; 14 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Command; 15 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.CommandDescription; 16 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Permission; 17 | 18 | public class ToolCommand extends CommunityCommand { 19 | 20 | private final ModerationTools tools; 21 | 22 | public ToolCommand() { 23 | this.tools = Community.get().getFeatures().getModeration().getTools(); 24 | } 25 | 26 | @Command("tptarget|tptg|tg ") 27 | @CommandDescription("Target a player for the player hook tool") 28 | @Permission(CommunityPermissions.STAFF) 29 | public void targetCommand( 30 | CommandAudience sender, Player player, @Argument("target") Player target) { 31 | if (isDisabled(sender)) return; 32 | tools.getTeleportHook().targetPlayer(player, target); 33 | } 34 | 35 | @Command("modtools|mtools") 36 | @CommandDescription("Give moderator tools to observer") 37 | @Permission(CommunityPermissions.STAFF) 38 | public void modTools(CommandAudience sender, Player player) { 39 | if (isDisabled(sender)) return; 40 | 41 | Match match = PGMUtils.getMatch(); 42 | if (match != null 43 | && match.getPlayer(player) != null 44 | && match.getPlayer(player).isObserving() 45 | && tools != null) { 46 | tools.giveTools(player); 47 | } 48 | } 49 | 50 | private boolean isDisabled(CommandAudience sender) { 51 | if (tools == null) { 52 | sender.sendWarning(text("Moderation Tools are not enabled!")); 53 | return true; 54 | } 55 | 56 | return false; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/commands/WarnCommand.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.commands; 2 | 3 | import dev.pgm.community.Community; 4 | import dev.pgm.community.CommunityCommand; 5 | import dev.pgm.community.CommunityPermissions; 6 | import dev.pgm.community.commands.player.TargetPlayer; 7 | import dev.pgm.community.moderation.feature.ModerationFeature; 8 | import dev.pgm.community.moderation.punishments.PunishmentType; 9 | import dev.pgm.community.users.feature.UsersFeature; 10 | import dev.pgm.community.utils.CommandAudience; 11 | import tc.oc.pgm.lib.org.incendo.cloud.annotation.specifier.Greedy; 12 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Argument; 13 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Command; 14 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.CommandDescription; 15 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Permission; 16 | 17 | public class WarnCommand extends CommunityCommand { 18 | 19 | private final ModerationFeature moderation; 20 | private final UsersFeature usernames; 21 | 22 | public WarnCommand() { 23 | this.moderation = Community.get().getFeatures().getModeration(); 24 | this.usernames = Community.get().getFeatures().getUsers(); 25 | } 26 | 27 | @Command("warn|w ") 28 | @CommandDescription("Warn a player for bad behavior") 29 | @Permission(CommunityPermissions.WARN) 30 | public void warn( 31 | CommandAudience audience, 32 | @Argument("target") TargetPlayer target, 33 | @Argument("reason") @Greedy String reason) { 34 | getTarget(target.getIdentifier(), usernames) 35 | .thenAccept( 36 | id -> { 37 | if (id.isPresent()) { 38 | moderation.punish( 39 | PunishmentType.WARN, 40 | id.get(), 41 | audience, 42 | reason, 43 | null, 44 | false, 45 | isDisguised(audience)); 46 | } else { 47 | audience.sendWarning(formatNotFoundComponent(target.getIdentifier())); 48 | } 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/punishments/NetworkPunishment.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.punishments; 2 | 3 | public class NetworkPunishment { 4 | 5 | private String serverId; 6 | private Punishment punishment; 7 | 8 | public NetworkPunishment(Punishment punishment, String serverId) { 9 | this.punishment = punishment; 10 | this.serverId = serverId; 11 | } 12 | 13 | public String getServer() { 14 | return serverId; 15 | } 16 | 17 | public Punishment getPunishment() { 18 | return punishment; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/punishments/types/BanPunishment.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.punishments.types; 2 | 3 | import dev.pgm.community.moderation.punishments.Punishment; 4 | import dev.pgm.community.moderation.punishments.PunishmentType; 5 | import java.util.UUID; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | public class BanPunishment extends Punishment { 9 | 10 | public BanPunishment( 11 | UUID punishmentId, 12 | UUID targetId, 13 | @Nullable UUID issuerId, 14 | String reason, 15 | long timeIssued, 16 | boolean active, 17 | long lastUpdated, 18 | @Nullable UUID lastUpdatedBy, 19 | String service) { 20 | super( 21 | PunishmentType.BAN, 22 | punishmentId, 23 | targetId, 24 | issuerId, 25 | reason, 26 | null, 27 | timeIssued, 28 | active, 29 | lastUpdated, 30 | lastUpdatedBy, 31 | service); 32 | } 33 | 34 | @Override 35 | public boolean punish(boolean silent) { 36 | return kick(silent); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/punishments/types/ExpirablePunishment.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.punishments.types; 2 | 3 | import dev.pgm.community.moderation.punishments.Punishment; 4 | import dev.pgm.community.moderation.punishments.PunishmentType; 5 | import java.time.Duration; 6 | import java.time.Instant; 7 | import java.util.UUID; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | /** A punishment that can expire * */ 11 | public abstract class ExpirablePunishment extends Punishment { 12 | 13 | public ExpirablePunishment( 14 | PunishmentType type, 15 | UUID id, 16 | UUID targetId, 17 | @Nullable UUID issuerId, 18 | String reason, 19 | long timeIssued, 20 | Duration length, 21 | boolean active, 22 | long lastUpdated, 23 | @Nullable UUID lastUpdatedBy, 24 | String service) { 25 | super( 26 | type, 27 | id, 28 | targetId, 29 | issuerId, 30 | reason, 31 | length, 32 | timeIssued, 33 | active, 34 | lastUpdated, 35 | lastUpdatedBy, 36 | service); 37 | } 38 | 39 | @Override 40 | public boolean isActive() { 41 | Instant expires = this.getTimeIssued().plus(this.getDuration()); 42 | return super.isActive() 43 | ? Instant.now().isBefore(expires) 44 | : false; // If expired return false, otherwise return true until expires 45 | } 46 | 47 | public Instant getExpireTime() { 48 | return getTimeIssued().plus(getDuration()); 49 | } 50 | 51 | public static @Nullable Duration getDuration(Punishment punishment) { 52 | return punishment instanceof ExpirablePunishment 53 | ? ExpirablePunishment.class.cast(punishment).getDuration() 54 | : null; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/punishments/types/KickPunishment.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.punishments.types; 2 | 3 | import dev.pgm.community.moderation.punishments.Punishment; 4 | import dev.pgm.community.moderation.punishments.PunishmentType; 5 | import java.util.UUID; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | public class KickPunishment extends Punishment { 9 | 10 | public KickPunishment( 11 | UUID id, 12 | UUID targetId, 13 | @Nullable UUID issuerId, 14 | String reason, 15 | long timeIssued, 16 | boolean active, 17 | long lastUpdated, 18 | @Nullable UUID lastUpdatedBy, 19 | String service) { 20 | super( 21 | PunishmentType.KICK, 22 | id, 23 | targetId, 24 | issuerId, 25 | reason, 26 | null, 27 | timeIssued, 28 | active, 29 | lastUpdated, 30 | lastUpdatedBy, 31 | service); 32 | } 33 | 34 | @Override 35 | public boolean punish(boolean silent) { 36 | return kick(silent); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/punishments/types/TempBanPunishment.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.punishments.types; 2 | 3 | import dev.pgm.community.moderation.punishments.PunishmentType; 4 | import java.time.Duration; 5 | import java.util.UUID; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | public class TempBanPunishment extends ExpirablePunishment { 9 | 10 | public TempBanPunishment( 11 | UUID id, 12 | UUID targetId, 13 | @Nullable UUID issuerId, 14 | String reason, 15 | long timeIssued, 16 | Duration length, 17 | boolean active, 18 | long lastUpdated, 19 | @Nullable UUID lastUpdatedBy, 20 | String service) { 21 | super( 22 | PunishmentType.TEMP_BAN, 23 | id, 24 | targetId, 25 | issuerId, 26 | reason, 27 | timeIssued, 28 | length, 29 | active, 30 | lastUpdated, 31 | lastUpdatedBy, 32 | service); 33 | } 34 | 35 | @Override 36 | public boolean punish(boolean silent) { 37 | return kick(silent); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/punishments/types/UsernameBanPunishment.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.punishments.types; 2 | 3 | import dev.pgm.community.moderation.punishments.Punishment; 4 | import dev.pgm.community.moderation.punishments.PunishmentType; 5 | import java.util.UUID; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | public class UsernameBanPunishment extends Punishment { 9 | 10 | public UsernameBanPunishment( 11 | UUID punishmentId, 12 | UUID targetId, 13 | @Nullable UUID issuerId, 14 | String reason, 15 | long timeIssued, 16 | boolean active, 17 | long lastUpdated, 18 | @Nullable UUID lastUpdatedBy, 19 | String service) { 20 | super( 21 | PunishmentType.NAME_BAN, 22 | punishmentId, 23 | targetId, 24 | issuerId, 25 | reason, 26 | null, 27 | timeIssued, 28 | active, 29 | lastUpdated, 30 | lastUpdatedBy, 31 | service); 32 | } 33 | 34 | @Override 35 | public boolean punish(boolean silent) { 36 | return kick(silent); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/punishments/types/WarnPunishment.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.punishments.types; 2 | 3 | import dev.pgm.community.moderation.punishments.Punishment; 4 | import dev.pgm.community.moderation.punishments.PunishmentType; 5 | import java.util.Optional; 6 | import java.util.UUID; 7 | import org.bukkit.entity.Player; 8 | import org.jetbrains.annotations.Nullable; 9 | import tc.oc.pgm.util.Audience; 10 | 11 | public class WarnPunishment extends Punishment { 12 | 13 | public WarnPunishment( 14 | UUID id, 15 | UUID targetId, 16 | @Nullable UUID issuerId, 17 | String reason, 18 | long timeIssued, 19 | boolean active, 20 | long lastUpdated, 21 | @Nullable UUID lastUpdatedBy, 22 | String service) { 23 | super( 24 | PunishmentType.WARN, 25 | id, 26 | targetId, 27 | issuerId, 28 | reason, 29 | null, 30 | timeIssued, 31 | active, 32 | lastUpdated, 33 | lastUpdatedBy, 34 | service); 35 | } 36 | 37 | @Override 38 | public boolean punish(boolean silent) { 39 | Optional target = getTargetPlayer(); 40 | target.ifPresent(player -> sendWarning(Audience.get(player), getReason())); 41 | return target.isPresent(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/services/ModerationQuery.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.services; 2 | 3 | public interface ModerationQuery { 4 | 5 | static final String TABLE_NAME = "punishments"; 6 | static final String TABLE_FIELDS = 7 | "(id VARCHAR(36) PRIMARY KEY, punished VARCHAR(36), issuer VARCHAR(36), reason VARCHAR(255), type VARCHAR(8), time LONG, expires LONG, active BOOL, last_updated LONG, updated_by VARCHAR(36), service VARCHAR(255))"; 8 | 9 | static final String INSERT_PUNISHMENT_QUERY = 10 | "INSERT INTO " 11 | + TABLE_NAME 12 | + "(id, punished, issuer, reason, type, time, expires, active, last_updated, updated_by, service) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; 13 | 14 | static final String SELECT_PUNISHMENTS_QUERY = 15 | "SELECT * from " + TABLE_NAME + " where punished = ?"; 16 | 17 | static final String SINGLE_PARDON_TYPE = "AND type = ?"; 18 | static final String MULTI_PARDON_TYPE = "AND (type = ? OR type = ? OR type = ?)"; 19 | static final String PARDON_QUERY = 20 | "UPDATE " 21 | + TABLE_NAME 22 | + " SET active = ?, last_updated = ?, updated_by = ? WHERE active = ? AND punished = ? "; 23 | static final String DEACTIVATE_QUERY = 24 | "UPDATE " + TABLE_NAME + " SET active = ? WHERE active = ? AND punished = ? "; 25 | 26 | static final String SELECT_RECENT_QUERY = 27 | "SELECT * from " + TABLE_NAME + " WHERE time > ? LIMIT ?"; 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/tools/ModerationTools.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.tools; 2 | 3 | import dev.pgm.community.moderation.ModerationConfig; 4 | import dev.pgm.community.moderation.tools.types.LookupSign; 5 | import dev.pgm.community.moderation.tools.types.ModerationMenuTool; 6 | import dev.pgm.community.moderation.tools.types.TeleportHook; 7 | import org.bukkit.entity.Player; 8 | import tc.oc.pgm.api.player.event.ObserverInteractEvent; 9 | 10 | public class ModerationTools { 11 | 12 | private ModerationMenuTool menu; 13 | private TeleportHook tpHook; 14 | private LookupSign sign; 15 | 16 | public ModerationTools(ModerationConfig config) { 17 | // TODO: allow reloads to enable/disable tools 18 | this.menu = new ModerationMenuTool(config.getModMenuSlot(), config.isModMenuEnabled()); 19 | this.tpHook = new TeleportHook(config.getPlayerHookSlot(), config.isPlayerHookEnabled()); 20 | this.sign = new LookupSign(config.getLookupSignSlot(), config.isLookupSignEnabled()); 21 | } 22 | 23 | public ModerationMenuTool getMenu() { 24 | return menu; 25 | } 26 | 27 | public TeleportHook getTeleportHook() { 28 | return tpHook; 29 | } 30 | 31 | public LookupSign getLookupSign() { 32 | return sign; 33 | } 34 | 35 | public void onInteract(ObserverInteractEvent event) { 36 | menu.onInteract(event); 37 | tpHook.onInteract(event); 38 | sign.onInteract(event); 39 | } 40 | 41 | public void giveTools(Player player) { 42 | getMenu().give(player); 43 | getTeleportHook().give(player); 44 | getLookupSign().give(player); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/tools/Tool.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.tools; 2 | 3 | import java.util.List; 4 | import org.bukkit.Material; 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.inventory.ItemStack; 7 | import tc.oc.pgm.api.player.event.ObserverInteractEvent; 8 | 9 | public interface Tool { 10 | 11 | void onInteract(ObserverInteractEvent event); 12 | 13 | void give(Player player); 14 | 15 | String getName(); 16 | 17 | List getLore(); 18 | 19 | Material getMaterial(); 20 | 21 | ItemStack getItem(); 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/tools/ToolBase.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.tools; 2 | 3 | import static dev.pgm.community.utils.MessageUtils.colorizeList; 4 | import static tc.oc.pgm.util.bukkit.BukkitUtils.colorize; 5 | 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.event.inventory.ClickType; 8 | import org.bukkit.inventory.ItemFlag; 9 | import org.bukkit.inventory.ItemStack; 10 | import tc.oc.pgm.api.player.event.ObserverInteractEvent; 11 | import tc.oc.pgm.util.inventory.ItemBuilder; 12 | 13 | public abstract class ToolBase implements Tool { 14 | 15 | private int slot; 16 | private boolean enabled; 17 | 18 | public ToolBase(int slot, boolean enabled) { 19 | this.slot = slot; 20 | this.enabled = enabled; 21 | } 22 | 23 | public abstract void onLeftClick(ObserverInteractEvent event); 24 | 25 | public abstract void onRightClick(ObserverInteractEvent event); 26 | 27 | @Override 28 | public void onInteract(ObserverInteractEvent event) { 29 | if (!enabled) return; 30 | if (event.getClickedItem() != null) { 31 | ItemStack clickedItem = event.getClickedItem(); 32 | if (clickedItem.isSimilar(getItem())) { 33 | if (event.getClickType() == ClickType.RIGHT) { 34 | onRightClick(event); 35 | } else { 36 | onLeftClick(event); 37 | } 38 | event.setCancelled(true); 39 | } 40 | } 41 | } 42 | 43 | @Override 44 | public void give(Player player) { 45 | if (!enabled) return; 46 | player.getInventory().setItem(slot, getItem()); 47 | } 48 | 49 | @Override 50 | public ItemStack getItem() { 51 | return new ItemBuilder() 52 | .material(getMaterial()) 53 | .name(colorize(getName())) 54 | .lore(colorizeList(getLore()).toArray(new String[getLore().size()])) 55 | .flags(ItemFlag.values()) 56 | .build(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/tools/buttons/ToolButton.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.tools.buttons; 2 | 3 | import fr.minuskube.inv.ClickableItem; 4 | import java.util.List; 5 | import java.util.function.Consumer; 6 | import org.bukkit.Material; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.event.inventory.InventoryClickEvent; 9 | import org.bukkit.inventory.ItemStack; 10 | 11 | public interface ToolButton { 12 | 13 | Player getViewer(); 14 | 15 | Material getMaterial(); 16 | 17 | int getAmount(); 18 | 19 | String getName(); 20 | 21 | List getLore(); 22 | 23 | ItemStack getIcon(); 24 | 25 | Consumer getClickEvent(); 26 | 27 | default ClickableItem getItem() { 28 | return ClickableItem.of(getIcon(), getClickEvent()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/tools/buttons/ToolButtonBase.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.tools.buttons; 2 | 3 | import static tc.oc.pgm.util.bukkit.BukkitUtils.colorize; 4 | 5 | import java.util.List; 6 | import org.bukkit.Material; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.inventory.ItemFlag; 9 | import org.bukkit.inventory.ItemStack; 10 | import org.bukkit.inventory.meta.ItemMeta; 11 | 12 | public abstract class ToolButtonBase implements ToolButton { 13 | 14 | private Player viewer; 15 | 16 | private String name; 17 | private List lore; 18 | private Material material; 19 | private int amount; 20 | 21 | public ToolButtonBase( 22 | Player viewer, String name, List lore, Material material, int amount) { 23 | this.viewer = viewer; 24 | this.name = name; 25 | this.lore = lore; 26 | this.material = material; 27 | this.amount = amount; 28 | } 29 | 30 | @Override 31 | public Player getViewer() { 32 | return viewer; 33 | } 34 | 35 | @Override 36 | public String getName() { 37 | return name; 38 | } 39 | 40 | @Override 41 | public List getLore() { 42 | return lore; 43 | } 44 | 45 | @Override 46 | public Material getMaterial() { 47 | return material; 48 | } 49 | 50 | @Override 51 | public int getAmount() { 52 | return amount; 53 | } 54 | 55 | @Override 56 | public ItemStack getIcon() { 57 | return getItem(getName(), getMaterial(), getLore(), getAmount()); 58 | } 59 | 60 | protected ItemStack getItem(String text, Material material, List lore, int amount) { 61 | ItemStack stack = new ItemStack(material, amount); 62 | ItemMeta meta = stack.getItemMeta(); 63 | meta.setDisplayName(colorize(text)); 64 | meta.setLore(lore); 65 | meta.addItemFlags(ItemFlag.values()); 66 | stack.setItemMeta(meta); 67 | return stack; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/tools/buttons/TranslatableToolButton.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.tools.buttons; 2 | 3 | import static net.kyori.adventure.text.Component.translatable; 4 | 5 | import com.google.common.collect.Lists; 6 | import java.util.List; 7 | import net.kyori.adventure.text.Component; 8 | import net.kyori.adventure.text.format.NamedTextColor; 9 | import net.kyori.adventure.text.format.TextDecoration; 10 | import org.bukkit.Material; 11 | import org.bukkit.entity.Player; 12 | import tc.oc.pgm.util.text.TextTranslations; 13 | 14 | public abstract class TranslatableToolButton extends ToolButtonBase { 15 | 16 | private String nameKey; 17 | private String loreKey; 18 | private NamedTextColor nameColor; 19 | 20 | public TranslatableToolButton( 21 | Player viewer, 22 | String nameKey, 23 | NamedTextColor color, 24 | String loreKey, 25 | Material material, 26 | int amount) { 27 | super(viewer, "", Lists.newArrayList(), material, amount); 28 | this.nameKey = nameKey; 29 | this.loreKey = loreKey; 30 | this.nameColor = color; 31 | } 32 | 33 | public NamedTextColor getColor() { 34 | return nameColor; 35 | } 36 | 37 | public Component getNameComponent() { 38 | return translatable(nameKey, getColor(), TextDecoration.BOLD); 39 | } 40 | 41 | public Component getLoreComponent() { 42 | return translatable(loreKey, NamedTextColor.GRAY); 43 | } 44 | 45 | @Override 46 | public String getName() { 47 | return TextTranslations.translateLegacy(getNameComponent(), getViewer()); 48 | } 49 | 50 | @Override 51 | public List getLore() { 52 | return Lists.newArrayList(TextTranslations.translateLegacy(getLoreComponent(), getViewer())); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/tools/buttons/types/NightVisionButton.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.tools.buttons.types; 2 | 3 | import static net.kyori.adventure.text.Component.translatable; 4 | 5 | import dev.pgm.community.moderation.tools.buttons.TranslatableToolButton; 6 | import java.util.function.Consumer; 7 | import net.kyori.adventure.text.Component; 8 | import net.kyori.adventure.text.format.NamedTextColor; 9 | import org.bukkit.Material; 10 | import org.bukkit.entity.Player; 11 | import org.bukkit.event.inventory.InventoryClickEvent; 12 | import org.bukkit.potion.PotionEffect; 13 | import org.bukkit.potion.PotionEffectType; 14 | 15 | public class NightVisionButton extends TranslatableToolButton { 16 | 17 | private static final String NAME_KEY = "setting.nightvision"; 18 | private static final String LORE_KEY = NAME_KEY + ".lore"; 19 | private static final Material MATERIAL = Material.POTION; 20 | private static final NamedTextColor COLOR = NamedTextColor.DARK_PURPLE; 21 | 22 | public NightVisionButton(Player viewer) { 23 | super(viewer, NAME_KEY, COLOR, LORE_KEY, MATERIAL, 1); 24 | } 25 | 26 | @Override 27 | public Consumer getClickEvent() { 28 | return c -> { 29 | toggleNightVision(getViewer()); 30 | c.setCancelled(true); 31 | c.setCurrentItem(getIcon()); 32 | }; 33 | } 34 | 35 | @Override 36 | public Component getLoreComponent() { 37 | Component status = 38 | translatable( 39 | hasNightVision(getViewer()) ? "misc.on" : "misc.off", 40 | hasNightVision(getViewer()) ? NamedTextColor.GREEN : NamedTextColor.RED); 41 | return translatable("setting.nightvision.lore", NamedTextColor.GRAY, status); 42 | } 43 | 44 | private boolean hasNightVision(Player player) { 45 | return player.hasPotionEffect(PotionEffectType.NIGHT_VISION); 46 | } 47 | 48 | public void toggleNightVision(Player player) { 49 | if (hasNightVision(player)) { 50 | player.removePotionEffect(PotionEffectType.NIGHT_VISION); 51 | } else { 52 | player.addPotionEffect( 53 | new PotionEffect(PotionEffectType.NIGHT_VISION, Integer.MAX_VALUE, 0, true, false)); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/tools/types/LookupSign.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.tools.types; 2 | 3 | import com.google.common.collect.Lists; 4 | import dev.pgm.community.moderation.tools.ToolBase; 5 | import dev.pgm.community.utils.compatibility.Materials; 6 | import java.util.List; 7 | import org.bukkit.Material; 8 | import tc.oc.pgm.api.player.MatchPlayer; 9 | import tc.oc.pgm.api.player.event.ObserverInteractEvent; 10 | 11 | public class LookupSign extends ToolBase { 12 | 13 | private static final Material MATERIAL = Materials.SIGN; 14 | 15 | private static final String NAME = "&c&lLookup Sign"; 16 | private static final List LORE = 17 | Lists.newArrayList("&7Click &bplayer &7to view punishment info"); 18 | 19 | public LookupSign(int slot, boolean enabled) { 20 | super(slot, enabled); 21 | } 22 | 23 | @Override 24 | public String getName() { 25 | return NAME; 26 | } 27 | 28 | @Override 29 | public List getLore() { 30 | return LORE; 31 | } 32 | 33 | @Override 34 | public Material getMaterial() { 35 | return MATERIAL; 36 | } 37 | 38 | @Override 39 | public void onLeftClick(ObserverInteractEvent event) { 40 | lookup(event); 41 | } 42 | 43 | @Override 44 | public void onRightClick(ObserverInteractEvent event) { 45 | lookup(event); 46 | } 47 | 48 | private void lookup(ObserverInteractEvent event) { 49 | if (event.getClickedPlayer() != null) { 50 | MatchPlayer target = event.getClickedPlayer(); 51 | event.getPlayer().getBukkit().performCommand("l " + target.getId().toString()); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/moderation/tools/types/ModerationMenuTool.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.moderation.tools.types; 2 | 3 | import com.google.common.collect.Lists; 4 | import dev.pgm.community.moderation.tools.ToolBase; 5 | import dev.pgm.community.moderation.tools.menu.ModerationToolsMenu; 6 | import java.util.List; 7 | import org.bukkit.Material; 8 | import org.bukkit.entity.Player; 9 | import tc.oc.pgm.api.player.event.ObserverInteractEvent; 10 | 11 | public class ModerationMenuTool extends ToolBase { 12 | 13 | private static final Material MATERIAL = Material.EMERALD; 14 | 15 | private static final String NAME = "&a&lModerator Tools"; 16 | private static final List LORE = 17 | Lists.newArrayList("&7Click to open the mod tools menu."); 18 | 19 | private ModerationToolsMenu menu; 20 | 21 | public ModerationMenuTool(int slot, boolean enabled) { 22 | super(slot, enabled); 23 | this.menu = new ModerationToolsMenu(); 24 | } 25 | 26 | @Override 27 | public String getName() { 28 | return NAME; 29 | } 30 | 31 | @Override 32 | public List getLore() { 33 | return LORE; 34 | } 35 | 36 | @Override 37 | public Material getMaterial() { 38 | return MATERIAL; 39 | } 40 | 41 | @Override 42 | public void onLeftClick(ObserverInteractEvent event) { 43 | openMenu(event.getPlayer().getBukkit()); 44 | } 45 | 46 | @Override 47 | public void onRightClick(ObserverInteractEvent event) { 48 | openMenu(event.getPlayer().getBukkit()); 49 | } 50 | 51 | public void openMenu(Player viewer) { 52 | menu.open(viewer); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/motd/MotdConfig.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.motd; 2 | 3 | import dev.pgm.community.feature.config.FeatureConfigImpl; 4 | import dev.pgm.community.utils.MessageUtils; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | import net.kyori.adventure.text.Component; 8 | import org.bukkit.configuration.Configuration; 9 | 10 | public class MotdConfig extends FeatureConfigImpl { 11 | 12 | private static final String KEY = "motd"; 13 | 14 | private List lines; 15 | 16 | public MotdConfig(Configuration config) { 17 | super(KEY, config); 18 | } 19 | 20 | public List getLines() { 21 | return lines; 22 | } 23 | 24 | @Override 25 | public void reload(Configuration config) { 26 | super.reload(config); 27 | this.lines = config.getStringList(getKey() + ".lines").stream() 28 | .map(MessageUtils::parseComponentWithURL) 29 | .collect(Collectors.toList()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/motd/MotdFeature.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.motd; 2 | 3 | import dev.pgm.community.feature.FeatureBase; 4 | import java.util.logging.Logger; 5 | import org.bukkit.configuration.Configuration; 6 | import org.bukkit.event.EventHandler; 7 | import org.bukkit.event.EventPriority; 8 | import org.bukkit.event.player.PlayerJoinEvent; 9 | import tc.oc.pgm.util.Audience; 10 | 11 | /** MotdFeature - Displays a configurable message at login * */ 12 | public class MotdFeature extends FeatureBase { 13 | 14 | public MotdFeature(Configuration config, Logger logger) { 15 | super(new MotdConfig(config), logger, "MOTD"); 16 | if (getConfig().isEnabled()) { 17 | enable(); 18 | } 19 | } 20 | 21 | public MotdConfig getMotdConfig() { 22 | return (MotdConfig) getConfig(); 23 | } 24 | 25 | @EventHandler(priority = EventPriority.LOW) 26 | public void onPlayerJoin(PlayerJoinEvent event) { 27 | if (getMotdConfig().getLines().isEmpty()) return; 28 | Audience audience = Audience.get(event.getPlayer()); 29 | getMotdConfig().getLines().forEach(audience::sendMessage); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/Mutation.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations; 2 | 3 | import static net.kyori.adventure.text.Component.text; 4 | 5 | import dev.pgm.community.mutations.options.MutationOption; 6 | import java.util.Collection; 7 | import java.util.Set; 8 | import net.kyori.adventure.text.Component; 9 | import net.kyori.adventure.text.event.HoverEvent; 10 | import net.kyori.adventure.text.format.NamedTextColor; 11 | import net.kyori.adventure.text.format.TextDecoration; 12 | 13 | /** Mutation - Represents a set of features that can be enabled/disabled during a PGM match * */ 14 | public interface Mutation { 15 | 16 | /** Called when a mutation is enabled */ 17 | void enable(); 18 | 19 | /** Called when a mutation is disabled */ 20 | void disable(); 21 | 22 | /** 23 | * Get whether this mutation has been enabled 24 | * 25 | * @return true if enabled, false if not 26 | */ 27 | boolean isEnabled(); 28 | 29 | /** 30 | * Gets the {@link MutationType} of this mutation 31 | * 32 | * @return the mutation type 33 | */ 34 | MutationType getType(); 35 | 36 | /** 37 | * Gets a set of {@link MutationOption} for this mutation. Set will be empty if there are no 38 | * options. 39 | * 40 | * @return a set of {@link MutationOption} 41 | */ 42 | Collection getOptions(); 43 | 44 | /** 45 | * Gets whether it is safe to enable current mutation Ex. If map is rage, don't allow rage 46 | * mutation to be enabled 47 | * 48 | * @param existingMutations - A set of existing mutations to check 49 | * @return 50 | */ 51 | boolean canEnable(Set existingMutations); 52 | 53 | default Component getName() { 54 | return text( 55 | getType().getDisplayName(), 56 | isEnabled() ? NamedTextColor.GREEN : NamedTextColor.RED, 57 | TextDecoration.BOLD) 58 | .hoverEvent(HoverEvent.showText(text(getType().getDescription(), NamedTextColor.GRAY))); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/MutationBase.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations; 2 | 3 | import com.google.common.collect.Sets; 4 | import dev.pgm.community.Community; 5 | import dev.pgm.community.mutations.options.MutationOption; 6 | import java.util.Collection; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.event.HandlerList; 9 | import org.bukkit.event.Listener; 10 | import org.jetbrains.annotations.Nullable; 11 | import tc.oc.pgm.api.match.Match; 12 | 13 | /** MutationBase - Foundation of all mutations */ 14 | public abstract class MutationBase implements Mutation, Listener { 15 | 16 | private boolean enabled; 17 | 18 | protected final Match match; 19 | private final MutationType type; 20 | 21 | public MutationBase(Match match, MutationType type) { 22 | this.match = match; 23 | this.type = type; 24 | } 25 | 26 | @Override 27 | public MutationType getType() { 28 | return type; 29 | } 30 | 31 | @Override 32 | public void enable() { 33 | if (!isEnabled()) { 34 | this.enabled = true; 35 | Community.get().getServer().getPluginManager().registerEvents(this, Community.get()); 36 | } 37 | } 38 | 39 | @Override 40 | public void disable() { 41 | this.enabled = false; 42 | HandlerList.unregisterAll(this); 43 | } 44 | 45 | @Override 46 | public Collection getOptions() { 47 | return Sets.newHashSet(); 48 | } 49 | 50 | @Override 51 | public boolean isEnabled() { 52 | return enabled; 53 | } 54 | 55 | protected boolean isParticipant(@Nullable Player player) { 56 | return player != null && match.getParticipant(player) != null; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/MutationConfig.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations; 2 | 3 | import dev.pgm.community.feature.config.FeatureConfigImpl; 4 | import org.bukkit.configuration.Configuration; 5 | 6 | public class MutationConfig extends FeatureConfigImpl { 7 | 8 | private static final String KEY = "mutations"; 9 | 10 | public MutationConfig(Configuration config) { 11 | super(KEY, config); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/options/MutationBooleanOption.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations.options; 2 | 3 | import org.bukkit.Material; 4 | 5 | public class MutationBooleanOption extends MutationOption { 6 | 7 | private boolean value; 8 | private boolean def; 9 | 10 | public MutationBooleanOption( 11 | String name, String description, Material iconMaterial, boolean def, boolean prereq) { 12 | super(name, description, iconMaterial, prereq); 13 | this.value = def; 14 | this.def = def; 15 | } 16 | 17 | public boolean getValue() { 18 | return value; 19 | } 20 | 21 | public boolean getDefaultValue() { 22 | return def; 23 | } 24 | 25 | public void setValue(boolean value) { 26 | this.value = value; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/options/MutationListOption.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations.options; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import java.util.List; 5 | import org.bukkit.Material; 6 | 7 | public class MutationListOption extends MutationOption { 8 | 9 | private List options; 10 | private int valueIndex; 11 | private T def; 12 | 13 | public MutationListOption( 14 | String name, 15 | String description, 16 | Material iconMaterial, 17 | boolean prerequisite, 18 | List options) { 19 | super(name, description, iconMaterial, prerequisite); 20 | this.options = options; 21 | this.valueIndex = 0; 22 | this.def = options.get(0); 23 | } 24 | 25 | public ImmutableList getOptions() { 26 | return ImmutableList.copyOf(options); 27 | } 28 | 29 | public T getDefaultValue() { 30 | return def; 31 | } 32 | 33 | public T getValue() { 34 | return options.get(valueIndex); 35 | } 36 | 37 | public void toggle(boolean forward) { 38 | this.valueIndex = valueIndex + (forward ? 1 : -1); 39 | 40 | if (valueIndex >= options.size()) { 41 | valueIndex = 0; 42 | } 43 | 44 | if (valueIndex < 0) { 45 | valueIndex = options.size() - 1; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/options/MutationOption.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations.options; 2 | 3 | import org.bukkit.Material; 4 | 5 | public abstract class MutationOption { 6 | 7 | private final String name; 8 | private final String description; 9 | private final Material iconMaterial; 10 | private final boolean prerequisite; 11 | 12 | public MutationOption( 13 | String name, String description, Material iconMaterial, boolean prerequisite) { 14 | this.name = name; 15 | this.description = description; 16 | this.iconMaterial = iconMaterial; 17 | this.prerequisite = prerequisite; 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | public String getDescription() { 25 | return description; 26 | } 27 | 28 | public Material getIconMaterial() { 29 | return iconMaterial; 30 | } 31 | 32 | public boolean isPrerequisite() { 33 | return prerequisite; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/options/MutationRangeOption.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations.options; 2 | 3 | import org.bukkit.Material; 4 | 5 | public class MutationRangeOption extends MutationOption { 6 | 7 | private int min; 8 | private int max; 9 | private int value; 10 | private int def; 11 | 12 | public MutationRangeOption( 13 | String name, 14 | String description, 15 | Material iconMaterial, 16 | boolean prereq, 17 | int def, 18 | int min, 19 | int max) { 20 | super(name, description, iconMaterial, prereq); 21 | this.min = min; 22 | this.max = max; 23 | this.value = def; 24 | this.def = def; 25 | } 26 | 27 | public int getValue() { 28 | return value; 29 | } 30 | 31 | public int getDefaultValue() { 32 | return def; 33 | } 34 | 35 | public int getMin() { 36 | return min; 37 | } 38 | 39 | public int getMax() { 40 | return max; 41 | } 42 | 43 | public void setValue(int value) { 44 | if (value >= min && value <= max) { 45 | this.value = value; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/types/BowMutation.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations.types; 2 | 3 | import dev.pgm.community.mutations.Mutation; 4 | import java.util.Set; 5 | 6 | // Denotes a mutation that modifies projectile type of a bow (only 1 per match) 7 | public interface BowMutation { 8 | 9 | default boolean hasBowMutation(Set activeMutations) { 10 | return activeMutations.stream().anyMatch(m -> m instanceof BowMutation); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/types/ScheduledMutationBase.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations.types; 2 | 3 | import dev.pgm.community.Community; 4 | import dev.pgm.community.mutations.MutationBase; 5 | import dev.pgm.community.mutations.MutationType; 6 | import java.util.Random; 7 | import tc.oc.pgm.api.match.Match; 8 | 9 | /** ScheduledMutationBase - A base for mutations which require a repeating task * */ 10 | public abstract class ScheduledMutationBase extends MutationBase { 11 | 12 | private int taskID; 13 | private final int seconds; 14 | 15 | protected final Random random; 16 | 17 | public ScheduledMutationBase(Match match, MutationType type, int seconds) { 18 | super(match, type); 19 | this.seconds = seconds; 20 | this.random = new Random(); 21 | } 22 | 23 | public abstract void run(); 24 | 25 | @Override 26 | public void enable() { 27 | super.enable(); 28 | this.taskID = 29 | Community.get() 30 | .getServer() 31 | .getScheduler() 32 | .scheduleSyncRepeatingTask(Community.get(), this::run, 20L, 20L * seconds); 33 | } 34 | 35 | @Override 36 | public void disable() { 37 | super.disable(); 38 | Community.get().getServer().getScheduler().cancelTask(taskID); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/types/arrows/EnderpearlMutation.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations.types.arrows; 2 | 3 | import com.google.common.collect.Sets; 4 | import dev.pgm.community.mutations.Mutation; 5 | import dev.pgm.community.mutations.MutationBase; 6 | import dev.pgm.community.mutations.MutationType; 7 | import dev.pgm.community.mutations.types.BowMutation; 8 | import java.util.Set; 9 | import org.bukkit.entity.EnderPearl; 10 | import org.bukkit.event.HandlerList; 11 | import tc.oc.pgm.api.match.Match; 12 | import tc.oc.pgm.api.match.MatchScope; 13 | import tc.oc.pgm.filters.matcher.StaticFilter; 14 | import tc.oc.pgm.modules.ModifyBowProjectileMatchModule; 15 | 16 | public class EnderpearlMutation extends MutationBase implements BowMutation { 17 | 18 | private ModifyBowProjectileMatchModule module; 19 | 20 | public EnderpearlMutation(Match match) { 21 | super(match, MutationType.ENDERPEARL); 22 | } 23 | 24 | @Override 25 | public boolean canEnable(Set existing) { 26 | return match.getModule(ModifyBowProjectileMatchModule.class) == null 27 | && !hasBowMutation(existing); 28 | } 29 | 30 | @Override 31 | public void enable() { 32 | super.enable(); 33 | this.module = 34 | new ModifyBowProjectileMatchModule( 35 | match, EnderPearl.class, 1, Sets.newHashSet(), StaticFilter.ALLOW); 36 | module.enable(); 37 | match.addListener(module, MatchScope.RUNNING); 38 | } 39 | 40 | @Override 41 | public void disable() { 42 | super.disable(); 43 | if (module != null) { 44 | module.disable(); 45 | HandlerList.unregisterAll(module); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/types/arrows/FireballBowMutation.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations.types.arrows; 2 | 3 | import com.google.common.collect.Sets; 4 | import dev.pgm.community.mutations.Mutation; 5 | import dev.pgm.community.mutations.MutationBase; 6 | import dev.pgm.community.mutations.MutationType; 7 | import dev.pgm.community.mutations.types.BowMutation; 8 | import java.util.Set; 9 | import org.bukkit.entity.Fireball; 10 | import org.bukkit.event.HandlerList; 11 | import tc.oc.pgm.api.match.Match; 12 | import tc.oc.pgm.api.match.MatchScope; 13 | import tc.oc.pgm.filters.matcher.StaticFilter; 14 | import tc.oc.pgm.modules.ModifyBowProjectileMatchModule; 15 | 16 | public class FireballBowMutation extends MutationBase implements BowMutation { 17 | 18 | private ModifyBowProjectileMatchModule module; 19 | 20 | public FireballBowMutation(Match match) { 21 | super(match, MutationType.FIREBALL_BOW); 22 | } 23 | 24 | @Override 25 | public boolean canEnable(Set existing) { 26 | return match.getModule(ModifyBowProjectileMatchModule.class) == null 27 | && !hasBowMutation(existing); 28 | } 29 | 30 | @Override 31 | public void enable() { 32 | super.enable(); 33 | this.module = 34 | new ModifyBowProjectileMatchModule( 35 | match, Fireball.class, 1, Sets.newHashSet(), StaticFilter.ALLOW); 36 | module.enable(); 37 | match.addListener(module, MatchScope.RUNNING); 38 | } 39 | 40 | @Override 41 | public void disable() { 42 | super.disable(); 43 | if (module != null) { 44 | module.disable(); 45 | HandlerList.unregisterAll(module); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/types/arrows/TNTBowMutation.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations.types.arrows; 2 | 3 | import com.google.common.collect.Sets; 4 | import dev.pgm.community.mutations.Mutation; 5 | import dev.pgm.community.mutations.MutationBase; 6 | import dev.pgm.community.mutations.MutationType; 7 | import dev.pgm.community.mutations.types.BowMutation; 8 | import java.util.Set; 9 | import org.bukkit.entity.TNTPrimed; 10 | import org.bukkit.event.HandlerList; 11 | import tc.oc.pgm.api.match.Match; 12 | import tc.oc.pgm.api.match.MatchScope; 13 | import tc.oc.pgm.filters.matcher.StaticFilter; 14 | import tc.oc.pgm.modules.ModifyBowProjectileMatchModule; 15 | 16 | public class TNTBowMutation extends MutationBase implements BowMutation { 17 | 18 | private ModifyBowProjectileMatchModule module; 19 | 20 | public TNTBowMutation(Match match) { 21 | super(match, MutationType.TNT_BOW); 22 | } 23 | 24 | @Override 25 | public boolean canEnable(Set existing) { 26 | return match.getModule(ModifyBowProjectileMatchModule.class) == null 27 | && !hasBowMutation(existing); 28 | } 29 | 30 | @Override 31 | public void enable() { 32 | super.enable(); 33 | this.module = 34 | new ModifyBowProjectileMatchModule( 35 | match, TNTPrimed.class, 1, Sets.newHashSet(), StaticFilter.ALLOW); 36 | module.enable(); 37 | match.addListener(module, MatchScope.RUNNING); 38 | } 39 | 40 | @Override 41 | public void disable() { 42 | super.disable(); 43 | if (module != null) { 44 | module.disable(); 45 | HandlerList.unregisterAll(module); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/types/gameplay/BlitzMutation.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations.types.gameplay; 2 | 3 | import com.google.common.collect.Sets; 4 | import dev.pgm.community.mutations.Mutation; 5 | import dev.pgm.community.mutations.MutationBase; 6 | import dev.pgm.community.mutations.MutationType; 7 | import dev.pgm.community.mutations.options.MutationOption; 8 | import dev.pgm.community.mutations.options.MutationRangeOption; 9 | import java.util.Collection; 10 | import java.util.Set; 11 | import org.bukkit.Material; 12 | import org.bukkit.event.HandlerList; 13 | import tc.oc.pgm.api.match.Match; 14 | import tc.oc.pgm.api.match.MatchScope; 15 | import tc.oc.pgm.blitz.BlitzConfig; 16 | import tc.oc.pgm.blitz.BlitzMatchModule; 17 | import tc.oc.pgm.filters.matcher.StaticFilter; 18 | 19 | /** BlitzMutation - Enables blitz on a non-blitz match * */ 20 | public class BlitzMutation extends MutationBase { 21 | 22 | private static MutationRangeOption BLITZ_LIVES = 23 | new MutationRangeOption( 24 | "Blitz Lives", "The number of lives per-user", Material.EGG, true, 1, 1, 999); 25 | 26 | private BlitzMatchModule blitz; 27 | 28 | public BlitzMutation(Match match) { 29 | super(match, MutationType.BLITZ); 30 | } 31 | 32 | @Override 33 | public Collection getOptions() { 34 | return Sets.newHashSet(BLITZ_LIVES); 35 | } 36 | 37 | @Override 38 | public void enable() { 39 | super.enable(); 40 | this.blitz = 41 | new BlitzMatchModule( 42 | match, 43 | new BlitzConfig( 44 | BLITZ_LIVES.getValue(), 45 | true, 46 | StaticFilter.ALLOW, 47 | StaticFilter.ALLOW, 48 | StaticFilter.DENY)); 49 | 50 | blitz.enable(); 51 | match.addListener(blitz, MatchScope.RUNNING); 52 | } 53 | 54 | @Override 55 | public void disable() { 56 | super.disable(); 57 | if (blitz != null) { 58 | blitz.disable(); 59 | HandlerList.unregisterAll(blitz); 60 | } 61 | } 62 | 63 | @Override 64 | public boolean canEnable(Set existing) { 65 | return match.getModule(BlitzMatchModule.class) == null; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/types/gameplay/GhostMutation.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations.types.gameplay; 2 | 3 | import com.google.common.collect.Sets; 4 | import dev.pgm.community.mutations.Mutation; 5 | import dev.pgm.community.mutations.MutationType; 6 | import dev.pgm.community.mutations.types.KitMutationBase; 7 | import java.util.Set; 8 | import org.bukkit.potion.PotionEffect; 9 | import org.bukkit.potion.PotionEffectType; 10 | import org.bukkit.scoreboard.NameTagVisibility; 11 | import tc.oc.pgm.api.match.Match; 12 | import tc.oc.pgm.api.party.Competitor; 13 | import tc.oc.pgm.kits.PotionKit; 14 | 15 | public class GhostMutation extends KitMutationBase { 16 | 17 | private static final PotionEffect EFFECT = 18 | new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 1, false, false); 19 | private static final PotionKit KIT = new PotionKit(Sets.newHashSet(EFFECT)); 20 | 21 | public GhostMutation(Match match) { 22 | super(match, MutationType.GHOST, KIT); 23 | } 24 | 25 | @Override 26 | public void enable() { 27 | super.enable(); 28 | match.getParties().stream() 29 | .filter(party -> party instanceof Competitor) 30 | .forEach( 31 | party -> 32 | ((Competitor) party).setNameTagVisibility(NameTagVisibility.HIDE_FOR_OTHER_TEAMS)); 33 | ; 34 | } 35 | 36 | @Override 37 | public void disable() { 38 | super.disable(); 39 | match.getParties().stream() 40 | .filter(party -> party instanceof Competitor) 41 | .forEach(party -> ((Competitor) party).setNameTagVisibility(NameTagVisibility.ALWAYS)); 42 | } 43 | 44 | @Override 45 | public boolean canEnable(Set existing) { 46 | return true; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/types/gameplay/RageMutation.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations.types.gameplay; 2 | 3 | import dev.pgm.community.mutations.Mutation; 4 | import dev.pgm.community.mutations.MutationBase; 5 | import dev.pgm.community.mutations.MutationType; 6 | import java.util.Set; 7 | import org.bukkit.entity.Entity; 8 | import org.bukkit.entity.Player; 9 | import org.bukkit.entity.Projectile; 10 | import org.bukkit.event.EventHandler; 11 | import org.bukkit.event.EventPriority; 12 | import org.bukkit.event.entity.EntityDamageByEntityEvent; 13 | import tc.oc.pgm.api.match.Match; 14 | import tc.oc.pgm.rage.RageMatchModule; 15 | import tc.oc.pgm.util.material.Materials; 16 | 17 | /** RageMutation - Enables rage (1-hit kills) on non-rage matches */ 18 | public class RageMutation extends MutationBase { 19 | 20 | public RageMutation(Match match) { 21 | super(match, MutationType.RAGE); 22 | } 23 | 24 | @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 25 | public void onPlayerDamage(EntityDamageByEntityEvent event) { 26 | if (isRageHit(event.getDamager())) { 27 | event.setDamage(1000); 28 | } 29 | } 30 | 31 | private boolean isRageHit(Entity entity) { 32 | return (entity instanceof Player 33 | && Materials.isWeapon(((Player) entity).getItemInHand().getType())) 34 | || (entity instanceof Projectile && ((Projectile) entity).getShooter() instanceof Player); 35 | } 36 | 37 | @Override 38 | public boolean canEnable(Set existing) { 39 | return match.getModule(RageMatchModule.class) == null; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/types/mechanics/BlindMutation.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations.types.mechanics; 2 | 3 | import com.google.common.collect.Sets; 4 | import dev.pgm.community.mutations.Mutation; 5 | import dev.pgm.community.mutations.MutationType; 6 | import dev.pgm.community.mutations.types.KitMutationBase; 7 | import java.util.Set; 8 | import org.bukkit.potion.PotionEffect; 9 | import org.bukkit.potion.PotionEffectType; 10 | import tc.oc.pgm.api.match.Match; 11 | import tc.oc.pgm.kits.PotionKit; 12 | 13 | public class BlindMutation extends KitMutationBase { 14 | 15 | public BlindMutation(Match match) { 16 | super(match, MutationType.BLIND, getBlindKit()); 17 | } 18 | 19 | @Override 20 | public boolean canEnable(Set existing) { 21 | return true; 22 | } 23 | 24 | private static PotionKit getBlindKit() { 25 | return new PotionKit( 26 | Sets.newHashSet(new PotionEffect(PotionEffectType.BLINDNESS, Integer.MAX_VALUE, 1))); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/types/mechanics/FriendlyFireMutation.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations.types.mechanics; 2 | 3 | import dev.pgm.community.mutations.Mutation; 4 | import dev.pgm.community.mutations.MutationBase; 5 | import dev.pgm.community.mutations.MutationType; 6 | import java.util.Set; 7 | import tc.oc.pgm.api.match.Match; 8 | import tc.oc.pgm.scoreboard.ScoreboardMatchModule; 9 | 10 | public class FriendlyFireMutation extends MutationBase { 11 | 12 | public FriendlyFireMutation(Match match) { 13 | super(match, MutationType.FRIENDLY); 14 | } 15 | 16 | @Override 17 | public boolean canEnable(Set existing) { 18 | return !match.getFriendlyFire(); 19 | } 20 | 21 | @Override 22 | public void enable() { 23 | super.enable(); 24 | match.setFriendlyFire(true); 25 | forceTeamUpdate(); 26 | } 27 | 28 | @Override 29 | public void disable() { 30 | match.setFriendlyFire(false); 31 | forceTeamUpdate(); 32 | super.disable(); 33 | } 34 | 35 | private void forceTeamUpdate() { 36 | ScoreboardMatchModule smm = match.getModule(ScoreboardMatchModule.class); 37 | if (smm == null) return; 38 | smm.getScoreboards() 39 | .forEach( 40 | board -> { 41 | board.getTeams().forEach(team -> team.setAllowFriendlyFire(match.getFriendlyFire())); 42 | }); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/types/mechanics/HealthMutation.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations.types.mechanics; 2 | 3 | import dev.pgm.community.mutations.Mutation; 4 | import dev.pgm.community.mutations.MutationType; 5 | import dev.pgm.community.mutations.types.KitMutationBase; 6 | import java.util.Set; 7 | import org.bukkit.potion.PotionEffect; 8 | import org.bukkit.potion.PotionEffectType; 9 | import tc.oc.pgm.api.match.Match; 10 | import tc.oc.pgm.api.player.MatchPlayer; 11 | import tc.oc.pgm.kits.MaxHealthKit; 12 | 13 | public class HealthMutation extends KitMutationBase { 14 | 15 | public HealthMutation(Match match) { 16 | super(match, MutationType.HEALTH, getHealthKit()); 17 | } 18 | 19 | @Override 20 | public boolean canEnable(Set existing) { 21 | return true; 22 | } 23 | 24 | @Override 25 | public void spawn(MatchPlayer player) { 26 | super.spawn(player); 27 | player.getBukkit().addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 3, 9)); 28 | } 29 | 30 | private static MaxHealthKit getHealthKit() { 31 | return new MaxHealthKit(40); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/mutations/types/mechanics/KnockbackMutation.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.mutations.types.mechanics; 2 | 3 | import dev.pgm.community.mutations.Mutation; 4 | import dev.pgm.community.mutations.MutationBase; 5 | import dev.pgm.community.mutations.MutationType; 6 | import java.util.Set; 7 | import org.bukkit.entity.Entity; 8 | import org.bukkit.event.EventHandler; 9 | import org.bukkit.event.EventPriority; 10 | import org.bukkit.util.Vector; 11 | import tc.oc.pgm.api.match.Match; 12 | import tc.oc.pgm.api.player.MatchPlayer; 13 | import tc.oc.pgm.util.event.player.PlayerAttackEntityEvent; 14 | 15 | public class KnockbackMutation extends MutationBase { 16 | 17 | public KnockbackMutation(Match match) { 18 | super(match, MutationType.KNOCKBACK); 19 | } 20 | 21 | @Override 22 | public boolean canEnable(Set existing) { 23 | return true; 24 | } 25 | 26 | @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 27 | public void onPlayerDamage(PlayerAttackEntityEvent event) { 28 | Entity target = event.getLeftClicked(); 29 | MatchPlayer player = match.getParticipant(event.getPlayer()); 30 | if (target == null || player == null || target.isDead() || player.isDead()) return; 31 | Vector playerLocation = player.getLocation().getDirection(); 32 | target.setVelocity(playerLocation.setY(1).multiply(2 + match.getRandom().nextInt(4))); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/network/Channels.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.network; 2 | 3 | /** Channels - Names of Channels used by NetworkUpdates * */ 4 | public class Channels { 5 | 6 | // PUNISHMENTS - Used to alert which a new punishment was issued for a player 7 | public static final String PUNISHMENTS = formatChannel("punishments"); 8 | 9 | // ASSISTANCE - Used to broadcast reports/assist requests to other servers 10 | public static final String ASSISTANCE = formatChannel("assistance"); 11 | 12 | // CHAT - Used to broadcast chat messages to other servers 13 | public static final String CHAT = formatChannel("chat"); 14 | 15 | // PUNISHMENT_UPDATE - Used to alert servers of unmuted or unbanned players 16 | public static final String PUNISHMENT_UPDATE = formatChannel("punishment_update"); 17 | 18 | private static final String formatChannel(String name) { 19 | return "community_" + name; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/network/NetworkConfig.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.network; 2 | 3 | import dev.pgm.community.feature.config.FeatureConfigImpl; 4 | import dev.pgm.community.utils.NetworkUtils; 5 | import java.util.UUID; 6 | import org.bukkit.configuration.Configuration; 7 | 8 | public class NetworkConfig extends FeatureConfigImpl { 9 | 10 | private static final String KEY = "network"; 11 | 12 | private static final String ID = KEY + ".id"; 13 | 14 | private static final String REDIS = KEY + ".redis"; 15 | private static final String REDIS_HOST = REDIS + ".host"; 16 | private static final String REDIS_PASSWORD = REDIS + ".password"; 17 | private static final String REDIS_PORT = REDIS + ".port"; 18 | private static final String REDIS_SSL = REDIS + ".ssl"; 19 | 20 | private String host; 21 | private String password; 22 | private int port; 23 | private boolean ssl; 24 | 25 | private String networkId; 26 | 27 | public NetworkConfig(Configuration config) { 28 | super(KEY, config); 29 | } 30 | 31 | public String getNetworkId() { 32 | return NetworkUtils.getServerVar(networkId); 33 | } 34 | 35 | public String getHost() { 36 | return host; 37 | } 38 | 39 | public String getPassword() { 40 | return password; 41 | } 42 | 43 | public int getPort() { 44 | return port; 45 | } 46 | 47 | public boolean isSSL() { 48 | return ssl; 49 | } 50 | 51 | @Override 52 | public void reload(Configuration config) { 53 | super.reload(config); 54 | this.host = config.getString(REDIS_HOST); 55 | this.password = config.getString(REDIS_PASSWORD); 56 | this.port = config.getInt(REDIS_PORT); 57 | this.ssl = config.getBoolean(REDIS_SSL); 58 | 59 | String netId = config.getString(ID); 60 | this.networkId = netId != null && !netId.isEmpty() ? netId : UUID.randomUUID().toString(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/network/feature/NetworkFeature.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.network.feature; 2 | 3 | import dev.pgm.community.feature.Feature; 4 | import dev.pgm.community.network.subs.NetworkSubscriber; 5 | import dev.pgm.community.network.updates.NetworkUpdate; 6 | 7 | /** NetworkFeature - Feature related to communicating across multiple servers (Bungee) * */ 8 | public interface NetworkFeature extends Feature { 9 | 10 | /** 11 | * Send a {@link NetworkUpdate} to publisher 12 | * 13 | * @param update The network update 14 | */ 15 | void sendUpdate(NetworkUpdate update); 16 | 17 | /** 18 | * Register a new {@link NetworkSubscriber} Will listen to and consume updates from {@link 19 | * #sendUpdate(NetworkUpdate)} 20 | * 21 | * @param sub 22 | */ 23 | void registerSubscriber(NetworkSubscriber sub); 24 | 25 | /** 26 | * Get the Network ID The network id is used to identify server where update originated from. 27 | * 28 | *

Note: Community will not consume updates which originate from the source server 29 | * 30 | * @return the network id 31 | */ 32 | String getNetworkId(); 33 | } 34 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/network/feature/NetworkFeatureBase.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.network.feature; 2 | 3 | import dev.pgm.community.feature.FeatureBase; 4 | import dev.pgm.community.network.NetworkConfig; 5 | import java.util.logging.Logger; 6 | import org.bukkit.configuration.Configuration; 7 | 8 | public abstract class NetworkFeatureBase extends FeatureBase implements NetworkFeature { 9 | 10 | public NetworkFeatureBase(Configuration config, Logger logger, String featureName) { 11 | super(new NetworkConfig(config), logger, featureName); 12 | if (getConfig().isEnabled()) { 13 | enable(); 14 | } 15 | } 16 | 17 | public NetworkConfig getNetworkConfig() { 18 | return (NetworkConfig) getConfig(); 19 | } 20 | 21 | @Override 22 | public String getNetworkId() { 23 | return getNetworkConfig().getNetworkId(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/network/subs/NetworkSubscriber.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.network.subs; 2 | 3 | import com.google.gson.Gson; 4 | import dev.pgm.community.utils.gson.GsonProvider; 5 | import java.util.logging.Logger; 6 | import redis.clients.jedis.JedisPubSub; 7 | 8 | public abstract class NetworkSubscriber extends JedisPubSub { 9 | 10 | private String channel; 11 | private String networkId; 12 | protected Logger logger; 13 | protected Gson gson; 14 | 15 | public NetworkSubscriber(String channel, String networkId, Logger logger) { 16 | this.channel = channel; 17 | this.networkId = networkId; 18 | this.logger = logger; 19 | this.gson = GsonProvider.get(); 20 | } 21 | 22 | public String getNetworkId() { 23 | return networkId; 24 | } 25 | 26 | public String getChannel() { 27 | return channel; 28 | } 29 | 30 | public abstract void onReceiveUpdate(String data); 31 | 32 | @Override 33 | public void onMessage(String channel, String msg) { 34 | if (channel.equalsIgnoreCase(getChannel())) { 35 | // Data format -> 'networkId;message' 36 | String[] parts = msg.split(";"); 37 | if (parts.length == 2) { 38 | String id = parts[0]; 39 | String data = parts[1]; 40 | if (!getNetworkId().equalsIgnoreCase(id)) { 41 | this.onReceiveUpdate(data); 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/network/subs/types/AssistanceSubscriber.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.network.subs.types; 2 | 3 | import dev.pgm.community.assistance.AssistanceRequest; 4 | import dev.pgm.community.assistance.feature.AssistanceFeature; 5 | import dev.pgm.community.network.Channels; 6 | import dev.pgm.community.network.subs.NetworkSubscriber; 7 | import java.util.logging.Logger; 8 | 9 | /** AssistanceSubscriber - Listens for {@link AssistanceRequest} */ 10 | public class AssistanceSubscriber extends NetworkSubscriber { 11 | 12 | private AssistanceFeature assist; 13 | 14 | public AssistanceSubscriber(AssistanceFeature assist, String networkId, Logger logger) { 15 | super(Channels.ASSISTANCE, networkId, logger); 16 | this.assist = assist; 17 | } 18 | 19 | @Override 20 | public void onReceiveUpdate(String data) { 21 | AssistanceRequest request = gson.fromJson(data, AssistanceRequest.class); 22 | if (request != null) { 23 | assist.recieveUpdate(request); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/network/subs/types/ChatSubscriber.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.network.subs.types; 2 | 3 | import dev.pgm.community.chat.network.NetworkChatFeature; 4 | import dev.pgm.community.chat.network.NetworkChatMessage; 5 | import dev.pgm.community.network.Channels; 6 | import dev.pgm.community.network.subs.NetworkSubscriber; 7 | import java.util.logging.Logger; 8 | 9 | /** ChatSubscriber - Listens for {@link NetworkChatMessage} */ 10 | public class ChatSubscriber extends NetworkSubscriber { 11 | 12 | private NetworkChatFeature chat; 13 | 14 | public ChatSubscriber(NetworkChatFeature chat, String networkId, Logger logger) { 15 | super(Channels.CHAT, networkId, logger); 16 | this.chat = chat; 17 | } 18 | 19 | @Override 20 | public void onReceiveUpdate(String data) { 21 | NetworkChatMessage message = gson.fromJson(data, NetworkChatMessage.class); 22 | if (message != null) { 23 | chat.recieveUpdate(message); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/network/subs/types/PunishmentSubscriber.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.network.subs.types; 2 | 3 | import dev.pgm.community.moderation.feature.ModerationFeature; 4 | import dev.pgm.community.moderation.punishments.NetworkPunishment; 5 | import dev.pgm.community.network.Channels; 6 | import dev.pgm.community.network.subs.NetworkSubscriber; 7 | import java.util.logging.Logger; 8 | 9 | /** PunishmentSubscriber - Listens for {@link NetworkPunishment} */ 10 | public class PunishmentSubscriber extends NetworkSubscriber { 11 | 12 | private ModerationFeature moderation; 13 | 14 | public PunishmentSubscriber(ModerationFeature moderation, String networkId, Logger logger) { 15 | super(Channels.PUNISHMENTS, networkId, logger); 16 | this.moderation = moderation; 17 | } 18 | 19 | @Override 20 | public void onReceiveUpdate(String data) { 21 | NetworkPunishment punishment = gson.fromJson(data, NetworkPunishment.class); 22 | if (punishment != null) { 23 | moderation.recieveUpdate(punishment); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/network/subs/types/RefreshPunishmentSubscriber.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.network.subs.types; 2 | 3 | import dev.pgm.community.moderation.feature.ModerationFeature; 4 | import dev.pgm.community.network.Channels; 5 | import dev.pgm.community.network.subs.NetworkSubscriber; 6 | import java.util.UUID; 7 | import java.util.logging.Logger; 8 | 9 | /** RefreshPunishmentSubscriber - Invalidates punishment cache for unbans/unmutes */ 10 | public class RefreshPunishmentSubscriber extends NetworkSubscriber { 11 | 12 | private ModerationFeature moderation; 13 | 14 | public RefreshPunishmentSubscriber( 15 | ModerationFeature moderation, String networkId, Logger logger) { 16 | super(Channels.PUNISHMENT_UPDATE, networkId, logger); 17 | this.moderation = moderation; 18 | } 19 | 20 | @Override 21 | public void onReceiveUpdate(String data) { 22 | try { 23 | UUID playerId = UUID.fromString(data); 24 | moderation.recieveRefresh(playerId); 25 | logger.info(String.format("Refreshed punishment data for %s", data)); 26 | } catch (IllegalArgumentException e) { 27 | logger.warning( 28 | String.format( 29 | "Invalid UUID (%s) recieved for message channel (%s)", Channels.PUNISHMENTS, data)); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/network/updates/NetworkUpdate.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.network.updates; 2 | 3 | public interface NetworkUpdate { 4 | 5 | String getChannel(); 6 | 7 | String getData(); 8 | } 9 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/network/updates/NetworkUpdateBase.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.network.updates; 2 | 3 | import com.google.gson.Gson; 4 | import dev.pgm.community.utils.gson.GsonProvider; 5 | 6 | public abstract class NetworkUpdateBase implements NetworkUpdate { 7 | 8 | private T item; 9 | private String channel; 10 | private Gson gson; 11 | 12 | public NetworkUpdateBase(T item, String channel) { 13 | this.item = item; 14 | this.channel = channel; 15 | this.gson = GsonProvider.get(); 16 | } 17 | 18 | @Override 19 | public String getChannel() { 20 | return channel; 21 | } 22 | 23 | @Override 24 | public String getData() { 25 | return gson.toJson(item); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/network/updates/types/AssistUpdate.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.network.updates.types; 2 | 3 | import dev.pgm.community.assistance.AssistanceRequest; 4 | import dev.pgm.community.network.Channels; 5 | import dev.pgm.community.network.updates.NetworkUpdateBase; 6 | 7 | /** AssistUpdate - Called when an {@link AssistanceRequest} is made */ 8 | public class AssistUpdate extends NetworkUpdateBase { 9 | 10 | public AssistUpdate(AssistanceRequest request) { 11 | super(request, Channels.ASSISTANCE); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/network/updates/types/ChatUpdate.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.network.updates.types; 2 | 3 | import dev.pgm.community.chat.network.NetworkChatMessage; 4 | import dev.pgm.community.network.Channels; 5 | import dev.pgm.community.network.updates.NetworkUpdateBase; 6 | 7 | /** ChatUpdate - Relay chat across the network. See {@link MatchPlayerChatEvent} */ 8 | public class ChatUpdate extends NetworkUpdateBase { 9 | 10 | public ChatUpdate(NetworkChatMessage message) { 11 | super(message, Channels.CHAT); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/network/updates/types/PunishmentUpdate.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.network.updates.types; 2 | 3 | import dev.pgm.community.moderation.punishments.NetworkPunishment; 4 | import dev.pgm.community.network.Channels; 5 | import dev.pgm.community.network.updates.NetworkUpdateBase; 6 | 7 | /** PunishmentUpdate - Called when a {@link Punishment} is issued */ 8 | public class PunishmentUpdate extends NetworkUpdateBase { 9 | 10 | public PunishmentUpdate(NetworkPunishment punishment) { 11 | super(punishment, Channels.PUNISHMENTS); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/network/updates/types/RefreshPunishmentUpdate.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.network.updates.types; 2 | 3 | import dev.pgm.community.network.Channels; 4 | import dev.pgm.community.network.updates.NetworkUpdate; 5 | import java.util.UUID; 6 | 7 | /** RefreshPunishmentUpdate - Called on ban pardon or unmute */ 8 | public class RefreshPunishmentUpdate implements NetworkUpdate { 9 | 10 | private final UUID playerId; 11 | 12 | public RefreshPunishmentUpdate(UUID playerId) { 13 | this.playerId = playerId; 14 | } 15 | 16 | @Override 17 | public String getChannel() { 18 | return Channels.PUNISHMENT_UPDATE; 19 | } 20 | 21 | @Override 22 | public String getData() { 23 | return playerId.toString(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/nick/Nick.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.nick; 2 | 3 | import java.time.Instant; 4 | import java.util.UUID; 5 | 6 | public interface Nick { 7 | 8 | /** 9 | * Get the nickname 10 | * 11 | * @return a nickname string 12 | */ 13 | String getName(); 14 | 15 | void setName(String name); 16 | 17 | /** 18 | * Get the owning player's ID 19 | * 20 | * @return player id 21 | */ 22 | UUID getPlayerId(); 23 | 24 | /** 25 | * Get the date in which nickname was set by the player 26 | * 27 | * @return a date 28 | */ 29 | Instant getDateSet(); 30 | 31 | /** 32 | * Get whether the nickname is enabled Note: This represents whether the user wants their nickname 33 | * applied upon login 34 | * 35 | * @return true if nickname is enabled, false if not 36 | */ 37 | boolean isEnabled(); 38 | 39 | /** 40 | * Set whether the nickname is enabled 41 | * 42 | * @param enabled True for enabled, false for not 43 | */ 44 | void setEnabled(boolean enabled); 45 | 46 | default void clear() { 47 | setName(""); 48 | setEnabled(false); 49 | } 50 | 51 | public static Nick of(UUID playerId, String nick) { 52 | return new NickImpl(playerId, nick, Instant.now(), true); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/nick/NickConfig.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.nick; 2 | 3 | import dev.pgm.community.feature.config.FeatureConfigImpl; 4 | import org.bukkit.configuration.Configuration; 5 | 6 | public class NickConfig extends FeatureConfigImpl { 7 | 8 | private static final String KEY = "nick"; 9 | 10 | private boolean pgmIntegration; 11 | 12 | public NickConfig(Configuration config) { 13 | super(KEY, config); 14 | } 15 | 16 | public boolean isIntegrationEnabled() { 17 | return pgmIntegration; 18 | } 19 | 20 | @Override 21 | public void reload(Configuration config) { 22 | super.reload(config); 23 | this.pgmIntegration = config.getBoolean(getKey() + ".pgm-integration"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/nick/NickImpl.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.nick; 2 | 3 | import java.time.Instant; 4 | import java.util.UUID; 5 | 6 | public class NickImpl implements Nick { 7 | 8 | private UUID playerId; 9 | private String nickName; 10 | private Instant date; 11 | private boolean enabled; 12 | 13 | public NickImpl(UUID playerId, String nickName, Instant date, boolean enabled) { 14 | this.playerId = playerId; 15 | this.nickName = nickName; 16 | this.date = date; 17 | this.enabled = enabled; 18 | } 19 | 20 | @Override 21 | public String getName() { 22 | return nickName; 23 | } 24 | 25 | @Override 26 | public void setName(String name) { 27 | this.nickName = name; 28 | this.enabled = true; 29 | this.date = Instant.now(); 30 | } 31 | 32 | @Override 33 | public UUID getPlayerId() { 34 | return playerId; 35 | } 36 | 37 | @Override 38 | public Instant getDateSet() { 39 | return date; 40 | } 41 | 42 | @Override 43 | public boolean isEnabled() { 44 | return !nickName.isEmpty() && enabled; 45 | } 46 | 47 | @Override 48 | public void setEnabled(boolean enabled) { 49 | this.enabled = enabled; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/nick/data/NickSelection.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.nick.data; 2 | 3 | import java.time.Duration; 4 | import java.time.Instant; 5 | import java.util.List; 6 | 7 | public class NickSelection { 8 | 9 | private List names; 10 | private Instant lastRefresh; 11 | 12 | public NickSelection(List names) { 13 | this.names = names; 14 | this.lastRefresh = Instant.now(); 15 | } 16 | 17 | public List getNames() { 18 | return names; 19 | } 20 | 21 | public boolean canRefresh() { 22 | return Duration.between(lastRefresh, Instant.now()).toHours() > 1; 23 | } 24 | 25 | public boolean isValid(String input) { 26 | return names.stream().anyMatch(s -> s.equalsIgnoreCase(input)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/nick/feature/NickFeature.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.nick.feature; 2 | 3 | import dev.pgm.community.feature.Feature; 4 | import dev.pgm.community.nick.Nick; 5 | import dev.pgm.community.nick.data.NickSelection; 6 | import dev.pgm.community.nick.skin.SkinManager; 7 | import java.util.UUID; 8 | import java.util.concurrent.CompletableFuture; 9 | import org.bukkit.entity.Player; 10 | 11 | public interface NickFeature extends Feature { 12 | 13 | CompletableFuture getNick(UUID playerId); // Get the CURRENT nick or NULL of a player 14 | 15 | CompletableFuture setNick(UUID playerId, String nickName); // Set the player's Nickname 16 | 17 | CompletableFuture clearNick(UUID playerId); // Remove the player's Nickname 18 | 19 | CompletableFuture toggleNickStatus(UUID playerId); // FALSE IF NO VALID NICK IS SET 20 | 21 | CompletableFuture setNickStatus(UUID playerId, boolean enabled); 22 | 23 | CompletableFuture isNameAvailable(String nickName); // RETURNS TRUE IF NAME IS NOT TAKEN 24 | 25 | boolean isNicked(UUID playerId); // Whether the given playerID is online & had a nickname 26 | 27 | String getOnlineNick(UUID playerId); // Get the nickname of an online player 28 | 29 | Player getPlayerFromNick(String nickName); 30 | 31 | void removeOnlineNick(UUID playerId); // Removes the player from being nicked 32 | 33 | boolean isAutoNicked( 34 | UUID playerId); // Whether the player was nicked via logging in with nick. 35 | 36 | SkinManager getSkinManager(); 37 | 38 | CompletableFuture getNickSelection(UUID playerId); 39 | } 40 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/nick/services/NickQuery.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.nick.services; 2 | 3 | public interface NickQuery { 4 | 5 | static final String TABLE_NAME = "nicknames"; 6 | static final String TABLE_FIELDS = 7 | "(playerId VARCHAR(36) PRIMARY KEY, nickname VARCHAR(16), date LONG, enabled BOOL)"; 8 | 9 | static final String INSERT_NICKNAME_QUERY = 10 | "INSERT INTO " + TABLE_NAME + "(playerId, nickname, date, enabled) VALUES (?,?,?,?)"; 11 | 12 | static final String SELECT_NICKNAME_BY_ID_QUERY = 13 | "SELECT * from " + TABLE_NAME + " where playerId = ? LIMIT 1"; 14 | 15 | static final String UPDATE_NICKNAME_QUERY = 16 | "UPDATE " + TABLE_NAME + " set nickname = ?, enabled = ?, date = ? where playerId = ?"; 17 | 18 | static final String SELECT_NICKNAME_BY_NAME_QUERY = 19 | "SELECT * from " + TABLE_NAME + " where LOWER(nickname) = LOWER(?)"; 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/nick/skin/SkinManager.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.nick.skin; 2 | 3 | import dev.pgm.community.Community; 4 | import org.bukkit.Skin; 5 | import org.bukkit.entity.Player; 6 | 7 | public class SkinManager { 8 | 9 | private SkinCache cache; 10 | 11 | public SkinManager() { 12 | this.cache = new SkinCache(); 13 | Community.get().registerListener(cache); 14 | } 15 | 16 | public void setSkin(Player player, Skin skin) { 17 | cache.onSkinRefresh(player, skin); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/party/MapParty.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.party; 2 | 3 | import dev.pgm.community.party.exceptions.MapPartySetupException; 4 | import dev.pgm.community.party.hosts.MapPartyHosts; 5 | import dev.pgm.community.party.settings.MapPartySettings; 6 | import java.time.Duration; 7 | import java.time.Instant; 8 | import java.util.List; 9 | import net.kyori.adventure.text.Component; 10 | import org.bukkit.command.CommandSender; 11 | import org.bukkit.event.player.PlayerJoinEvent; 12 | import org.bukkit.event.player.PlayerQuitEvent; 13 | import org.jetbrains.annotations.Nullable; 14 | import tc.oc.pgm.api.map.MapInfo; 15 | 16 | public interface MapParty { 17 | 18 | Component getStyledName(); 19 | 20 | MapPartyType getEventType(); 21 | 22 | String getName(); 23 | 24 | void setName(String name); 25 | 26 | String getDescription(); 27 | 28 | void setDescription(String description); 29 | 30 | boolean shouldAutoScale(); 31 | 32 | void setAutoScaling(boolean autoScaling); 33 | 34 | @Nullable 35 | Duration getLength(); 36 | 37 | void setLength(Duration length); 38 | 39 | MapPartyHosts getHosts(); 40 | 41 | boolean isRunning(); 42 | 43 | Instant getStartTime(); 44 | 45 | void start(CommandSender sender); 46 | 47 | void stop(CommandSender sender); 48 | 49 | void restart(CommandSender sender); 50 | 51 | void setup(CommandSender sender) throws MapPartySetupException; 52 | 53 | boolean isSetup(); 54 | 55 | void setSetup(boolean setup); 56 | 57 | void addMap(MapInfo map); 58 | 59 | void removeMap(MapInfo map); 60 | 61 | boolean isMapAdded(MapInfo map); 62 | 63 | boolean canAddMaps(); 64 | 65 | List getCustomMaps(); 66 | 67 | MapPartySettings getSettings(); 68 | 69 | void onLogin(PlayerJoinEvent event); 70 | 71 | void onQuit(PlayerQuitEvent event); 72 | } 73 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/party/MapPartyStatusType.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.party; 2 | 3 | import static net.kyori.adventure.text.Component.text; 4 | 5 | import net.kyori.adventure.text.Component; 6 | import net.kyori.adventure.text.format.NamedTextColor; 7 | 8 | public enum MapPartyStatusType { 9 | START("started", NamedTextColor.GREEN), 10 | END("stopped", NamedTextColor.RED), 11 | RESTART("restarted", NamedTextColor.DARK_GREEN); 12 | 13 | String name; 14 | NamedTextColor color; 15 | 16 | MapPartyStatusType(String name, NamedTextColor color) { 17 | this.name = name; 18 | this.color = color; 19 | } 20 | 21 | public Component getNameComponent() { 22 | return text(name, color); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/party/MapPartyType.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.party; 2 | 3 | import org.apache.commons.lang.WordUtils; 4 | import org.bukkit.Material; 5 | 6 | public enum MapPartyType { 7 | REGULAR(Material.IRON_INGOT, "Use an existing map pool"), 8 | CUSTOM(Material.GOLD_INGOT, "Select a custom list of maps"); 9 | 10 | private Material material; 11 | private String description; 12 | 13 | MapPartyType(Material material, String description) { 14 | this.material = material; 15 | this.description = description; 16 | } 17 | 18 | public String getName() { 19 | return WordUtils.capitalize(name().toLowerCase()); 20 | } 21 | 22 | public String getDescription() { 23 | return description; 24 | } 25 | 26 | public Material getMaterial() { 27 | return material; 28 | } 29 | 30 | public static MapPartyType parse(String name) { 31 | if (name.toLowerCase().equalsIgnoreCase("custom")) { 32 | return MapPartyType.CUSTOM; 33 | } 34 | return MapPartyType.REGULAR; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/party/events/MapPartyCreateEvent.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.party.events; 2 | 3 | import dev.pgm.community.party.MapParty; 4 | import org.bukkit.command.CommandSender; 5 | 6 | public class MapPartyCreateEvent extends MapPartyEvent { 7 | 8 | public MapPartyCreateEvent(MapParty party, CommandSender sender) { 9 | super(party, sender); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/party/events/MapPartyEndEvent.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.party.events; 2 | 3 | import dev.pgm.community.party.MapParty; 4 | import org.bukkit.command.CommandSender; 5 | 6 | public class MapPartyEndEvent extends MapPartyEvent { 7 | 8 | public MapPartyEndEvent(MapParty party, CommandSender sender) { 9 | super(party, sender); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/party/events/MapPartyEvent.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.party.events; 2 | 3 | import dev.pgm.community.events.CommunityEvent; 4 | import dev.pgm.community.party.MapParty; 5 | import org.bukkit.command.CommandSender; 6 | 7 | public abstract class MapPartyEvent extends CommunityEvent { 8 | 9 | private final MapParty party; 10 | private final CommandSender sender; 11 | 12 | public MapPartyEvent(MapParty party, CommandSender sender) { 13 | this.party = party; 14 | this.sender = sender; 15 | } 16 | 17 | public MapParty getParty() { 18 | return party; 19 | } 20 | 21 | public CommandSender getSender() { 22 | return sender; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/party/events/MapPartyRestartEvent.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.party.events; 2 | 3 | import dev.pgm.community.party.MapParty; 4 | import org.bukkit.command.CommandSender; 5 | 6 | public class MapPartyRestartEvent extends MapPartyEvent { 7 | 8 | public MapPartyRestartEvent(MapParty party, CommandSender sender) { 9 | super(party, sender); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/party/events/MapPartyStartEvent.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.party.events; 2 | 3 | import dev.pgm.community.party.MapParty; 4 | import org.bukkit.command.CommandSender; 5 | 6 | public class MapPartyStartEvent extends MapPartyEvent { 7 | 8 | public MapPartyStartEvent(MapParty party, CommandSender sender) { 9 | super(party, sender); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/party/exceptions/MapPartyException.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.party.exceptions; 2 | 3 | import dev.pgm.community.party.MapParty; 4 | 5 | public abstract class MapPartyException extends Exception { 6 | 7 | private MapParty party; 8 | 9 | public MapPartyException(MapParty party, String error) { 10 | super(error); 11 | this.party = party; 12 | } 13 | 14 | public MapParty getParty() { 15 | return party; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/party/exceptions/MapPartySetupException.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.party.exceptions; 2 | 3 | import dev.pgm.community.party.MapParty; 4 | 5 | public class MapPartySetupException extends MapPartyException { 6 | 7 | public MapPartySetupException(String error, MapParty party) { 8 | super(party, error); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/party/menu/MapPartyTypeSelectionMenu.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.party.menu; 2 | 3 | import com.google.common.collect.Lists; 4 | import dev.pgm.community.menu.StaticMenuItem; 5 | import dev.pgm.community.party.MapPartyType; 6 | import dev.pgm.community.party.feature.MapPartyFeature; 7 | import fr.minuskube.inv.ClickableItem; 8 | import fr.minuskube.inv.content.InventoryContents; 9 | import org.bukkit.Bukkit; 10 | import org.bukkit.entity.Player; 11 | import org.bukkit.inventory.ItemStack; 12 | 13 | public class MapPartyTypeSelectionMenu extends MapPartyMenu { 14 | 15 | private static final String TITLE = "&a&lSelect mode&8:"; 16 | private static final int ROWS = 3; 17 | private static final boolean HOST_ONLY = false; 18 | 19 | public MapPartyTypeSelectionMenu(MapPartyFeature feature, Player viewer) { 20 | super(feature, TITLE, ROWS, HOST_ONLY, viewer); 21 | } 22 | 23 | @Override 24 | public void init(Player player, InventoryContents contents) { 25 | int[] SLOTS = {2, 6}; 26 | 27 | int index = 0; 28 | for (MapPartyType type : MapPartyType.values()) { 29 | contents.set( 30 | 1, 31 | SLOTS[index++], 32 | ClickableItem.of( 33 | getPartyItem(type), 34 | c -> { 35 | Bukkit.dispatchCommand(player, "event create " + type.name()); 36 | })); 37 | } 38 | this.addBackButton(contents); 39 | } 40 | 41 | private ItemStack getPartyItem(MapPartyType type) { 42 | return new StaticMenuItem( 43 | type.getMaterial(), 44 | "&a" + type.getName(), 45 | Lists.newArrayList( 46 | "&7" + type.getDescription(), "", "&7Click to select &a" + type.getName())) 47 | .getItemStack(); 48 | } 49 | 50 | @Override 51 | public void update(Player player, InventoryContents contents) {} 52 | } 53 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/party/presets/MapPartyPreset.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.party.presets; 2 | 3 | import static tc.oc.pgm.util.text.TextParser.parseDuration; 4 | 5 | import dev.pgm.community.party.MapPartyType; 6 | import java.time.Duration; 7 | import java.util.List; 8 | import org.bukkit.configuration.ConfigurationSection; 9 | 10 | public class MapPartyPreset { 11 | 12 | private final String name; 13 | private final String description; 14 | private final Duration duration; 15 | private final String pool; 16 | private final List maps; 17 | 18 | public static MapPartyPreset of(ConfigurationSection section) { 19 | return new MapPartyPreset( 20 | section.getString("name"), 21 | section.getString("description"), 22 | parseDuration(section.getString("duration")), 23 | section.getString("pool"), 24 | section.getStringList("maps")); 25 | } 26 | 27 | public MapPartyPreset( 28 | String name, String description, Duration duration, String pool, List maps) { 29 | this.name = name; 30 | this.description = description; 31 | this.duration = duration; 32 | this.pool = pool; 33 | this.maps = maps; 34 | } 35 | 36 | public String getName() { 37 | return name; 38 | } 39 | 40 | public String getDescription() { 41 | return description; 42 | } 43 | 44 | public Duration getDuration() { 45 | return duration; 46 | } 47 | 48 | public String getPool() { 49 | return pool; 50 | } 51 | 52 | public List getMaps() { 53 | return maps; 54 | } 55 | 56 | public MapPartyType getType() { 57 | return (getPool() == null || getPool().isEmpty()) ? MapPartyType.CUSTOM : MapPartyType.REGULAR; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/party/settings/MapPartySettings.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.party.settings; 2 | 3 | import dev.pgm.community.party.MapPartyConfig; 4 | import dev.pgm.community.utils.compatibility.Materials; 5 | import org.bukkit.Material; 6 | 7 | public class MapPartySettings { 8 | 9 | private PartyBooleanSetting showLoginMessage; 10 | private PartyBooleanSetting showPartyNotifications; 11 | private PartyBooleanSetting autoscalingTeams; 12 | 13 | public MapPartySettings(MapPartyConfig config) { 14 | this.showLoginMessage = new PartyBooleanSetting( 15 | "Login Message", 16 | "Display a login welcome when party is active", 17 | config.showLoginMessage(), 18 | Material.SIGN, 19 | Material.BARRIER); 20 | this.showPartyNotifications = new PartyBooleanSetting( 21 | "Notification", 22 | "Broadcast announcements related to party", 23 | config.showPartyNotifications(), 24 | Materials.BOOK_AND_QUILL, 25 | Material.BARRIER); 26 | this.autoscalingTeams = new PartyBooleanSetting( 27 | "Autoscaling Teams", 28 | "Automatically resize teams on match cycle", 29 | true, 30 | Materials.GOLD_PLATE, 31 | Materials.WOOD_PLATE); 32 | } 33 | 34 | public PartyBooleanSetting getShowLoginMessage() { 35 | return showLoginMessage; 36 | } 37 | 38 | public PartyBooleanSetting getShowPartyNotifications() { 39 | return showPartyNotifications; 40 | } 41 | 42 | public PartyBooleanSetting getAutoscalingTeams() { 43 | return autoscalingTeams; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/party/settings/PartyBooleanSetting.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.party.settings; 2 | 3 | import org.bukkit.Material; 4 | 5 | public class PartyBooleanSetting extends PartySetting { 6 | 7 | private Material trueIcon; 8 | private Material falseIcon; 9 | 10 | private boolean value; 11 | 12 | public PartyBooleanSetting( 13 | String name, String description, boolean def, Material trueIcon, Material falseIcon) { 14 | super(name, description); 15 | this.value = def; 16 | this.trueIcon = trueIcon; 17 | this.falseIcon = falseIcon; 18 | } 19 | 20 | public boolean getValue() { 21 | return value; 22 | } 23 | 24 | public void setValue(boolean value) { 25 | this.value = value; 26 | } 27 | 28 | @Override 29 | public Material getIcon() { 30 | return getValue() ? trueIcon : falseIcon; 31 | } 32 | 33 | public void toggle() { 34 | setValue(!getValue()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/party/settings/PartySetting.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.party.settings; 2 | 3 | import org.bukkit.Material; 4 | 5 | public abstract class PartySetting { 6 | 7 | private String name; 8 | private String description; 9 | 10 | public PartySetting(String name, String description) { 11 | this.name = name; 12 | this.description = description; 13 | } 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public String getDescription() { 20 | return description; 21 | } 22 | 23 | public abstract Material getIcon(); 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/polls/Poll.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.polls; 2 | 3 | import dev.pgm.community.polls.ending.EndAction; 4 | import java.time.Duration; 5 | import java.time.Instant; 6 | import java.util.List; 7 | import java.util.UUID; 8 | import net.kyori.adventure.text.Component; 9 | import org.bukkit.entity.Player; 10 | 11 | public interface Poll { 12 | 13 | Component getQuestion(); 14 | 15 | UUID getCreator(); 16 | 17 | Instant getStartTime(); 18 | 19 | Instant getEndTime(); 20 | 21 | void setEndTime(Instant time); 22 | 23 | boolean isRunning(); 24 | 25 | List getEndAction(); 26 | 27 | boolean vote(Player player, String option); 28 | 29 | long getTotalVotes(); 30 | 31 | PollThreshold getRequiredThreshold(); 32 | 33 | Duration getTimeLeft(); 34 | 35 | boolean hasVoted(Player player); 36 | 37 | void tallyVotes(); 38 | 39 | void start(); 40 | 41 | Component getVoteButtons(boolean compact); 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/polls/PollConfig.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.polls; 2 | 3 | import static tc.oc.pgm.util.text.TextParser.parseDuration; 4 | 5 | import dev.pgm.community.feature.config.FeatureConfigImpl; 6 | import java.time.Duration; 7 | import org.bukkit.configuration.Configuration; 8 | 9 | public class PollConfig extends FeatureConfigImpl { 10 | 11 | private static final String KEY = "polls"; 12 | 13 | private Duration duration; 14 | private PollThreshold threshold; 15 | 16 | public PollConfig(Configuration config) { 17 | super(KEY, config); 18 | } 19 | 20 | public Duration getDuration() { 21 | return duration; 22 | } 23 | 24 | public PollThreshold getThreshold() { 25 | return threshold; 26 | } 27 | 28 | @Override 29 | public void reload(Configuration config) { 30 | super.reload(config); 31 | this.duration = parseDuration(config.getString(KEY + ".duration")); 32 | this.threshold = PollThreshold.valueOf(config.getString(KEY + ".threshold").toUpperCase()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/polls/PollThreshold.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.polls; 2 | 3 | import static net.kyori.adventure.text.Component.text; 4 | 5 | import net.kyori.adventure.text.Component; 6 | import net.kyori.adventure.text.format.NamedTextColor; 7 | 8 | public enum PollThreshold { 9 | CLEAR_MINORITY("Clear Minority", 0.25, NamedTextColor.DARK_GREEN), 10 | SIMPLE("Simple Majority", 0.5, NamedTextColor.GREEN), 11 | THREE_FIFTHS("3/5 Majority", 0.6, NamedTextColor.GOLD), 12 | TWO_THIRDS("2/3 Majority", 0.6667, NamedTextColor.RED), 13 | STRONG_MAJORITY("Strong Majority", 0.75, NamedTextColor.DARK_RED); 14 | 15 | private final String displayName; 16 | private final double value; 17 | private final NamedTextColor color; 18 | 19 | PollThreshold(String displayName, double value, NamedTextColor color) { 20 | this.displayName = displayName; 21 | this.value = value; 22 | this.color = color; 23 | } 24 | 25 | public String getName() { 26 | return displayName; 27 | } 28 | 29 | public double getValue() { 30 | return value; 31 | } 32 | 33 | public Component toComponent() { 34 | return text(displayName) 35 | .color(color) 36 | .append(text(" (", NamedTextColor.GRAY)) 37 | .append(text((int) (value * 100) + "%", color)) 38 | .append(text(")", NamedTextColor.GRAY)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/polls/commands/PollVoteCommands.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.polls.commands; 2 | 3 | import dev.pgm.community.Community; 4 | import dev.pgm.community.CommunityCommand; 5 | import dev.pgm.community.polls.feature.PollFeature; 6 | import dev.pgm.community.utils.CommandAudience; 7 | import org.bukkit.entity.Player; 8 | import tc.oc.pgm.lib.org.incendo.cloud.annotation.specifier.Greedy; 9 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Argument; 10 | import tc.oc.pgm.lib.org.incendo.cloud.annotations.Command; 11 | 12 | public class PollVoteCommands extends CommunityCommand { 13 | 14 | public static final String COMMAND = "pollvote"; 15 | 16 | private final PollFeature polls; 17 | 18 | public PollVoteCommands() { 19 | this.polls = Community.get().getFeatures().getPolls(); 20 | } 21 | 22 | @Command(COMMAND + "

See https://stackoverflow.com/a/4660195 for more details. 20 | */ 21 | final class UTF8Control extends ResourceBundle.Control { 22 | 23 | /** {@inheritDoc} */ 24 | public ResourceBundle newBundle( 25 | String baseName, Locale locale, String format, ClassLoader loader, boolean reload) 26 | throws IOException { 27 | // The below is a copy of the default implementation. 28 | String bundleName = toBundleName(baseName, locale); 29 | String resourceName = toResourceName(bundleName, "properties"); 30 | ResourceBundle bundle = null; 31 | InputStream stream = null; 32 | if (reload) { 33 | URL url = loader.getResource(resourceName); 34 | if (url != null) { 35 | URLConnection connection = url.openConnection(); 36 | if (connection != null) { 37 | connection.setUseCaches(false); 38 | stream = connection.getInputStream(); 39 | } 40 | } 41 | } else { 42 | stream = loader.getResourceAsStream(resourceName); 43 | } 44 | if (stream != null) { 45 | try { 46 | // Only this line is changed to make it to read properties files as UTF-8. 47 | bundle = new PropertyResourceBundle(new InputStreamReader(stream, StandardCharsets.UTF_8)); 48 | } finally { 49 | stream.close(); 50 | } 51 | } 52 | return bundle; 53 | } 54 | 55 | @Override 56 | public List getCandidateLocales(String name, Locale locale) { 57 | return Arrays.asList(Locale.ROOT); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/users/UserProfile.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.users; 2 | 3 | import dev.pgm.community.sessions.Session; 4 | import java.time.Instant; 5 | import java.util.UUID; 6 | import java.util.concurrent.CompletableFuture; 7 | 8 | /** 9 | * UserProfile 10 | * 11 | *

A profile that holds data related to a user 12 | */ 13 | public interface UserProfile { 14 | 15 | /** 16 | * Get the player's UUID 17 | * 18 | * @return player UUID 19 | */ 20 | UUID getId(); 21 | 22 | /** 23 | * Get the player's last known username Note: If username has changed, will be updated next time 24 | * they login 25 | * 26 | * @return player username 27 | */ 28 | String getUsername(); 29 | 30 | /** 31 | * Get the player's first login date 32 | * 33 | * @return Date of first login 34 | */ 35 | Instant getFirstLogin(); 36 | 37 | /** 38 | * Get the player's session 39 | * 40 | * @return The player's session 41 | */ 42 | CompletableFuture getLatestSession(boolean ignoreDisguisedSessions); 43 | 44 | /** 45 | * Get the player's number of server joins 46 | * 47 | * @return Player join count 48 | */ 49 | int getJoinCount(); 50 | 51 | /** 52 | * Set the player's username 53 | * 54 | * @param username Player's username 55 | * @see {@link Player#getName} 56 | */ 57 | void setUsername(String username); 58 | 59 | /** 60 | * Sets the player's first login date 61 | * 62 | * @param now The time of login 63 | */ 64 | void setFirstLogin(Instant now); 65 | 66 | /** Increases the join count by 1 */ 67 | void incJoinCount(); 68 | } 69 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/users/UserProfileImpl.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.users; 2 | 3 | import dev.pgm.community.Community; 4 | import dev.pgm.community.sessions.Session; 5 | import dev.pgm.community.sessions.feature.SessionFeature; 6 | import java.time.Instant; 7 | import java.util.UUID; 8 | import java.util.concurrent.CompletableFuture; 9 | 10 | public class UserProfileImpl implements UserProfile { 11 | 12 | private UUID playerId; 13 | private String username; 14 | private Instant firstLogin; 15 | private int joinCount; 16 | 17 | public UserProfileImpl(UUID playerId, String username) { 18 | this(playerId, username, Instant.now(), 1); 19 | } 20 | 21 | public UserProfileImpl(UUID playerId, String username, Instant firstLogin, int joinCount) { 22 | this.playerId = playerId; 23 | this.username = username; 24 | this.firstLogin = firstLogin; 25 | this.joinCount = joinCount; 26 | } 27 | 28 | @Override 29 | public UUID getId() { 30 | return playerId; 31 | } 32 | 33 | @Override 34 | public String getUsername() { 35 | return username; 36 | } 37 | 38 | @Override 39 | public Instant getFirstLogin() { 40 | return firstLogin; 41 | } 42 | 43 | @Override 44 | public CompletableFuture getLatestSession(boolean ignoreDisguisedSessions) { 45 | SessionFeature sessions = Community.get().getFeatures().getSessions(); 46 | if (!sessions.isEnabled()) return CompletableFuture.completedFuture(null); 47 | 48 | return sessions.getLatestSession(getId(), ignoreDisguisedSessions); 49 | } 50 | 51 | @Override 52 | public int getJoinCount() { 53 | return joinCount; 54 | } 55 | 56 | @Override 57 | public void setUsername(String username) { 58 | this.username = username; 59 | } 60 | 61 | @Override 62 | public void setFirstLogin(Instant now) { 63 | this.firstLogin = now; 64 | } 65 | 66 | @Override 67 | public void incJoinCount() { 68 | this.joinCount++; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/users/UserProfileWithSessionCallback.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.users; 2 | 3 | import dev.pgm.community.sessions.Session; 4 | 5 | public interface UserProfileWithSessionCallback { 6 | 7 | public void run(UserProfile profile, Session session); 8 | } 9 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/users/UsersConfig.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.users; 2 | 3 | import dev.pgm.community.feature.config.FeatureConfigImpl; 4 | import java.util.List; 5 | import org.bukkit.configuration.Configuration; 6 | 7 | public class UsersConfig extends FeatureConfigImpl { 8 | 9 | public static final String KEY = "users"; 10 | 11 | private List firstJoinCommands; 12 | 13 | public UsersConfig(Configuration config) { 14 | super(KEY, config); 15 | } 16 | 17 | public List getFirstJoinCommands() { 18 | return firstJoinCommands; 19 | } 20 | 21 | @Override 22 | public void reload(Configuration config) { 23 | super.reload(config); 24 | 25 | this.firstJoinCommands = config.getStringList(getKey() + ".first-join"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/users/feature/UsersFeatureBase.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.users.feature; 2 | 3 | import com.google.common.cache.Cache; 4 | import com.google.common.cache.CacheBuilder; 5 | import dev.pgm.community.Community; 6 | import dev.pgm.community.feature.FeatureBase; 7 | import dev.pgm.community.users.UserProfile; 8 | import dev.pgm.community.users.UsersConfig; 9 | import dev.pgm.community.users.listeners.UserProfileLoginListener; 10 | import java.util.Optional; 11 | import java.util.UUID; 12 | import java.util.logging.Logger; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | public abstract class UsersFeatureBase extends FeatureBase implements UsersFeature { 16 | 17 | protected final Cache names; 18 | protected final Cache profiles; 19 | 20 | public UsersFeatureBase(UsersConfig config, Logger logger, String featureName) { 21 | super(config, logger, featureName); 22 | this.profiles = CacheBuilder.newBuilder().build(); 23 | this.names = CacheBuilder.newBuilder().build(); 24 | 25 | // Auto register username change listener 26 | Community.get().registerListener(new UserProfileLoginListener(this)); 27 | } 28 | 29 | public UsersConfig getUsersConfig() { 30 | return (UsersConfig) getConfig(); 31 | } 32 | 33 | @Override 34 | public @Nullable String getUsername(UUID id) { 35 | return names.getIfPresent(id); 36 | } 37 | 38 | @Override 39 | public Optional getId(String username) { 40 | return names.asMap().entrySet().stream() 41 | .filter(e -> e.getValue().equalsIgnoreCase(username)) 42 | .map(e -> e.getKey()) 43 | .findAny(); 44 | } 45 | 46 | @Override 47 | public UserProfile getProfile(UUID id) { 48 | return profiles.getIfPresent(id); 49 | } 50 | 51 | @Override 52 | public void setName(UUID id, String name) { 53 | names.put(id, name); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/users/services/UserQuery.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.users.services; 2 | 3 | public interface UserQuery { 4 | 5 | static final String TABLE_FIELDS = 6 | "(id VARCHAR(36) PRIMARY KEY, name VARCHAR(16), first_join LONG, join_count INT)"; 7 | static final String TABLE_NAME = "users"; 8 | 9 | static final String INSERT_USER_QUERY = 10 | "INSERT INTO " + TABLE_NAME + "(id, name, first_join, join_count) VALUES (?,?,?,?)"; 11 | 12 | static final String USERNAME_QUERY = 13 | "SELECT * from " + TABLE_NAME + " WHERE LOWER(name) = LOWER(?) LIMIT 1"; 14 | static final String PLAYERID_QUERY = "SELECT * from " + TABLE_NAME + " WHERE id = ? LIMIT 1"; 15 | 16 | static final String UPDATE_USER_QUERY = 17 | "UPDATE " + TABLE_NAME + " SET name = ?, join_count = ? WHERE id = ? "; 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/utils/AFKDetection.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.utils; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.plugin.Plugin; 6 | import tc.oc.occ.afk.AFKPlugin; 7 | 8 | public class AFKDetection { 9 | 10 | private Plugin afkPlugin; 11 | 12 | public AFKDetection() { 13 | afkPlugin = Bukkit.getPluginManager().getPlugin("AFK"); 14 | } 15 | 16 | public boolean isAFK(Player player) { 17 | if (afkPlugin != null && afkPlugin.isEnabled()) { 18 | return isPlayerAFK(player); 19 | } 20 | return false; 21 | } 22 | 23 | private boolean isPlayerAFK(Player player) { 24 | return AFKPlugin.get() != null && AFKPlugin.get().getManager().isAFK(player); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/utils/CenterUtils.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.utils; 2 | 3 | import static net.kyori.adventure.text.Component.text; 4 | 5 | import com.google.common.base.Strings; 6 | import net.kyori.adventure.text.Component; 7 | import tc.oc.pgm.util.LegacyFormatUtils; 8 | import tc.oc.pgm.util.text.TextTranslations; 9 | 10 | public class CenterUtils { 11 | 12 | public static Component centerComponent(Component component) { 13 | int textWidth = 14 | LegacyFormatUtils.pixelWidth(TextTranslations.translateLegacy(component.asComponent())); 15 | int spaceCount = 16 | Math.max( 17 | 0, 18 | ((LegacyFormatUtils.MAX_CHAT_WIDTH - textWidth) / 2 + 1) 19 | / (LegacyFormatUtils.SPACE_PIXEL_WIDTH + 1)); 20 | String line = Strings.repeat(" ", spaceCount); 21 | return text().append(text(line)).append(component).build(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/utils/CommandAudience.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.utils; 2 | 3 | import java.util.Optional; 4 | import java.util.UUID; 5 | import net.kyori.adventure.text.Component; 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.entity.Player; 9 | import org.jetbrains.annotations.Nullable; 10 | import tc.oc.pgm.util.Audience; 11 | import tc.oc.pgm.util.named.NameStyle; 12 | import tc.oc.pgm.util.player.PlayerComponent; 13 | 14 | public class CommandAudience { 15 | 16 | private Audience audience; 17 | private CommandSender sender; 18 | 19 | public static CommandAudience CONSOLE = new CommandAudience(Bukkit.getConsoleSender()); 20 | 21 | public CommandAudience(CommandSender sender) { 22 | this.sender = sender; 23 | this.audience = Audience.get(sender); 24 | } 25 | 26 | public Optional getId() { 27 | return Optional.ofNullable(sender instanceof Player ? ((Player) sender).getUniqueId() : null); 28 | } 29 | 30 | public CommandSender getSender() { 31 | return sender; 32 | } 33 | 34 | public Audience getAudience() { 35 | return audience; 36 | } 37 | 38 | public Component getStyledName() { 39 | return getStyledName(NameStyle.FANCY); 40 | } 41 | 42 | public Component getStyledName(NameStyle style) { 43 | return PlayerComponent.player(sender, style); 44 | } 45 | 46 | public @Nullable Player getPlayer() { 47 | return isPlayer() ? (Player) sender : null; 48 | } 49 | 50 | public boolean isPlayer() { 51 | return getSender() instanceof Player; 52 | } 53 | 54 | public void sendMessage(Component message) { 55 | audience.sendMessage(message); 56 | } 57 | 58 | public void sendWarning(Component message) { 59 | audience.sendWarning(message); 60 | } 61 | 62 | public boolean hasPermission(String permission) { 63 | return isPlayer() ? getPlayer().hasPermission(permission) : true; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/utils/DatabaseUtils.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.utils; 2 | 3 | import co.aikar.idb.DbRow; 4 | 5 | public class DatabaseUtils { 6 | 7 | public static boolean parseBoolean(DbRow row, String fieldName) throws ClassCastException { 8 | Object obj = row.get(fieldName); 9 | if (obj instanceof Integer) { 10 | int activeInt = (Integer) obj; 11 | return (activeInt != 0); 12 | } else if (obj instanceof Boolean) { 13 | return (Boolean) obj; 14 | } else { 15 | throw new ClassCastException( 16 | "Unexpected type for '" + fieldName + "': " + obj.getClass().getName()); 17 | } 18 | } 19 | 20 | public static long parseLong(DbRow row, String fieldName) throws ClassCastException { 21 | Object obj = row.get(fieldName); 22 | if (obj instanceof String) { 23 | String rawLong = (String) obj; 24 | return Long.parseLong(rawLong); 25 | } else if (obj instanceof Long) { 26 | return (Long) obj; 27 | } else if (obj instanceof Integer) { 28 | return (Integer) obj; 29 | } else { 30 | throw new ClassCastException( 31 | "Unexpected type for '" + fieldName + "': " + obj.getClass().getName()); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/utils/NameUtils.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.utils; 2 | 3 | import java.util.UUID; 4 | import java.util.regex.Pattern; 5 | 6 | public class NameUtils { 7 | 8 | static final Pattern NAME_REGEX = Pattern.compile("[a-zA-Z0-9_]{1,16}"); 9 | 10 | public static boolean isMinecraftName(String name) { 11 | return NAME_REGEX.matcher(name).matches(); 12 | } 13 | 14 | public static boolean isPlayerId(String uuid) { 15 | try { 16 | UUID playerId = UUID.fromString(uuid); 17 | return true; 18 | } catch (IllegalArgumentException e) { 19 | return false; 20 | } 21 | } 22 | 23 | public static boolean isIdentifier(String input) { 24 | return isMinecraftName(input) || isPlayerId(input); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/utils/NetworkUtils.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.utils; 2 | 3 | import static net.kyori.adventure.text.Component.empty; 4 | import static net.kyori.adventure.text.Component.text; 5 | 6 | import dev.pgm.community.Community; 7 | import net.kyori.adventure.text.Component; 8 | import net.kyori.adventure.text.event.ClickEvent; 9 | import net.kyori.adventure.text.event.HoverEvent; 10 | import net.kyori.adventure.text.format.NamedTextColor; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | public class NetworkUtils { 14 | 15 | public static String getServer() { 16 | return Community.get().getServerConfig().getServerId(); 17 | } 18 | 19 | public static Component formatServer(String server) { 20 | return text() 21 | .append(text(server, NamedTextColor.GREEN)) 22 | .hoverEvent(HoverEvent.showText(text() 23 | .append(text("Click to join ")) 24 | .append(text(server, NamedTextColor.AQUA)) 25 | .color(NamedTextColor.GRAY) 26 | .build())) 27 | .clickEvent(ClickEvent.runCommand("/server " + server)) 28 | .build(); 29 | } 30 | 31 | public static Component server(String server) { 32 | return isLocal(server) ? empty() : formatServer(server); 33 | } 34 | 35 | private static boolean isLocal(String request) { 36 | return request == null || request.equalsIgnoreCase(getServer()); 37 | } 38 | 39 | @Nullable 40 | public static String getServerVar(String def) { 41 | String id = System.getenv("SERVER_NAME"); 42 | return (id != null && !id.isEmpty()) ? id : def; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/utils/SkullUtils.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.utils; 2 | 3 | import com.mojang.authlib.GameProfile; 4 | import com.mojang.authlib.properties.Property; 5 | import com.mojang.authlib.properties.PropertyMap; 6 | import dev.pgm.community.utils.compatibility.Materials; 7 | import java.lang.reflect.Field; 8 | import java.util.Arrays; 9 | import java.util.Base64; 10 | import java.util.UUID; 11 | import org.bukkit.SkullType; 12 | import org.bukkit.inventory.ItemFlag; 13 | import org.bukkit.inventory.ItemStack; 14 | import org.bukkit.inventory.meta.SkullMeta; 15 | import tc.oc.pgm.util.bukkit.BukkitUtils; 16 | 17 | public class SkullUtils { 18 | 19 | public static ItemStack customSkull(String url, String displayName, String... lore) { 20 | ItemStack head = new ItemStack(Materials.SKULL_ITEM); 21 | head.setDurability((short) SkullType.PLAYER.ordinal()); 22 | if (url.isEmpty()) { 23 | return head; 24 | } 25 | 26 | SkullMeta headMeta = (SkullMeta) head.getItemMeta(); 27 | GameProfile profile = createGameProfile(url); 28 | Field profileField; 29 | try { 30 | profileField = headMeta.getClass().getDeclaredField("profile"); 31 | profileField.setAccessible(true); 32 | profileField.set(headMeta, profile); 33 | } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException ignored) { 34 | ignored.printStackTrace(); 35 | } 36 | headMeta.setDisplayName(BukkitUtils.colorize(displayName)); 37 | headMeta.setLore(MessageUtils.colorizeList(Arrays.asList(lore))); 38 | headMeta.addItemFlags(ItemFlag.values()); 39 | head.setItemMeta(headMeta); 40 | return head; 41 | } 42 | 43 | private static GameProfile createGameProfile(String url) { 44 | GameProfile profile = new GameProfile(UUID.randomUUID(), null); 45 | PropertyMap propertyMap = profile.getProperties(); 46 | if (propertyMap == null) { 47 | return null; 48 | } 49 | 50 | byte[] encodedData = Base64.getEncoder() 51 | .encode(String.format("{textures:{SKIN:{url:\"%s\"}}}", url).getBytes()); 52 | propertyMap.put("textures", new Property("textures", new String(encodedData))); 53 | 54 | return profile; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/utils/VisibilityUtils.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.utils; 2 | 3 | import java.util.UUID; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.entity.Player; 6 | import tc.oc.pgm.api.integration.Integration; 7 | 8 | public class VisibilityUtils { 9 | 10 | public static boolean isDisguised(UUID playerId) { 11 | Player player = Bukkit.getPlayer(playerId); 12 | return player != null && isDisguised(player); 13 | } 14 | 15 | public static boolean isDisguised(Player player) { 16 | return Integration.isVanished(player) || Integration.getNick(player) != null; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/utils/compatibility/Enchantments.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.utils.compatibility; 2 | 3 | import org.bukkit.enchantments.Enchantment; 4 | import tc.oc.pgm.util.bukkit.BukkitUtils; 5 | 6 | public interface Enchantments { 7 | Enchantment INFINITY = parse("ARROW_INFINITE", "infinity"); 8 | Enchantment LUCK_OF_THE_SEA = parse("LUCK", "luck_of_the_sea"); 9 | 10 | private static Enchantment parse(String... names) { 11 | return BukkitUtils.parse(Enchantment::getByName, names); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/utils/compatibility/EntityTypes.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.utils.compatibility; 2 | 3 | import org.bukkit.entity.EntityType; 4 | import tc.oc.pgm.util.bukkit.BukkitUtils; 5 | 6 | public interface EntityTypes { 7 | EntityType PIG_ZOMBIE = parse("PIG_ZOMBIE", "ZOMBIFIED_PIGLIN"); 8 | 9 | private static EntityType parse(String... names) { 10 | return BukkitUtils.parse(EntityType::valueOf, names); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/utils/compatibility/PotionEffects.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.utils.compatibility; 2 | 3 | import org.bukkit.potion.PotionEffectType; 4 | import tc.oc.pgm.util.bukkit.BukkitUtils; 5 | 6 | public interface PotionEffects { 7 | PotionEffectType NAUSEA = parse("CONFUSION", "nausea"); 8 | PotionEffectType RESISTANCE = parse("DAMAGE_RESISTANCE", "resistance"); 9 | PotionEffectType HASTE = parse("FAST_DIGGING", "HASTE"); 10 | PotionEffectType STRENGTH = parse("INCREASE_DAMAGE", "strength"); 11 | PotionEffectType JUMP_BOOST = parse("JUMP", "jump_boost"); 12 | PotionEffectType SLOWNESS = parse("SLOW", "slowness"); 13 | PotionEffectType MINING_FATIGUE = parse("SLOW_DIGGING", "mining_fatigue"); 14 | 15 | private static PotionEffectType parse(String... names) { 16 | return BukkitUtils.parse(PotionEffectType::getByName, names); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/utils/gson/GsonProvider.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.utils.gson; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import dev.pgm.community.utils.gson.types.DurationConverter; 6 | import java.time.Duration; 7 | 8 | public class GsonProvider { 9 | 10 | public static Gson get() { 11 | return new GsonBuilder().registerTypeAdapter(Duration.class, new DurationConverter()).create(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/utils/gson/types/DurationConverter.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.utils.gson.types; 2 | 3 | import com.google.gson.JsonDeserializationContext; 4 | import com.google.gson.JsonDeserializer; 5 | import com.google.gson.JsonElement; 6 | import com.google.gson.JsonParseException; 7 | import com.google.gson.JsonPrimitive; 8 | import com.google.gson.JsonSerializationContext; 9 | import com.google.gson.JsonSerializer; 10 | import java.lang.reflect.Type; 11 | import java.time.Duration; 12 | 13 | public class DurationConverter implements JsonSerializer, JsonDeserializer { 14 | 15 | @Override 16 | public JsonElement serialize(Duration src, Type typeOfSrc, JsonSerializationContext context) { 17 | return new JsonPrimitive(src.toString()); 18 | } 19 | 20 | @Override 21 | public Duration deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 22 | throws JsonParseException { 23 | return Duration.parse(json.getAsString()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/dev/pgm/community/utils/ranks/RankUtils.java: -------------------------------------------------------------------------------- 1 | package dev.pgm.community.utils.ranks; 2 | 3 | import dev.pgm.community.Community; 4 | import java.util.List; 5 | import org.bukkit.entity.Player; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | public class RankUtils { 9 | 10 | @Nullable 11 | public static RanksConfig.Rank getHighestLevelRank(Player player) { 12 | List allRanks = 13 | Community.get().getServerConfig().getRanksConfig().getRanks(); 14 | RanksConfig.Rank highestRank = null; 15 | 16 | for (RanksConfig.Rank rank : allRanks) { 17 | if (player.hasPermission(rank.getPermission())) { 18 | if (highestRank == null || rank.getWeight() > highestRank.getWeight()) { 19 | highestRank = rank; 20 | } 21 | } 22 | } 23 | 24 | return highestRank; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: Community 2 | description: ${description} 3 | main: ${mainClass} 4 | version: ${version} (git-${commitHash}) 5 | website: ${url} 6 | author: ${author} 7 | softdepend: [PGM, Environment, AFK] 8 | -------------------------------------------------------------------------------- /core/src/main/resources/strings.properties: -------------------------------------------------------------------------------- 1 | squad.create.success = Successfully created a new party 2 | 3 | squad.invite.sent = Sent party invite to {0} 4 | squad.invite.received = You were invited to {0}'s party {1} {2} 5 | squad.invite.accept = [ACCEPT] 6 | squad.invite.deny = [DENY] 7 | 8 | squad.accept.invited = Joined {0}'s party 9 | squad.accept.leader = {0} has accepted your invitation 10 | 11 | squad.deny.invited = Denied invite to join {0}'s party 12 | squad.deny.leader = {0} has denied your invitation 13 | 14 | squad.leave.success = Successfully left the party 15 | 16 | squad.autojoin = Auto join: {0} (click to toggle) 17 | squad.autojoin.enabled = ENABLED 18 | squad.autojoin.disabled = DISABLED 19 | 20 | squad.list.all = Parties 21 | squad.list.header = {0}'s Party 22 | squad.list.leader = Party leader 23 | squad.list.pending = Pending invite 24 | squad.list.removeHover = Remove player from party 25 | 26 | squad.kicked.leader = Kicked {0} from your party 27 | squad.kicked.player = You were kicked from {0}'s party 28 | 29 | squad.disband.success = You have successfully disbanded your party 30 | squad.disband.empty = Your party disbanded since all players left 31 | 32 | squad.err.alreadyInvited = {0} is already in your squad or has a pending invite 33 | squad.err.alreadyCreated = You're already in a party 34 | squad.err.alreadyInSquad = {0} is already in a party 35 | squad.err.noInvite = No pending invite from {0} was found 36 | squad.err.full = Party is already full or has pending invites ({0}/{1} players) 37 | squad.err.leaderOnly = You must be the party leader to perform this command 38 | squad.err.memberOnly = You are not in a party. Start one with /party 39 | squad.err.notInYourParty = {0} is not in your party 40 | squad.err.noSelfInvite = You can't invite yourself to a party 41 | squad.err.leaderCannotLeave = You cannot leave your own party (you must disband it instead) 42 | squad.err.notEnabled = This feature is not enabled 43 | 44 | squad.warn.autoJoin = Skipped party auto join since you disabled it 45 | squad.warn.afk = Skipped party auto join because you were AFK 46 | squad.warn.manualJoin = Manual join was prevented as it messes with party auto join -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PGMDev/Community/a0e54a95167003b6a0893cf504c043a781675d56/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "community" 2 | 3 | include(":core") 4 | --------------------------------------------------------------------------------