Skip to content

Commit

Permalink
Prevent start command from locking up the server
Browse files Browse the repository at this point in the history
  • Loading branch information
danthedaniel committed Oct 8, 2023
1 parent 219b121 commit e729a65
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 38 deletions.
11 changes: 8 additions & 3 deletions src/main/java/com/danangell/treasurehunt/TreasureHunt.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public void setGame(@NotNull TreasureHuntGame game) {
this.game = game;
}

private void clearGame() {
public void clearGame() {
this.game = null;
}

Expand Down Expand Up @@ -71,8 +71,13 @@ private void onTick() {

this.game.onTick();

if (this.game.getState() == TreasureHuntState.COMPLETED) {
this.clearGame();
switch (this.game.getState()) {
case COMPLETED:
case FAILED:
this.clearGame();
break;
default:
break;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
}

Server server = this.plugin.getServer();
TreasureHuntGame game = new TreasureHuntGame(this.plugin, server.getWorld("world"));
TreasureHuntGame game = new TreasureHuntGame(sender, this.plugin, server.getWorld("world"));
this.plugin.setGame(game);
try {
game.init();
Expand Down
105 changes: 72 additions & 33 deletions src/main/java/com/danangell/treasurehunt/TreasureHuntGame.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,19 @@
import java.util.concurrent.ThreadLocalRandom;

import org.bukkit.Chunk;
import org.bukkit.ChunkSnapshot;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Chest;
import org.bukkit.block.Lectern;
import org.bukkit.command.CommandSender;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BookMeta;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitScheduler;
import org.jetbrains.annotations.Nullable;

import net.kyori.adventure.text.format.TextDecoration;
Expand Down Expand Up @@ -64,13 +68,17 @@ public class TreasureHuntGame {
private TreasureHuntState state;
private Date stateEnteredOn;

private CommandSender sender;
private TreasureHunt plugin;
private World world;
private ThreadLocalRandom random;
private @Nullable Block lecturnSpot;
private @Nullable Block treasureSpot;
private @Nullable ItemStack treasure;
private @Nullable String bookContents;

public TreasureHuntGame(TreasureHunt plugin, World world) {
public TreasureHuntGame(CommandSender sender, TreasureHunt plugin, World world) {
this.sender = sender;
this.plugin = plugin;
this.state = TreasureHuntState.NOT_STARTED;
this.world = world;
Expand All @@ -81,11 +89,15 @@ public TreasureHuntState getState() {
return this.state;
}

public void setState(TreasureHuntState state) {
public synchronized void setState(TreasureHuntState state) {
this.state = state;
this.stateEnteredOn = new Date();
}

private synchronized void setBookContents(String bookContents) {
this.bookContents = bookContents;
}

/**
* Get the number of milliseconds that the game has been in its current state.
*/
Expand Down Expand Up @@ -116,38 +128,59 @@ public void init() throws TreasureHuntException {
this.plugin.getLogger().info("Placing treasure at (" + this.treasureSpot.getX() + ", "
+ this.treasureSpot.getY() + ", " + this.treasureSpot.getZ() + ")");

ItemStack treasure = selectTreasure();
this.treasure = selectTreasure();

int roundTo = 16;
int xApprox = (this.treasureSpot.getX() / roundTo) * roundTo;
int zApprox = (this.treasureSpot.getZ() / roundTo) * roundTo;

String prompt = "";
prompt += "Please give me flavor text for a treasure hunt describing a";
prompt += " location where a chest is hidden in a Minecraft world.\n";
prompt += "\n";
prompt += "Details:\n";
prompt += "Biome: " + this.treasureSpot.getBiome().toString().replace('_', ' ') + "\n";
prompt += "X: ~" + xApprox + "\n";
prompt += "Z: ~" + zApprox + "\n";
prompt += "Height: " + heightDescription(this.treasureSpot.getY()) + "\n";
prompt += "Contents: " + treasure.getType().toString().replace('_', ' ') + "\n";
prompt += "\n";
prompt += "Be concise. This should be no more than 3 sentences. Make sure to include the biome, ";
prompt += "coordinates (and that they are approximate), height, and contents. This message is broadcast ";
prompt += "to all online players, so tailor it accordingly.\n";

String response;
StringBuilder promptBuilder = new StringBuilder();
promptBuilder.append("Please give me flavor text for a treasure hunt describing a ");
promptBuilder.append("location where a chest is hidden in a Minecraft world.\n");
promptBuilder.append("\n");
promptBuilder.append("Details:\n");
promptBuilder.append("Biome: " + this.treasureSpot.getBiome().toString().replace('_', ' ') + "\n");
promptBuilder.append("X: ~" + xApprox + "\n");
promptBuilder.append("Z: ~" + zApprox + "\n");
promptBuilder.append("Height: " + heightDescription(this.treasureSpot.getY()) + "\n");
promptBuilder.append("Contents: " + this.treasure.getType().toString().replace('_', ' ') + "\n");
promptBuilder.append("\n");
promptBuilder.append("Be concise. This should be no more than 3 sentences. Make sure to include the biome, ");
promptBuilder.append("coordinates (and that they are approximate), height, and contents. This message is broadcast ");
promptBuilder.append("to all online players, so tailor it accordingly.\n");
final String prompt = promptBuilder.toString();

Plugin plugin = this.plugin;
TreasureHuntGame game = this;

BukkitScheduler scheduler = this.plugin.getServer().getScheduler();
scheduler.runTaskAsynchronously(this.plugin, new Runnable() {
public void run() {
try {
String response = OpenAIClient.completion(prompt);
game.setBookContents(response);
} catch (IOException e) {
plugin.getLogger().warning("Failed to get response from OpenAI API");
game.setState(TreasureHuntState.FAILED);
return;
}

game.setState(TreasureHuntState.READY_TO_START);
}
});
}

private void startTreasureHunt() {
placeLecturn(this.lecturnSpot, bookContents);

try {
response = OpenAIClient.completion(prompt);
} catch (IOException e) {
this.plugin.getLogger().warning("Failed to get response from OpenAI API");
throw new TreasureHuntException("Failed to get response from OpenAI API");
placeTreasure(this.treasureSpot, treasure);
} catch (TreasureHuntException e) {
this.plugin.getLogger().warning("Failed to place treasure: " + e.getMessage());
setState(TreasureHuntState.FAILED);
return;
}

placeLecturn(this.lecturnSpot, response);
placeTreasure(this.treasureSpot, treasure);

announce("TREASURE HUNT!", NamedTextColor.GREEN, Set.of(TextDecoration.BOLD));
String announcement = "You will find directions to buried treasure at ";
announcement += "(" + this.lecturnSpot.getX() + ", " + this.lecturnSpot.getY() + ", "
Expand Down Expand Up @@ -228,6 +261,9 @@ public void onTick() {
switch (this.state) {
case NOT_STARTED:
break;
case READY_TO_START:
startTreasureHunt();
break;
case IN_PROGRESS:
checkTreasure();

Expand All @@ -240,6 +276,10 @@ public void onTick() {
case COMPLETED:
deleteTreasure();
break;
case FAILED:
deleteTreasure();
sender.sendMessage("Treasure hunt failed!");
break;
}
}

Expand Down Expand Up @@ -293,7 +333,6 @@ private Chunk randomLecturnChunk() {
}

private Chunk randomChestChunk(Location lecternLocation) {
// Find a spot between 100 and 500 blocks away from the lectern
int distanceRange = TREASURE_LECTERN_MAX_RADIUS - TREASURE_LECTERN_MIN_RADIUS;
int x = random.nextInt(-distanceRange, distanceRange + 1);
x += TREASURE_LECTERN_MIN_RADIUS * (x > 0 ? 1 : -1);
Expand All @@ -314,23 +353,23 @@ private Chunk randomChestChunk(Location lecternLocation) {
* @return Block with Material of AIR - or null if no spot was found.
*/
private @Nullable Block findTreasureSpot(Chunk chunk, int yMin, int yMax) {
ChunkSnapshot chunkSnapshot = chunk.getChunkSnapshot();

for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
for (int y = yMin; y < yMax; y++) {
// Look for a solid block
Block baseBlock = chunk.getBlock(x, y, z);
Material baseMaterial = baseBlock.getType();
Material baseMaterial = chunkSnapshot.getBlockType(x, y, z);
if (!baseMaterial.isSolid()) {
continue;
}

// Look for an air block above it
Block chestBlock = chunk.getBlock(x, y + 1, z);
if (chestBlock.getType() != Material.AIR) {
Material chestSpotMaterial = chunkSnapshot.getBlockType(x, y + 1, z);
if (chestSpotMaterial != Material.AIR) {
continue;
}

return chestBlock;
return chunk.getBlock(x, y + 1, z);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

public enum TreasureHuntState {
NOT_STARTED,
READY_TO_START,
IN_PROGRESS,
COMPLETED
COMPLETED,
FAILED
}

0 comments on commit e729a65

Please sign in to comment.