Skip to content

Commit fb1cb91

Browse files
authored
Merge pull request #1 from ModularEnigma/staging
Implement v1 of Mob Hunt
2 parents 1850209 + 8c7b40c commit fb1cb91

File tree

18 files changed

+1624
-0
lines changed

18 files changed

+1624
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.idea
2+
target

dbinit.sql

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
DROP DATABASE IF EXISTS MobHunt;
2+
CREATE DATABASE IF NOT EXISTS MobHunt;
3+
USE MobHunt;
4+
5+
CREATE USER IF NOT EXISTS 'MobHunt'@'%' IDENTIFIED WITH mysql_native_password BY 'PasswordMobHunt321';
6+
FLUSH PRIVILEGES;
7+
GRANT SELECT ON MobHunt.* TO MobHunt@'%';
8+
GRANT INSERT ON MobHunt.* TO MobHunt@'%';
9+
GRANT UPDATE ON MobHunt.* TO MobHunt@'%';
10+
GRANT DELETE ON MobHunt.* TO MobHunt@'%';
11+
12+
CREATE TABLE mobs (
13+
id int AUTO_INCREMENT PRIMARY KEY NOT NULL,
14+
uuid VARCHAR(36),
15+
mobType VARCHAR(100) NOT NULL,
16+
mobsKilled int DEFAULT 1
17+
);
18+
19+
CREATE TABLE points (
20+
uuid VARCHAR(36) PRIMARY KEY NOT NULL,
21+
username VARCHAR(16),
22+
n int DEFAULT 0
23+
);

pom.xml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>com.modularenigma</groupId>
8+
<artifactId>MobHunt</artifactId>
9+
<version>1.0</version>
10+
11+
<properties>
12+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13+
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
14+
</properties>
15+
16+
<build>
17+
<plugins>
18+
<plugin>
19+
<groupId>org.apache.maven.plugins</groupId>
20+
<artifactId>maven-compiler-plugin</artifactId>
21+
<version>3.8.1</version>
22+
<configuration>
23+
<release>17</release>
24+
</configuration>
25+
</plugin>
26+
</plugins>
27+
28+
<resources>
29+
<resource>
30+
<directory>src/main/resources</directory>
31+
<filtering>true</filtering>
32+
</resource>
33+
</resources>
34+
</build>
35+
36+
<repositories>
37+
<repository>
38+
<id>papermc</id>
39+
<url>https://papermc.io/repo/repository/maven-public/</url>
40+
</repository>
41+
</repositories>
42+
43+
<dependencies>
44+
<!-- Paper -->
45+
<dependency>
46+
<groupId>io.papermc.paper</groupId>
47+
<artifactId>paper-api</artifactId>
48+
<version>1.18.2-R0.1-SNAPSHOT</version>
49+
<scope>provided</scope>
50+
<exclusions>
51+
<exclusion>
52+
<groupId>org.bstats</groupId>
53+
<artifactId>bstats-bukkit</artifactId>
54+
</exclusion>
55+
</exclusions>
56+
</dependency>
57+
58+
<!-- MySQL -->
59+
<dependency>
60+
<groupId>mysql</groupId>
61+
<artifactId>mysql-connector-java</artifactId>
62+
<version>8.0.23</version>
63+
</dependency>
64+
65+
<dependency>
66+
<groupId>org.projectlombok</groupId>
67+
<artifactId>lombok</artifactId>
68+
<version>1.18.22</version>
69+
<scope>provided</scope>
70+
</dependency>
71+
</dependencies>
72+
73+
</project>
Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
package com.modularenigma.MobHunt;
2+
3+
import com.modularenigma.MobHunt.helpers.DefaultFontInfo;
4+
import org.bukkit.Bukkit;
5+
import org.bukkit.Sound;
6+
import org.bukkit.command.CommandSender;
7+
import org.bukkit.entity.Player;
8+
9+
import java.util.List;
10+
11+
public class HunterController {
12+
private final MobHuntMain plugin;
13+
14+
public HunterController(MobHuntMain plugin) {
15+
this.plugin = plugin;
16+
}
17+
18+
/**
19+
* For when the player kills a Mob.
20+
* @param player The player who killed the mob.
21+
* @param mobType The mobType the player killed.
22+
* @param points The number of points awarded for killing the mob.
23+
*/
24+
public void mobKilledResponse(Player player, String mobType, int points) {
25+
player.sendMessage(plugin.config().getLangMobKilled()
26+
.replace("%MobType%", mobType)
27+
.replace("%Points%", "" + points)
28+
.replace("%Plural%", points == 1 ? "" : "s"));
29+
}
30+
31+
/**
32+
* For when the player has killed cap number of mobType mobs. This notifies
33+
* the player that they will no longer receive points for killing mobType
34+
* @param player The player who killed the mob
35+
* @param mobType The mobType the player killed
36+
* @param kills The number of kills the player has gotten for said mobtype
37+
* @param killCap The killCap threshold
38+
*/
39+
public void mobKilledCapReachedResponse(Player player, String mobType, int kills, int killCap) {
40+
player.sendMessage(plugin.config().getLangMobKilledCapReached()
41+
.replace("%MobType%", mobType)
42+
.replace("%Kills%", "" + kills)
43+
.replace("%Cap%", "" + killCap));
44+
}
45+
46+
/**
47+
* For when the player wants to see a breakdown of the kills they have gotten
48+
* across all the mobs.
49+
* @param player The player to send the stats to.
50+
* @param stats A (presorted) list of of stats to render.
51+
*/
52+
public void mobStatsResponse(Player player, List<MobHuntQuery.MobStat> stats) {
53+
int centrePixel = minecraftMessageLengthInPixels(
54+
plugin.config().getLangLeaderboardHeader()) / 2;
55+
56+
String title = plugin.config().getLangStatsTitle()
57+
.replace("%Player%", player.getName());
58+
59+
sendMessageInCentre(player, title, centrePixel);
60+
61+
for (MobHuntQuery.MobStat stat : stats) {
62+
String statMessage = plugin.config().getLangStatsFormat()
63+
.replace("%MobType%", stat.mobType())
64+
.replace("%Kills%", "" + stat.mobsKilled());
65+
sendMessageInCentre(player, statMessage, centrePixel);
66+
}
67+
}
68+
69+
/**
70+
* For when a player wants to see the rules of MobHunt.
71+
* @param sender The sender to tell the rules to.
72+
*/
73+
public void mobHelpResponse(CommandSender sender) {
74+
for (String s : plugin.config().getLangMobHelp())
75+
sender.sendMessage(s);
76+
}
77+
78+
/**
79+
* For when a player reaches a points Milestone. This tells other people in
80+
* the world when the player reaches a Milestone. If it is a Major Milestone,
81+
* then the sound changes, but other players will only hear the minor milestone
82+
* sound. They will only hear the sound if they are closeby to the player who
83+
* achieved the Milestone.
84+
* @param player The player who achieved the Milestone.
85+
* @param isMajorSound Whether the player surpasssed a Major Milestone or not.
86+
* @param milestonePoints The number of points associated with the Milestone.
87+
*/
88+
public void collectionMilestoneReachedResponse(Player player, boolean isMajorSound, int milestonePoints) {
89+
if (!plugin.config().isFeatureMilestoneMessageEnabled())
90+
return;
91+
92+
// TODO: Congratulate the player on reaching a milestone. On major milestones
93+
// notify other players as well. Revise and test this.
94+
Sound majorSound = plugin.config().getSoundMajorCollectionMilestone();
95+
Sound minorSound = plugin.config().getSoundMinorCollectionMilestone();
96+
97+
if (isMajorSound)
98+
player.playSound(player.getLocation(), majorSound, 1, 1);
99+
else
100+
player.playSound(player.getLocation(), minorSound, 1, 1);
101+
102+
// Tell other players about the milestone
103+
String broadcastMessage = plugin.config().getLangCollectionMilestoneReached()
104+
.replace("%Player%", player.getName())
105+
.replace("%Points%", "" + milestonePoints);
106+
107+
// TODO: Revise and test this. Other players should be able to hear the
108+
// milestone. If not, then this needs to change AND the PlayerHeadHunt
109+
// plugin code.
110+
player.getWorld().playSound(player.getLocation(), minorSound, 1, 1);
111+
for (Player otherPlayers : Bukkit.getOnlinePlayers())
112+
otherPlayers.sendMessage(broadcastMessage);
113+
}
114+
115+
/**
116+
* When a new player joins tell them the rules.
117+
* @param player The player who joined.
118+
*/
119+
public void newPlayerJoinsTheHunt(Player player) {
120+
for (String s : plugin.config().getLangNewHunter())
121+
player.sendMessage(s.replace("%Player%", player.getName()));
122+
}
123+
124+
/**
125+
* When a player clears their own points.
126+
* @param player The player who cleared their own points.
127+
*/
128+
public void playerClearedTheirPointsResponse(Player player) {
129+
playerClearedTheirPointsResponse(player, player.getName());
130+
}
131+
132+
/**
133+
* When a sender wants to clear the points of another player silently,
134+
* they would call this function. Only the sender is notified of the
135+
* clear.
136+
* @param messageRecipient The person to send the cleared message to.
137+
* @param aboutPlayerName The player whose points were cleared.
138+
*/
139+
public void playerClearedTheirPointsResponse(CommandSender messageRecipient, String aboutPlayerName) {
140+
messageRecipient.sendMessage(plugin.config().getLangOnMobClear()
141+
.replace("%Player%", aboutPlayerName));
142+
}
143+
144+
/**
145+
* From: https://stackoverflow.com/a/6810409
146+
* This function converts a rank to its ordinal representation
147+
* @param rank Rank to convert to ordinal.
148+
* @return The oridinal String.
149+
*/
150+
private static String rankToOrdinal(int rank) {
151+
String[] suffixes = new String[] { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" };
152+
return switch (rank % 100) {
153+
case 11, 12, 13 -> rank + "th";
154+
default -> rank + suffixes[rank % 10];
155+
};
156+
}
157+
158+
/**
159+
* From: https://www.spigotmc.org/threads/free-code-sending-perfectly-centered-chat-message.95872/
160+
* @param message The message to measure its length.
161+
* @return The length of the message in pixels (" " characters).
162+
*/
163+
private static int minecraftMessageLengthInPixels(String message) {
164+
if (message == null || message.equals(""))
165+
return 0;
166+
167+
int messagePxSize = 0;
168+
boolean previousCode = false;
169+
boolean isBold = false;
170+
171+
for (char c : message.toCharArray()) {
172+
if (c == '§'){
173+
previousCode = true;
174+
} else if (previousCode){
175+
previousCode = false;
176+
isBold = (c == 'l' || c == 'L');
177+
} else {
178+
DefaultFontInfo dFI = DefaultFontInfo.getDefaultFontInfo(c);
179+
messagePxSize += isBold ? dFI.getBoldLength() : dFI.getLength();
180+
messagePxSize++;
181+
}
182+
}
183+
return messagePxSize;
184+
}
185+
186+
/**
187+
* From: https://www.spigotmc.org/threads/free-code-sending-perfectly-centered-chat-message.95872/
188+
* @param pixels The number of pixels to pad.
189+
* @return The padded String.
190+
*/
191+
private static String getPixelPadding(int pixels) {
192+
StringBuilder sb = new StringBuilder();
193+
int spaceLength = DefaultFontInfo.SPACE.getLength() + 1;
194+
int compensated = 0;
195+
while (compensated < pixels){
196+
sb.append(" ");
197+
compensated += spaceLength;
198+
}
199+
return sb.toString();
200+
}
201+
202+
/**
203+
* From: https://www.spigotmc.org/threads/free-code-sending-perfectly-centered-chat-message.95872/
204+
* Sends the message to the chat such that it is in the middle of the chat box.
205+
* @param player The player sending the message.
206+
* @param message The message to send.
207+
* @param centrePixel The pixel to treat as the centre of the message.
208+
*/
209+
private static void sendMessageInCentre(Player player, String message, int centrePixel) {
210+
int messagePxSize = minecraftMessageLengthInPixels(message);
211+
int halvedMessageSize = messagePxSize / 2;
212+
int toCompensate = centrePixel - halvedMessageSize;
213+
player.sendMessage(getPixelPadding(toCompensate) + message);
214+
}
215+
216+
/**
217+
* For when a player wants to see who the best hunters are.
218+
* @param player The player who requested the leaderboard.
219+
* @param bestHunters A (presorted) list of stats to show on the leaderboard.
220+
*/
221+
public void showLeaderBoardResponse(Player player, List<MobHuntQuery.MobHunter> bestHunters) {
222+
showLeaderBoardResponse(player, bestHunters, null);
223+
}
224+
225+
/**
226+
* When you want to see the leaderboard with a heading of a specific mob.
227+
* @param player The player who requested the leaderboard.
228+
* @param bestHunters A (presorted) list of stats to show on the leaderboard.
229+
* @param title The title to give the leaderboard.
230+
*/
231+
public void showLeaderBoardResponse(Player player, List<MobHuntQuery.MobHunter> bestHunters, String title) {
232+
int centrePixel = minecraftMessageLengthInPixels(
233+
plugin.config().getLangLeaderboardHeader()) / 2;
234+
235+
// Show the header first
236+
sendMessageInCentre(player, plugin.config().getLangLeaderboardHeader(), centrePixel);
237+
player.sendMessage("");
238+
239+
if (title != null)
240+
sendMessageInCentre(player, title, centrePixel);
241+
242+
if (bestHunters.size() == 0) {
243+
// If there are no hunters we should probably tell the player
244+
sendMessageInCentre(player, plugin.config().getLangLeaderboardNoMobsKilled(), centrePixel);
245+
} else {
246+
for (int i = 0; i < bestHunters.size(); i++) {
247+
MobHuntQuery.MobHunter hunter = bestHunters.get(i);
248+
249+
// We probably shouldn't list players who have no points.
250+
// Once we find a player with 0 points then the rest will
251+
// also have 0 as it is sorted.
252+
if (hunter.points() == 0)
253+
break;
254+
255+
int rank = i + 1;
256+
String rankingColour = switch (rank) {
257+
case 1 -> plugin.config().getLangLeaderboardFirstColor();
258+
case 2 -> plugin.config().getLangLeaderboardSecondColor();
259+
case 3 -> plugin.config().getLangLeaderboardThirdColor();
260+
default -> plugin.config().getLangLeaderboardOtherColor();
261+
};
262+
263+
String rankingMessage = plugin.config().getLangLeaderboardFormat()
264+
.replace("%Color%", rankingColour)
265+
.replace("%Ranking%", rankToOrdinal(rank))
266+
.replace("%Player%", hunter.name())
267+
.replace("%Points%", "" + hunter.points());
268+
sendMessageInCentre(player, rankingMessage, centrePixel);
269+
}
270+
}
271+
272+
player.sendMessage("");
273+
sendMessageInCentre(player, plugin.config().getLangLeaderboardHeader(), centrePixel);
274+
}
275+
}

0 commit comments

Comments
 (0)