Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 130 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,140 @@
![img](https://github.com/ModularSoftAU/assets/blob/master/playerheadhunt/playerheadhunt-icon-text-256.png?raw=true)
# PlayerHeadHunt

## About

PlayerHeadHunt is a Minecraft minigame plugin that allows server administrators to set up a head-hunting game. Players can search for hidden heads within a defined region and compete to find them all. The plugin is highly configurable, allowing for custom messages, sounds, and rewards.

## Features

* **Customizable Hunt Region:** Define a specific area for the head hunt using WorldEdit.
* **Configurable Heads:** Use any block as a "head," not just player heads. Customize the skins of player heads.
* **Milestone Rewards:** Reward players with items (like helmets) and broadcast messages when they reach certain milestones.
* **Leaderboard:** Display the top head hunters on the server.
* **Customizable Messages and Sounds:** Configure all user-facing messages and sounds to match your server's theme.
* **Database Support:** Player data is stored in a `player-data.yml` file.

## Commands

| Command | Description | Usage | Aliases |
| ------------------- | ------------------------------------------------- | ----------------------------------------- | --------------- |
| `/heads` | Shows the number of heads you have found. | `/heads` | `eggs`, `presents` |
| `/leaderboard` | Shows the top 5 head hunters on the server. | `/leaderboard` | `lb` |
| `/debugheadhunt` | Debug command for developers. | `/debugheadhunt <clearheads|countheads>` | `dhh` |

## Installation
* Clone this repo.
* Configure your config.
* Run the dbinit.

## Requirements
* MySQL Database.
1. Install [WorldEdit](https://dev.bukkit.org/projects/worldedit).
2. Download the latest version of PlayerHeadHunt.
3. Place the `PlayerHeadHunt.jar` file in your server's `plugins` directory.
4. Restart your server.
5. Configure the plugin by editing the `config.yml` file in the `plugins/PlayerHeadHunt` directory.

## Dependencies
- `WorldEdit` is **required** since it is used to count all the heads in the hunting region.
## Configuration

## Gameplay
When a player right-clicks a Player Head, the coordinates are logged in a database and a number incremented in their name.
The `config.yml` file is heavily commented and allows you to customize many aspects of the plugin.

#### Milestones
When a player finds over an X amount of heads, a message will broadcast to all online players that they have reached a milestone.
The milestones are hardcoded and at this time cannot be changed, these milestones are `10, 50, 100, 150, 200, 500`.
### `REGION`

##### Milestone Helmets
To symbolise to other people in the Head Hunt where people are at, every goal achieved in the table below is given a helmet to visualise how much someone has progressed in the Hunt.
This section defines the area where heads will be placed. You need to set the coordinates for the upper and lower corners of the region.

| Number | Helmet |
|--------|-----------|
| 50 | Leather |
| 100 | Chainmail |
| 150 | Iron |
| 200 | Gold |
| 250 | Diamond |
| 300 | Netherite |
```yaml
REGION:
UPPERREGION:
X: -54
Y: 255 # Do not change this, this expands vertically.
Z: 48
LOWERREGION:
X: -33
Y: 0 # Do not change this, this expands vertically.
Z: 4
```

#### Head Collection Cooldown
To avoid hunters following other players to collect their heads, heads will disappear and reappear in a configurable option `HEAD.RESPAWNTIMER`
### `FEATURE`

## Commands
| Command | Description | Permission |
|--------------|------------------------------------------------|-----------------------------|
| /heads | Grab the amount of heads you have. | |
| /clearheads | Clear all heads from yourself. | `playerheadhunt.clearhead` |
| /countheads | Recalculates the number of heads in the world. | `playerheadhunt.countheads` |
| /leaderboard | Show the 5 best head hunters on the Server. | |
Enable or disable certain features of the plugin.

```yaml
FEATURE:
MILESTONEHAT: TRUE
MILESTONEMESSAGE: TRUE
```

* `MILESTONEHAT`: If `true`, players will receive a helmet as a reward for reaching a milestone.
* `MILESTONEMESSAGE`: If `true`, a message will be broadcasted when a player reaches a milestone.

### `HEAD`

Configure the heads themselves.

```yaml
HEAD:
HEADTOTAL:
HEADBLOCK: PLAYER_HEAD
RESPAWNTIMER: 1200 # Default is 1200 (1 minute)
SKINSMAX: 9
SKINS:
0: "..."
1: "..."
# ...
```

* `HEADTOTAL`: The total number of heads in the region. This is calculated automatically.
* `HEADBLOCK`: The material of the block to be used as a head. A list of materials can be found [here](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html).
* `RESPAWNTIMER`: The time in seconds it takes for a head to respawn after being found.
* `SKINSMAX`: The number of skins to use for the heads.
* `SKINS`: A list of base64 encoded skins for the player heads.

### `SOUND`

Customize the sounds played by the plugin. A list of sounds can be found [here](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Sound.html).

```yaml
SOUND:
HEADFOUND: "BLOCK_NOTE_BLOCK_SNARE"
HEADALREADYFOUND: "BLOCK_NOTE_BLOCK_BASS"
MINORCOLLECTIONMILESTONE: "ENTITY_PLAYER_LEVELUP"
MAJORCOLLECTIONMILESTONE: "UI_TOAST_CHALLENGE_COMPLETE"
```

### `MILESTONES`

Define the milestones for the head hunt.

```yaml
MILESTONES:
MINOR:
- 16
- 32
# ...
MAJOR:
- 128
- 256
# ...
LEATHERHELMET: 16
CHAINMAILHELMET: 32
# ...
```

* `MINOR` and `MAJOR`: Lists of head counts that trigger milestone events.
* `LEATHERHELMET`, `CHAINMAILHELMET`, etc.: The number of heads a player must find to receive the corresponding helmet.

### `LANG`

Customize all user-facing messages.

```yaml
LANG:
DATABASE:
CONNECTIONERROR: "&cA database error has occurred, please contact an Administrator."
# ...
COMMAND:
# ...
HEAD:
# ...
LEADERBOARD:
# ...
```

## For Developers

The source code is available on [GitHub](https://github.com/ModularSoftAU/PlayerHeadHunt). Feel free to contribute to the project by creating issues or pull requests.
19 changes: 9 additions & 10 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,11 @@
</exclusions>
</dependency>

<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>

<!-- WorldEdit -->
<dependency>
<groupId>com.sk89q.worldedit</groupId>
<artifactId>worldedit-bukkit</artifactId>
<version>7.3.0</version>
<version>7.3.10</version>
<scope>provided</scope>
<exclusions>
<exclusion>
Expand All @@ -84,7 +77,7 @@
<dependency>
<groupId>com.sk89q.worldedit</groupId>
<artifactId>worldedit-core</artifactId>
<version>7.3.0</version>
<version>7.3.10</version>
<scope>provided</scope>
<exclusions>
<exclusion>
Expand All @@ -97,9 +90,15 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.0</version>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@

import java.util.List;

import static org.modularsoft.PlayerHeadHunt.HeadQuery.foundHeadsAlreadyCount;

public class HeadChatController {
private final PlayerHeadHuntMain plugin;
private final HeadQuery headQuery;

public HeadChatController(PlayerHeadHuntMain plugin) {
public HeadChatController(PlayerHeadHuntMain plugin, HeadQuery headQuery) {
this.plugin = plugin;
this.headQuery = headQuery;
}

public void headFoundResponse(Player player, boolean hasAlreadyBeenFound, int headCount, int x, int y, int z) {
Expand All @@ -28,7 +28,8 @@ public void headFoundResponse(Player player, boolean hasAlreadyBeenFound, int he
player.playSound(player.getLocation(), plugin.config().getHeadFoundSound(), 1, 1);
}

int otherPlayerFoundHead = foundHeadsAlreadyCount(plugin, x, y, z) - 1;
// Get the number of other players who have found this head
int otherPlayerFoundHead = Math.max(0, headQuery.foundHeadsAlreadyCount(x, y, z) - 1);

String otherPlayersHaveFoundSuffix;
if (otherPlayerFoundHead == 0) {
Expand All @@ -39,18 +40,18 @@ public void headFoundResponse(Player player, boolean hasAlreadyBeenFound, int he
}
} else if (otherPlayerFoundHead == 1) {
otherPlayersHaveFoundSuffix = plugin.config().getLangHeadNotFirstFinderSingle()
.replace("%OTHERPLAYERSFOUNDHEAD%", "" + otherPlayerFoundHead);
.replace("%OTHERPLAYERSFOUNDHEAD%", String.valueOf(otherPlayerFoundHead));
} else {
otherPlayersHaveFoundSuffix = plugin.config().getLangHeadNotFirstFinderMultiple()
.replace("%OTHERPLAYERSFOUNDHEAD%", "" + otherPlayerFoundHead);
.replace("%OTHERPLAYERSFOUNDHEAD%", String.valueOf(otherPlayerFoundHead));
}

// Replace placeholders in the message
String message = baseMessage
.replace("%FOUNDHEADS%", "" + headCount)
.replace("%NUMBEROFHEADS%", "" + plugin.config().getTotalHeads())
.replace("%FOUNDHEADS%", String.valueOf(headCount))
.replace("%NUMBEROFHEADS%", String.valueOf(plugin.config().getTotalHeads()))
.replace("%ALREADYFOUNDHEADS%", otherPlayersHaveFoundSuffix);

// Play sound for a Player Head that is found.
player.sendMessage(message);
}

Expand Down Expand Up @@ -100,9 +101,9 @@ public void newPlayerJoinsTheHunt(Player player) {
}

public void playersOwnHeadCountResponse(Player player) {
// Players wants to see their own head count
// Use the instance of HeadQuery to call the method
player.sendMessage(plugin.config().getLangHeadCount()
.replace("%FOUNDHEADS%", "" + HeadQuery.foundHeadsCount(plugin, player))
.replace("%FOUNDHEADS%", "" + headQuery.foundHeadsCount(player))
.replace("%NUMBEROFHEADS%", "" + plugin.config().getTotalHeads()));
}

Expand Down
Loading