Skip to content
Merged
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
138 changes: 138 additions & 0 deletions Events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# KillQuestPlugin Custom Events

The `KillQuestPlugin` provides several custom events that other plugins can listen to and handle. These events are dispatched at various points during the execution of quests and jumping puzzles.

## Events Overview

### JumpPuzzleStartEvent

- **Description**: This event is triggered when a player starts a jumping puzzle.
- **Class**: `com.digitalwm.killquest.events.JumpPuzzleStartEvent`
- **Methods**:
- `Player getPlayer()`: Returns the player who started the puzzle.
- `String getPuzzleName()`: Returns the name of the puzzle.
- **Usage**:
```java
@EventHandler
public void onJumpPuzzleStart(JumpPuzzleStartEvent event) {
Player player = event.getPlayer();
String puzzleName = event.getPuzzleName();
// Handle the event
}
```

### JumpPuzzleEndEvent

- **Description**: This event is triggered when a player completes a jumping puzzle.
- **Class**: `com.digitalwm.killquest.events.JumpPuzzleEndEvent`
- **Methods**:
- `Player getPlayer()`: Returns the player who completed the puzzle.
- `String getPuzzleName()`: Returns the name of the puzzle.
- **Usage**:
```java
@EventHandler
public void onJumpPuzzleEnd(JumpPuzzleEndEvent event) {
Player player = event.getPlayer();
String puzzleName = event.getPuzzleName();
// Handle the event
}
```

### JumpPuzzleTimeoutEvent

- **Description**: This event is triggered when the timer for a jumping puzzle expires.
- **Class**: `com.digitalwm.killquest.events.JumpPuzzleTimeoutEvent`
- **Methods**:
- `Player getPlayer()`: Returns the player whose puzzle timed out.
- `String getPuzzleName()`: Returns the name of the puzzle.
- **Usage**:
```java
@EventHandler
public void onJumpPuzzleTimeout(JumpPuzzleTimeoutEvent event) {
Player player = event.getPlayer();
String puzzleName = event.getPuzzleName();
// Handle the event
}
```

### QuestStartEvent

- **Description**: This event is triggered when a player starts a quest.
- **Class**: `com.digitalwm.killquest.events.QuestStartEvent`
- **Methods**:
- `Player getPlayer()`: Returns the player who started the quest.
- `String getQuestName()`: Returns the name of the quest.
- **Usage**:
```java
@EventHandler
public void onQuestStart(QuestStartEvent event) {
Player player = event.getPlayer();
String questName = event.getQuestName();
// Handle the event
}
```

### QuestEndEvent

- **Description**: This event is triggered when a player completes a quest.
- **Class**: `com.digitalwm.killquest.events.QuestEndEvent`
- **Methods**:
- `Player getPlayer()`: Returns the player who completed the quest.
- `String getQuestName()`: Returns the name of the quest.
- **Usage**:
```java
@EventHandler
public void onQuestEnd(QuestEndEvent event) {
Player player = event.getPlayer();
String questName = event.getQuestName();
// Handle the event
}
```

## Registering Event Listeners

To listen for these events, you need to register an event listener in your plugin. Here is an example of how to do this:

```java
import cn.nukkit.plugin.PluginBase;
import cn.nukkit.event.Listener;
import cn.nukkit.event.EventHandler;
import com.digitalwm.killquest.events.JumpPuzzleStartEvent;
import com.digitalwm.killquest.events.JumpPuzzleEndEvent;
import com.digitalwm.killquest.events.JumpPuzzleTimeoutEvent;
import com.digitalwm.killquest.events.QuestStartEvent;
import com.digitalwm.killquest.events.QuestEndEvent;

public class YourPlugin extends PluginBase implements Listener {

@Override
public void onEnable() {
getServer().getPluginManager().registerEvents(this, this);
}

@EventHandler
public void onJumpPuzzleStart(JumpPuzzleStartEvent event) {
// Handle the jump puzzle start event
}

@EventHandler
public void onJumpPuzzleEnd(JumpPuzzleEndEvent event) {
// Handle the jump puzzle end event
}

@EventHandler
public void onJumpPuzzleTimeout(JumpPuzzleTimeoutEvent event) {
// Handle the jump puzzle timeout event
}

@EventHandler
public void onQuestStart(QuestStartEvent event) {
// Handle the quest start event
}

@EventHandler
public void onQuestEnd(QuestEndEvent event) {
// Handle the quest end event
}
}
```
51 changes: 37 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,18 @@

---

## Changes to 1.0.1
## Changes in 1.0.2
- Added regenaration of puzzle when a user finishes it
- Added regeneration of puzzle, using a reset block. You must stay at least 5 seconds on it
- Added 2 Doors around the start block so the players can enter and exit the puzzle
- Added 5 Events to be triggered from within the plugin
- JumpPuzzleEndEvent
- JumpPuzzleStartEvent
- JumpPuzzleTimeoutEvent
- QuestEndEvent
- QuestStartEvent

## Changes in 1.0.1

- Added Handling of onPlayerFish event so fishing quests can be created
- Added complete new loging of generating jumping puzzles
Expand All @@ -26,17 +37,19 @@
---

## **📜 Features**
✔ **Quest System:** Kill entities and gather items to complete quests.
✔ **Dynamic Quest Selection:** Players can select quests using a UI (`/quests`).
✔ **Scoreboard Tracking:** Displays active quest progress in the top-right.
✔ **Auto-Saving:** Quest progress is saved to files per player.
✔ **EconomyAPI Integration:** Players earn credits upon completion.
✔ **Multilingual Support:** Uses Minecraft’s translations for entity/item names.
✔ **Jumping Puzzles:** Procedurally generate jumping puzzles with varying heights and difficulties.
✔ **Puzzle Persistence:** Puzzles are saved and can be reloaded after server restarts.
✔ **Player Movement Tracking:** Detect when players start and complete puzzles.
✔ **Block Restrictions:** Prevent players from modifying puzzle areas.
✔ **Puzzle Management Commands:** Create, list, and remove puzzles dynamically.
- **Quest System:** Kill entities and gather items to complete quests.
- **Dynamic Quest Selection:** Players can select quests using a UI (`/quests`).
- **Scoreboard Tracking:** Displays active quest progress in the top-right.
- **Auto-Saving:** Quest progress is saved to files per player.
- **EconomyAPI Integration:** Players earn credits upon completion.
- **Multilingual Support:** Uses Minecraft’s translations for entity/item names.
- **Jumping Puzzles:** Procedurally generate jumping puzzles with varying heights and difficulties.
- **Puzzle Persistence:** Puzzles are saved and can be reloaded after server restarts.
- **Player Movement Tracking:** Detect when players start and complete puzzles.
- **Block Restrictions:** Prevent players from modifying puzzle areas.
- **Puzzle Management Commands:** Create, list, and remove puzzles dynamically.
- **Puzzle Regen Logic:** Regenerate the given puzzle, when the user completes it or using reset block.
- **Server Events:** The plugin sends events when changes are on Quests and Jumping Puzzles.

---

Expand Down Expand Up @@ -65,6 +78,14 @@
3. Players must jump across blocks that are generated to be challenging but solvable.
4. A tracking system monitors when a player starts and completes the puzzle.
5. Upon completion, the player receives 100 credits via EconomyAPI.
6. Once completed, the user is teleported to the center and the puzzle regenerates
7. If puzzle is imposible, use the green block to regenerate it. Stay on it more than 5 seconds

---

## **For coders**

For more information about the custom events provided by this plugin, see the [Events Documentation](Events.md).

---

Expand Down Expand Up @@ -134,7 +155,7 @@ translations:
[INFO ] [KillQuestPlugin] ██║ ██╗██║███████╗███████╗╚██████╔╝╚██████╔╝███████╗███████║ ██║
[INFO ] [KillQuestPlugin] ╚═╝ ╚═╝╚═╝╚══════╝╚══════╝ ╚══▀▀═╝ ╚═════╝ ╚══════╝╚══════╝ ╚═╝
[INFO ] [KillQuestPlugin]
[INFO ] [KillQuestPlugin] Version: 1.0.0
[INFO ] [KillQuestPlugin] Version: 1.0.2
[INFO ] [KillQuestPlugin] Developed by digitalwm
[INFO ] [KillQuestPlugin]
[INFO ] [KillQuestPlugin] Loaded language: en_US with 41 keys.
Expand All @@ -143,12 +164,14 @@ translations:
[INFO ] [KillQuestPlugin] Total translation keys loaded: 82
[INFO ] [KillQuestPlugin] KillQuestPlugin enabled with 23 available quests.
[INFO ] [KillQuestPlugin] EconomyAPI found. Rewards enabled.
[INFO ] [KillQuestPlugin] Loading saved puzzles...
[INFO ] [KillQuestPlugin] Loaded puzzle: test
```

---

## **💡 Future Improvements**
- ✅ **More Quest Types:** Crafting
- ✅ **More Quest Types:** Crafting, Shooting
- ✅ **Permissions Support**
- ✅ **More Customization Options**
- ✅ **SQL Database support**
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<groupId>com.digitalwm.killquestplugin</groupId>
<artifactId>KillQuestPlugin</artifactId>
<version>1.0.1</version>
<version>1.0.2</version>

<build>
<defaultGoal>package</defaultGoal>
Expand Down
73 changes: 73 additions & 0 deletions src/main/java/com/digitalwm/killquest/JumpPuzzleGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import cn.nukkit.Player;
import cn.nukkit.block.Block;
import cn.nukkit.block.BlockDoor;
import cn.nukkit.level.Level;
import cn.nukkit.math.Vector3;
import cn.nukkit.event.player.PlayerMoveEvent;
import cn.nukkit.block.BlockDoorWood;
import me.onebone.economyapi.EconomyAPI;
import java.util.HashMap;
import java.util.Map;
Expand All @@ -26,6 +28,7 @@ public class JumpPuzzleGenerator {
private Vector3 endBlock;

private final Map<Player, Long> playerStartTimes = new HashMap<>();
private final Map<Player, Long> playerGreenBlockTimes = new HashMap<>();

// List to track all blocks generated in the puzzle

Expand Down Expand Up @@ -177,6 +180,42 @@ private void generatePuzzle() {
level.setBlock(startBlock, Block.get(Block.GOLD_BLOCK));
trackBlock(startBlock, "START"); // ✅ Track start block

// ✅ Create wooden doors
BlockDoorWood doorBottom1 = new BlockDoorWood();
BlockDoorWood doorTop1 = new BlockDoorWood();
doorTop1.setDamage(8);

BlockDoorWood doorBottom2 = new BlockDoorWood();
BlockDoorWood doorTop2 = new BlockDoorWood();
doorTop2.setDamage(8); // ✅ Set as upper part of the door

// Door base positions (1 block above start block, placed at the corner)
Vector3 doorBase1 = new Vector3(startBlock.x - 1, startBlock.y + 1, startBlock.z);
Vector3 doorBase2 = new Vector3(startBlock.x, startBlock.y + 1, startBlock.z - 1);

// Door top positions (1 block above door bases)
Vector3 doorTop1Pos = new Vector3(doorBase1.x, doorBase1.y + 1, doorBase1.z);
Vector3 doorTop2Pos = new Vector3(doorBase2.x, doorBase2.y + 1, doorBase2.z);

// ✅ Place bottom and top door parts
level.setBlock(doorBase1, doorBottom1);
level.setBlock(doorTop1Pos, doorTop1);

level.setBlock(doorBase2, doorBottom2);
level.setBlock(doorTop2Pos, doorTop2);

// ✅ Track doors for removal
trackBlock(doorBase1, "DOOR_BOTTOM");
trackBlock(doorTop1Pos, "DOOR_TOP");

trackBlock(doorBase2, "DOOR_BOTTOM");
trackBlock(doorTop2Pos, "DOOR_TOP");

// ✅ Add a single green block diagonally opposite to the start block on the same height plane
Vector3 greenBlock = new Vector3(puzzleMax.x - 1, startBlock.y, puzzleMax.z - 1);
level.setBlock(greenBlock, Block.get(Block.EMERALD_BLOCK));
trackBlock(greenBlock, "GREEN"); // ✅ Track green block

int currentHeight = 0;
int blocksAtCurrentHeight = 0;

Expand Down Expand Up @@ -276,21 +315,41 @@ public void handlePlayerMovement(PlayerMoveEvent event) {

if (pos.equals(startBlock) && !playerStartTimes.containsKey(player)) {
player.sendMessage("§eYou started the jump puzzle! Reach the end within 15 minutes!");
plugin.onJumpPuzzleStart(player, puzzleName); // Trigger start event
playerStartTimes.put(player, System.currentTimeMillis());
}

// Check if the player is on the green block
if (puzzleBlocks.containsKey(pos) && "GREEN".equals(puzzleBlocks.get(pos))) {
long currentTime = System.currentTimeMillis();
if (!playerGreenBlockTimes.containsKey(player)) {
playerGreenBlockTimes.put(player, currentTime);
} else {
long timeOnGreenBlock = currentTime - playerGreenBlockTimes.get(player);
if (timeOnGreenBlock > 5000) { // 5 seconds
player.sendMessage("§cYou stayed on the green block for too long! The puzzle has been reset.");
resetPuzzleForPlayer(player);
}
}
} else {
playerGreenBlockTimes.remove(player);
}

if (playerStartTimes.containsKey(player)) {
long startTime = playerStartTimes.get(player);
if (System.currentTimeMillis() - startTime > 15 * 60 * 1000) {
player.sendMessage("§cYou ran out of time for the jump puzzle!");
plugin.onJumpPuzzleTimeout(player, puzzleName); // Trigger timeout event
playerStartTimes.remove(player);
return;
}

if (pos.equals(endBlock)) {
player.sendMessage("§aCongratulations! You completed the jump puzzle!");
EconomyAPI.getInstance().addMoney(player, 100);
plugin.onJumpPuzzleEnd(player, puzzleName); // Trigger end event
playerStartTimes.remove(player);
resetPuzzleForPlayer(player);
}
}
}
Expand Down Expand Up @@ -412,4 +471,18 @@ public void setPuzzleBlocks(Map<Vector3, String> newBlocks) {
this.puzzleBlocks.clear();
this.puzzleBlocks.putAll(newBlocks);
}

private void resetPuzzleForPlayer(Player player) {
// Teleport the player to the center of the puzzle
Vector3 centerBlock = new Vector3(
startPos.x,
startPos.y,
startPos.z
);
player.teleport(centerBlock);

// Regenerate the puzzle
removePuzzle();
generate();
}
}
9 changes: 9 additions & 0 deletions src/main/java/com/digitalwm/killquest/JumpPuzzleListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import cn.nukkit.Player;
import cn.nukkit.event.EventHandler;
import cn.nukkit.block.BlockDoor;
import cn.nukkit.event.Listener;
import cn.nukkit.math.Vector3;
import cn.nukkit.event.block.BlockBreakEvent;
import cn.nukkit.event.player.PlayerInteractEvent;
import cn.nukkit.event.block.BlockPlaceEvent;
import cn.nukkit.event.player.PlayerMoveEvent;

Expand All @@ -16,6 +18,13 @@ public JumpPuzzleListener(KillQuestPlugin plugin) {
this.plugin = plugin;
}

@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
if (event.getBlock() instanceof BlockDoor) {
// plugin.getLogger().info(event.getPlayer().getName() + " interacted with a door at " + event.getBlock().getLocation());
}
}

@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
Player player = event.getPlayer();
Expand Down
Loading
Loading