Compare commits

...

22 Commits

Author SHA1 Message Date
131d131dfe Trying to fix villager spawn 2024-02-05 22:47:19 +01:00
c9dd268c14 Feat: Change way of handling voids
Only store to database when fetching scoreboard or on disconnect.
else just use the persistentStorage from players
2024-02-04 21:38:28 +01:00
a7a88bb619 Log Voids interaction
This is just in case the server would crash and not save current score.
log can be used to see what was the last score at some point
2024-02-04 21:29:03 +01:00
d92a8c6125 Seend a death message to the webhook 2024-02-04 21:28:26 +01:00
30be45065f Need thevoidmanager.score to execute /void score 2024-02-04 21:27:53 +01:00
f36e6b1aa0 Refactoring 2024-01-31 12:34:04 +01:00
629695ac21 Item drop bug 2024-01-31 12:27:38 +01:00
8bf35896f4 /void manage bring command 2024-01-29 18:25:13 +01:00
1d34a3040d Show Custom Name 2024-01-29 18:23:02 +01:00
af96c5a412 todos 2024-01-27 13:09:58 +01:00
105d564ec0 Notification on /void give 2024-01-27 00:17:47 +01:00
a7fdff2dd9 Next Item In Merchand 2024-01-27 00:17:24 +01:00
2b2683b22b Discord Binding 2024-01-26 23:47:46 +01:00
402b94a797 Check if give is not negative 2024-01-26 23:38:12 +01:00
56b7ae97ef removing uncraftable tuff stuff 2024-01-26 21:31:55 +01:00
b08fb8e5a4 Names 2024-01-26 21:25:48 +01:00
f61e6d865e Discord link 2024-01-26 20:10:45 +01:00
2f24f61b16 Unban Command 2024-01-26 19:00:03 +01:00
2df9d0c293 Ban hourly 2024-01-25 22:48:29 +01:00
3e3a6e9a5d Show Scoreboard below name and top screen 2024-01-25 20:27:16 +01:00
a7a775d1c8 Merchand materials + spawn management 2024-01-25 13:39:56 +01:00
94507d980d Basics of Merchand 2024-01-23 22:08:02 +01:00
14 changed files with 1531 additions and 159 deletions

19
TODO.md Normal file
View File

@ -0,0 +1,19 @@
# TODO list
- [x] deathBan reset
- [x] voids exchanges
- [x] /void give négatives values
- [x] Make Discord Webhoook for item changes
- [x] chest name
- [x] Show next Item
- [x] /void manage bring
- [+] /void give afficher title
- subtitle + chat
- [+] Double Check Inventory reset on die
- [+] Annonce
- [+] Find Map : 51 (250, 300)
- [+] Dupe bug (respawn)
- [-] i18n
- [ ] Events
- [ ] Command completions
- [ ] More descriptive /void commands

View File

@ -0,0 +1,42 @@
package ovh.herisson.thevoidroad;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
import org.bukkit.event.player.AsyncPlayerPreLoginEvent.Result;
import org.bukkit.event.player.PlayerKickEvent.Cause;
import net.kyori.adventure.text.Component;
public class BanHourly implements Listener{
@EventHandler
public void banned(AsyncPlayerPreLoginEvent e){
if(DatabaseManager.getInstance().hasDiedInHour(e.getUniqueId()))
e.disallow(Result.KICK_BANNED, Component.text("Vous etes mort dans la dernière heure... Patientez la prochaine!"));
}
@EventHandler
public void died(PlayerDeathEvent e){
DatabaseManager.getInstance().setDeath(e.getPlayer().getUniqueId());
e.setKeepInventory(true);
e.setKeepLevel(false);
e.getDrops().clear();
e.getPlayer().kick(Component.text("Vous etes mort dans la dernière heure... Patientez la prochaine!"), Cause.BANNED);
// Send death
String link = DatabaseManager.getInstance().getConfig("discord-wh");
if(!link.equals("")){
DiscordWebhook discord = new DiscordWebhook(link);
discord.setUsername("Ange de la mort");
discord.setAvatarUrl("http://static.planetminecraft.com/files/banners/minecraft_banner_18d1g881yg5831c.png");
discord.setContent(e.getDeathMessage());
try {
discord.execute();
} catch(Exception ex){
ex.printStackTrace();
}
}
}
}

View File

@ -35,13 +35,14 @@ public class DatabaseManager {
con = DriverManager.getConnection("jdbc:sqlite:plugins/TheVoidRoad/voids.db");
InitVoids();
InitConfig();
InitDeaths();
}
// Voids table and methods
private void InitVoids() throws SQLException{
String query = "CREATE TABLE IF NOT EXISTS voids (\n"
+ "id integer PRIMARY KEY,\n"
+ "uuid text NOT NULL,\n"
+ "uuid text NOT NULL UNIQUE,\n"
+ "amount INTEGER DEFAULT 0)";
Statement st = con.createStatement();
@ -49,25 +50,35 @@ public class DatabaseManager {
st.close();
}
public int getVoids(UUID uuid) throws SQLException{
Statement st = con.createStatement();
String query = "SELECT amount FROM voids WHERE uuid = ? LIMIT 1";
PreparedStatement p = con.prepareStatement(query);
p.setString(1, uuid.toString());
ResultSet rs = p.executeQuery();
int value = rs.getInt(1);
st.close();
return value;
public int getVoids(UUID uuid){
try {
Statement st = con.createStatement();
String query = "SELECT amount FROM voids WHERE uuid = ? LIMIT 1";
PreparedStatement p = con.prepareStatement(query);
p.setString(1, uuid.toString());
ResultSet rs = p.executeQuery();
int value = rs.getInt(1);
st.close();
return value;
} catch(Exception e){
e.printStackTrace();
}
return 0;
}
public void setVoids(UUID uuid, int amount) throws SQLException{
Statement st = con.createStatement();
String query = "INSERT OR REPLACE INTO voids (uuid, amount) VALUES (?, ?)";
PreparedStatement p = con.prepareStatement(query);
p.setString(1, uuid.toString());
p.setInt(2, amount);
p.execute();
st.close();
public void setVoids(UUID uuid, int amount) {
Bukkit.getLogger().info("[VOIDS] -> " + uuid.toString() + " to " + amount);
try {
Statement st = con.createStatement();
String query = "INSERT OR REPLACE INTO voids (uuid, amount) VALUES (?, ?)";
PreparedStatement p = con.prepareStatement(query);
p.setString(1, uuid.toString());
p.setInt(2, amount);
p.execute();
st.close();
} catch(Exception e){
e.printStackTrace();
}
}
public HashMap<UUID, Integer> getVoidsScoreboard() throws SQLException{
@ -97,27 +108,87 @@ public class DatabaseManager {
st.close();
}
public String getConfig(String name) throws SQLException{
Statement st = con.createStatement();
String query = "SELECT value FROM config WHERE name = ? LIMIT 1";
PreparedStatement p = con.prepareStatement(query);
p.setString(1, name);
ResultSet rs = p.executeQuery();
String value = rs.getString(1);
st.close();
return value;
public String getConfig(String name){
try {
Statement st = con.createStatement();
String query = "SELECT value FROM config WHERE name = ? LIMIT 1";
PreparedStatement p = con.prepareStatement(query);
p.setString(1, name);
ResultSet rs = p.executeQuery();
String value = rs.getString(1);
st.close();
return value;
} catch(Exception e){
e.printStackTrace();
}
return null;
}
public void setConfig(String name, @Nullable String value) throws SQLException{
public void setConfig(String name, @Nullable String value){
try {
Statement st = con.createStatement();
String query = "INSERT OR REPLACE INTO config (name, value) VALUES (?, ?)";
PreparedStatement p = con.prepareStatement(query);
p.setString(1, name);
p.setString(2, value);
p.execute();
st.close();
} catch(Exception e){
e.printStackTrace();
}
}
private void InitDeaths() throws SQLException{
String query = " CREATE TABLE IF NOT EXISTS deaths (\n"
+ "id integer PRIMARY KEY,\n"
+ "uuid text NOT NULL UNIQUE,\n"
+ "lastDeath INTEGER DEFAULT (unixepoch() / (60 * 60)))";
Statement st = con.createStatement();
String query = "INSERT OR REPLACE INTO config (name, value) VALUES (?, ?)";
PreparedStatement p = con.prepareStatement(query);
p.setString(1, name);
p.setString(2, value);
p.execute();
st.execute(query);
st.close();
}
public void setDeath(UUID uuid) {
try {
Statement st = con.createStatement();
String query = "INSERT OR REPLACE INTO deaths (uuid) VALUES (?)";
PreparedStatement p = con.prepareStatement(query);
p.setString(1, uuid.toString());
p.execute();
st.close();
} catch(Exception e){
e.printStackTrace();
}
}
public boolean hasDiedInHour(UUID uuid){
try {
Statement st = con.createStatement();
String query = "SELECT (unixepoch() / (60 * 60)) - lastDeath <= 0 FROM deaths WHERE uuid = ? LIMIT 1 ;";
PreparedStatement p = con.prepareStatement(query);
p.setString(1, uuid.toString());
ResultSet rs = p.executeQuery();
boolean value = rs.getBoolean(1);
st.close();
return value;
} catch(Exception e){
e.printStackTrace();
}
return false;
}
public void unban(UUID uuid) {
try {
Statement st = con.createStatement();
String query = "INSERT OR REPLACE INTO deaths (uuid, lastDeath) SELECT uuid, lastDeath - 1 FROM deaths WHERE uuid = ?";
PreparedStatement p = con.prepareStatement(query);
p.setString(1, uuid.toString());
p.execute();
st.close();
} catch(Exception e){
e.printStackTrace();
}
}
public void close(){
try {

View File

@ -0,0 +1,392 @@
package ovh.herisson.thevoidroad;
import javax.net.ssl.HttpsURLConnection;
import java.awt.Color;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Class used to execute Discord Webhooks with low effort
* @source https://gist.github.com/k3kdude/fba6f6b37594eae3d6f9475330733bdb
*/
public class DiscordWebhook {
private final String url;
private String content;
private String username;
private String avatarUrl;
private boolean tts;
private List<EmbedObject> embeds = new ArrayList<>();
/**
* Constructs a new DiscordWebhook instance
*
* @param url The webhook URL obtained in Discord
*/
public DiscordWebhook(String url) {
this.url = url;
}
public void setContent(String content) {
this.content = content;
}
public void setUsername(String username) {
this.username = username;
}
public void setAvatarUrl(String avatarUrl) {
this.avatarUrl = avatarUrl;
}
public void setTts(boolean tts) {
this.tts = tts;
}
public void addEmbed(EmbedObject embed) {
this.embeds.add(embed);
}
public void execute() throws IOException {
if (this.content == null && this.embeds.isEmpty()) {
throw new IllegalArgumentException("Set content or add at least one EmbedObject");
}
JSONObject json = new JSONObject();
json.put("content", this.content);
json.put("username", this.username);
json.put("avatar_url", this.avatarUrl);
json.put("tts", this.tts);
if (!this.embeds.isEmpty()) {
List<JSONObject> embedObjects = new ArrayList<>();
for (EmbedObject embed : this.embeds) {
JSONObject jsonEmbed = new JSONObject();
jsonEmbed.put("title", embed.getTitle());
jsonEmbed.put("description", embed.getDescription());
jsonEmbed.put("url", embed.getUrl());
if (embed.getColor() != null) {
Color color = embed.getColor();
int rgb = color.getRed();
rgb = (rgb << 8) + color.getGreen();
rgb = (rgb << 8) + color.getBlue();
jsonEmbed.put("color", rgb);
}
EmbedObject.Footer footer = embed.getFooter();
EmbedObject.Image image = embed.getImage();
EmbedObject.Thumbnail thumbnail = embed.getThumbnail();
EmbedObject.Author author = embed.getAuthor();
List<EmbedObject.Field> fields = embed.getFields();
if (footer != null) {
JSONObject jsonFooter = new JSONObject();
jsonFooter.put("text", footer.getText());
jsonFooter.put("icon_url", footer.getIconUrl());
jsonEmbed.put("footer", jsonFooter);
}
if (image != null) {
JSONObject jsonImage = new JSONObject();
jsonImage.put("url", image.getUrl());
jsonEmbed.put("image", jsonImage);
}
if (thumbnail != null) {
JSONObject jsonThumbnail = new JSONObject();
jsonThumbnail.put("url", thumbnail.getUrl());
jsonEmbed.put("thumbnail", jsonThumbnail);
}
if (author != null) {
JSONObject jsonAuthor = new JSONObject();
jsonAuthor.put("name", author.getName());
jsonAuthor.put("url", author.getUrl());
jsonAuthor.put("icon_url", author.getIconUrl());
jsonEmbed.put("author", jsonAuthor);
}
List<JSONObject> jsonFields = new ArrayList<>();
for (EmbedObject.Field field : fields) {
JSONObject jsonField = new JSONObject();
jsonField.put("name", field.getName());
jsonField.put("value", field.getValue());
jsonField.put("inline", field.isInline());
jsonFields.add(jsonField);
}
jsonEmbed.put("fields", jsonFields.toArray());
embedObjects.add(jsonEmbed);
}
json.put("embeds", embedObjects.toArray());
}
URL url = new URL(this.url);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("User-Agent", "Java-DiscordWebhook-BY-Gelox_");
connection.setDoOutput(true);
connection.setRequestMethod("POST");
OutputStream stream = connection.getOutputStream();
stream.write(json.toString().getBytes());
stream.flush();
stream.close();
connection.getInputStream().close(); //I'm not sure why but it doesn't work without getting the InputStream
connection.disconnect();
}
public static class EmbedObject {
private String title;
private String description;
private String url;
private Color color;
private Footer footer;
private Thumbnail thumbnail;
private Image image;
private Author author;
private List<Field> fields = new ArrayList<>();
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
public String getUrl() {
return url;
}
public Color getColor() {
return color;
}
public Footer getFooter() {
return footer;
}
public Thumbnail getThumbnail() {
return thumbnail;
}
public Image getImage() {
return image;
}
public Author getAuthor() {
return author;
}
public List<Field> getFields() {
return fields;
}
public EmbedObject setTitle(String title) {
this.title = title;
return this;
}
public EmbedObject setDescription(String description) {
this.description = description;
return this;
}
public EmbedObject setUrl(String url) {
this.url = url;
return this;
}
public EmbedObject setColor(Color color) {
this.color = color;
return this;
}
public EmbedObject setFooter(String text, String icon) {
this.footer = new Footer(text, icon);
return this;
}
public EmbedObject setThumbnail(String url) {
this.thumbnail = new Thumbnail(url);
return this;
}
public EmbedObject setImage(String url) {
this.image = new Image(url);
return this;
}
public EmbedObject setAuthor(String name, String url, String icon) {
this.author = new Author(name, url, icon);
return this;
}
public EmbedObject addField(String name, String value, boolean inline) {
this.fields.add(new Field(name, value, inline));
return this;
}
private class Footer {
private String text;
private String iconUrl;
private Footer(String text, String iconUrl) {
this.text = text;
this.iconUrl = iconUrl;
}
private String getText() {
return text;
}
private String getIconUrl() {
return iconUrl;
}
}
private class Thumbnail {
private String url;
private Thumbnail(String url) {
this.url = url;
}
private String getUrl() {
return url;
}
}
private class Image {
private String url;
private Image(String url) {
this.url = url;
}
private String getUrl() {
return url;
}
}
private class Author {
private String name;
private String url;
private String iconUrl;
private Author(String name, String url, String iconUrl) {
this.name = name;
this.url = url;
this.iconUrl = iconUrl;
}
private String getName() {
return name;
}
private String getUrl() {
return url;
}
private String getIconUrl() {
return iconUrl;
}
}
private class Field {
private String name;
private String value;
private boolean inline;
private Field(String name, String value, boolean inline) {
this.name = name;
this.value = value;
this.inline = inline;
}
private String getName() {
return name;
}
private String getValue() {
return value;
}
private boolean isInline() {
return inline;
}
}
}
private class JSONObject {
private final HashMap<String, Object> map = new HashMap<>();
void put(String key, Object value) {
if (value != null) {
map.put(key, value);
}
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
Set<Map.Entry<String, Object>> entrySet = map.entrySet();
builder.append("{");
int i = 0;
for (Map.Entry<String, Object> entry : entrySet) {
Object val = entry.getValue();
builder.append(quote(entry.getKey())).append(":");
if (val instanceof String) {
builder.append(quote(String.valueOf(val)));
} else if (val instanceof Integer) {
builder.append(Integer.valueOf(String.valueOf(val)));
} else if (val instanceof Boolean) {
builder.append(val);
} else if (val instanceof JSONObject) {
builder.append(val.toString());
} else if (val.getClass().isArray()) {
builder.append("[");
int len = Array.getLength(val);
for (int j = 0; j < len; j++) {
builder.append(Array.get(val, j).toString()).append(j != len - 1 ? "," : "");
}
builder.append("]");
}
builder.append(++i == entrySet.size() ? "}" : ",");
}
return builder.toString();
}
private String quote(String string) {
return "\"" + string + "\"";
}
}
}

View File

@ -1,60 +0,0 @@
package ovh.herisson.thevoidroad.Entity;
import java.util.Random;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.Villager;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.EntitiesUnloadEvent;
import ovh.herisson.thevoidroad.Event.HourEvent;
//Unique, so singleton patern
public class Merchand implements Listener{
private static Merchand instance;
public static Merchand getInstance(){
if(instance != null)
return instance;
return new Merchand();
}
private Villager m ;
private Merchand() {
generate();
}
private void generate(){
int x = new Random().nextInt(750 * 2) - 750, z = new Random().nextInt(750 * 2) - 750;
m = (Villager) Bukkit.getWorld("world").spawnEntity(new Location(Bukkit.getWorld("world"), x, 300, z), EntityType.VILLAGER);
m.setGlowing(true);
m.setInvulnerable(true);
Bukkit.getServer().forEachAudience((a) -> {
if(a instanceof Player ply){
ply.setCompassTarget(m.getLocation());
}
}); //Temporary
}
public void regenerate(){
if(m != null){ m.remove(); }
generate();
}
@EventHandler
public void onHour(HourEvent e){
regenerate();
}
@EventHandler //TODO(Merchand): Check if can't do using ticket chunk
public void onUnload(EntitiesUnloadEvent e){
if(e.getEntities().contains(m)){
m.getChunk().load();
}
}
}

View File

@ -1,4 +1,4 @@
package ovh.herisson.thevoidroad.Event;
package ovh.herisson.thevoidroad;
import java.time.LocalTime;
@ -13,6 +13,7 @@ import com.destroystokyo.paper.event.server.ServerTickStartEvent;
public class HourEvent extends Event implements Listener{
private static final HandlerList handlerList = new HandlerList();
public int hour = LocalTime.now().getHour();
public long unixhour = System.currentTimeMillis() / (1000L * 60L * 60L);
public static HandlerList getHandlerList(){
return handlerList;
@ -27,6 +28,7 @@ public class HourEvent extends Event implements Listener{
public void onHour(ServerTickStartEvent e){
if(LocalTime.now().getHour() != hour){
hour = LocalTime.now().getHour();
unixhour = System.currentTimeMillis() / (1000L * 60L * 60L);
Bukkit.getPluginManager().callEvent(this);
}
}

View File

@ -0,0 +1,179 @@
package ovh.herisson.thevoidroad;
import java.io.File;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Random;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.Villager;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.world.EntitiesLoadEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataType;
import net.kyori.adventure.text.Component;
//Unique, so singleton patern
public class Merchand implements Listener{
public static Tuple<Material, Integer> current, next;
private static Merchand instance;
private static final ArrayList<Material> mat = new ArrayList<>();
private static final ArrayList<String> names = new ArrayList<>();
private static Inventory inv;
private Villager m ;
private static final NamespacedKey tagger = new NamespacedKey(TheVoidRoad.instance, "merchand") ;
public static Merchand getInstance(){
if(instance == null)
instance = new Merchand();
return instance;
}
private Merchand() {
//Get file materials
File f = new File(TheVoidRoad.instance.getDataFolder(), "materials.txt");
try {
for (String s : Files.readAllLines(f.toPath())) {
mat.add(Material.valueOf(s));
}
} catch(Exception e){
e.printStackTrace();
}
f = new File(TheVoidRoad.instance.getDataFolder(), "names.txt");
try {
for (String s : Files.readAllLines(f.toPath())) {
names.add(s);
}
} catch(Exception e){
e.printStackTrace();
}
//Is the game inited
if(DatabaseManager.getInstance().getConfig("init") != null &&
DatabaseManager.getInstance().getConfig("init").equalsIgnoreCase("true")){
regenerate();
}
//Webhook connection
}
public void regenerate(){
if(m != null){ m.remove(); }
current = genTrade(System.currentTimeMillis() / (1000 * 60 * 60));
next = genTrade(1 + System.currentTimeMillis() / (1000 * 60 * 60));
Location center = Bukkit.getWorld("world").getWorldBorder().getCenter();
double brdSize = Bukkit.getWorld("world").getWorldBorder().getSize() - 1;
double x = new Random().nextDouble(brdSize) - brdSize/2, z = new Random().nextDouble(brdSize) - brdSize/2;
m = (Villager) Bukkit.getWorld("world").spawnEntity(center.add(x, 200, z), EntityType.VILLAGER);
m.getPersistentDataContainer().set(tagger, PersistentDataType.BOOLEAN, true);
m.setGlowing(true);
m.setInvulnerable(true);
m.customName(Component.text(names.get(new Random().nextInt(names.size()))));
m.setCustomNameVisible(true);
inv = Bukkit.createInventory(null, 9, Component.text(m.getName()));
Bukkit.getServer().forEachAudience((a) -> {
if(a instanceof Player ply){
ply.setCompassTarget(m.getLocation());
}
}); //Temporary
Bukkit.getServer().sendMessage(Component.text("The merchand just spawned"));
}
public Location getLocation(){
return m != null ? m.getLocation(): null;
}
public static Tuple<Material, Integer> genTrade(long hour){
Random rnd = new Random(hour);
return new Tuple<>(mat.get(rnd.nextInt(mat.size())), rnd.nextInt(9)+1);
}
@EventHandler
public void checkTagged(EntitiesLoadEvent e){
for (Entity m : e.getEntities()) {
if(m.getPersistentDataContainer().has(tagger) && m.getPersistentDataContainer().get(tagger, PersistentDataType.BOOLEAN)){
if(!m.equals(this.m)){
m.remove();
}
}
}
}
@EventHandler
public void onHour(HourEvent e){
current = genTrade(e.unixhour);
next = genTrade(e.unixhour + 1);
String link = DatabaseManager.getInstance().getConfig("discord-wh");
if(!link.equals("")){
DiscordWebhook discord = new DiscordWebhook(link);
discord.setUsername(m.getName());
discord.setContent("Salut, Je vend actuellement `" + current.x + "` au prix de " + current.y + TheVoidRoad.CoinGlyph);
try {
discord.execute();
} catch(Exception ex){
ex.printStackTrace();
}
}
regenerate();
}
@EventHandler
public void OpenInventory(PlayerInteractEntityEvent e){
if(e.getRightClicked().equals(m)){
e.setCancelled(true);
inv.clear();
inv.setItem(4, new ItemStack(current.x, current.y));
ItemStack nextItem = new ItemStack(next.x,next.y);
nextItem.editMeta(m ->{ m.setDisplayName("Prochain item en vente"); });
inv.setItem(8, nextItem);
e.getPlayer().openInventory(inv);
}
}
@EventHandler
public void Compass(PlayerInteractEvent e){
if(getLocation() != null && e.getItem() != null && e.getItem().getType() == Material.COMPASS){
e.getPlayer().setCompassTarget(getLocation());
}
}
//Inventory interaction
@EventHandler
public void ClickInsideInventory(InventoryClickEvent e){
// Did the click the right slot in the right inventory
if(!e.getInventory().equals(inv)) return;
e.setCancelled(true);
if(!e.getInventory().equals(inv) || e.getSlot() != 4) return;
if(e.getWhoClicked() instanceof Player ply){
//Do we have the item and if so remove them
if(ply.getInventory().contains(current.x)){
for (ItemStack i : ply.getInventory().getContents()) {
if(i != null && i.getType() == current.x){
i.subtract(1);
Voids.add(ply, current.y);
return;
}
}
}
}
}
public void teleport(Location location) {
m.teleport(location);
}
}

View File

@ -1,26 +1,37 @@
package ovh.herisson.thevoidroad;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
import ovh.herisson.thevoidroad.Commands.VoidCommands;
import ovh.herisson.thevoidroad.Event.HourEvent;
import ovh.herisson.thevoidroad.VoidCommands;
import ovh.herisson.thevoidroad.Merchand;
import ovh.herisson.thevoidroad.HourEvent;
public class TheVoidRoad extends JavaPlugin implements Listener{
public class TheVoidRoad extends JavaPlugin{
public static String CoinGlyph = ""; // Ɣ, √, ▼, Ṿ, ṿ
public static final DatabaseManager db = DatabaseManager.getInstance();
public static TheVoidRoad instance;
public TheVoidRoad(){
super();
instance = this;
}
@Override
public void onEnable(){
saveResource("materials.txt", false);
saveResource("names.txt", false);
//Commands
getCommand("void").setExecutor(new VoidCommands());
getCommand("void").setTabCompleter(new VoidCommands());
//Events
getServer().getPluginManager().registerEvents(new HourEvent(), this); //For HourEvent
getServer().getPluginManager().registerEvents(this, this);
getServer().getPluginManager().registerEvents(Merchand.getInstance(), this);
getServer().getPluginManager().registerEvents(new Voids(), this);
getServer().getPluginManager().registerEvents(new BanHourly(), this);
}
@Override

View File

@ -0,0 +1,10 @@
package ovh.herisson.thevoidroad;
public class Tuple<X, Y> {
public final X x;
public final Y y;
public Tuple(X x, Y y) {
this.x = x;
this.y = y;
}
}

View File

@ -1,7 +1,8 @@
package ovh.herisson.thevoidroad.Commands;
package ovh.herisson.thevoidroad;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -12,10 +13,10 @@ import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import ovh.herisson.thevoidroad.TheVoidRoad;
import ovh.herisson.thevoidroad.Voids;
import net.kyori.adventure.text.Component;
public class VoidCommands implements CommandExecutor, TabCompleter{
private final Merchand m = Merchand.getInstance();
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
@ -31,13 +32,19 @@ public class VoidCommands implements CommandExecutor, TabCompleter{
}
switch (args[0]) {
case "score":
Voids.scoreboard().forEach((p, a) -> {
sender.sendMessage(p + " : " + a);
});
return true;
if(!sender.hasPermission("void.score")){
Voids.scoreboard().forEach((p, a) -> {
sender.sendMessage(p + " : " + a);
});
return true;
}
return false;
case "give":
//TODO(Balance): Give to a player
return true;
if(args.length < 2) return false;
Player target = Bukkit.getPlayer(args[1]);
if(target != null && sender instanceof Player ply && Integer.parseInt(args[2]) > 0)
Voids.give(ply,target, Integer.parseInt(args[2]));
break;
case "event":
//TODO(event) manage event
return true;
@ -47,21 +54,42 @@ public class VoidCommands implements CommandExecutor, TabCompleter{
case "setspawn":
return setspawn(sender);
case "init":
return init();
m.regenerate();
Bukkit.getServer().sendMessage(Component.text(m.getLocation().toString()));
DatabaseManager.getInstance().setConfig("init", "true");
return true;
case "reset":
return reset();
DatabaseManager.getInstance().setConfig("init", "false");
break;
case "unban":
UUID target_uuid = Bukkit.getPlayerUniqueId(args[2]);
DatabaseManager.getInstance().unban(target_uuid);
return true;
case "skip":
//TODO(Merchand): Skip trade
break;
case "goto":
if(sender instanceof Player ply && m.getLocation() != null){
ply.teleport(m.getLocation());
}else{
sender.sendMessage("You can't teleport!");
}
break;
case "bring":
if(sender instanceof Player ply && m.getLocation() != null){
m.teleport(ply.getLocation());
}else{
return false;
}
break;
case "balance":
if(args.length < 5) return false;
switch (args[2]) {
case "set":
Player target = Bukkit.getPlayer(args[3]);
Voids.set(target, Integer.parseInt(args[4]));
Player target_ = Bukkit.getPlayer(args[3]);
Voids.set(target_, Integer.parseInt(args[4]));
return true;
case "add":
case "sub":
sender.sendMessage("TODO"); //TODO
}
return false;
}
@ -74,7 +102,7 @@ public class VoidCommands implements CommandExecutor, TabCompleter{
if(sender instanceof Player ply){
Location loc = ply.getLocation();
WorldBorder border = ply.getWorld().getWorldBorder();
ply.getWorld().setSpawnLocation(loc);
border.setCenter(loc);
border.setSize(750);
@ -83,24 +111,18 @@ public class VoidCommands implements CommandExecutor, TabCompleter{
return false;
}
private boolean init(){
//TODO(merchand): init the game
return true;
}
private boolean reset(){
return false;
}
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) { //TODO: add all commands
ArrayList<String> list = new ArrayList<>();
if(args.length == 1){
list.addAll(List.of("give","event", "score"));
list.addAll(List.of("give","event"));
if(sender.hasPermission("void.manage")){
list.add("manage");
}
if(sender.hasPermission("void.score")){
list.add("score");
}
}
if(args.length >= 2){
switch (args[0]) {
@ -110,7 +132,7 @@ public class VoidCommands implements CommandExecutor, TabCompleter{
return list;
case "manage":
if(sender.hasPermission("void.manage")){
if(args[1] == "balance"){
if(args[1] == "balance" && args.length <= 3){
list.addAll(List.of("set", "add", "sub"));
return list;
}

View File

@ -5,59 +5,74 @@ import java.util.HashMap;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.scoreboard.Criteria;
import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Objective;
import org.bukkit.scoreboard.Score;
import org.bukkit.scoreboard.Scoreboard;
public final class Voids{
import net.kyori.adventure.bossbar.BossBar;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.title.Title;
private Voids(){} // Prohib the instantiation
public final class Voids implements Listener{
private static HashMap<Player, BossBar> bossbars = new HashMap<>();
private static final NamespacedKey voids = new NamespacedKey(TheVoidRoad.instance, "voids");
public static int get(Player ply){
try {
return TheVoidRoad.db.getVoids(ply.getUniqueId());
} catch(SQLException e){
e.printStackTrace();
if(ply.getPersistentDataContainer().has(voids)){
return ply.getPersistentDataContainer().get(voids, PersistentDataType.INTEGER);
}
return 0;
return TheVoidRoad.db.getVoids(ply.getUniqueId());
}
public static void set(Player ply, int amount){
try {
TheVoidRoad.db.setVoids(ply.getUniqueId(), amount);
} catch(SQLException e){
e.printStackTrace();
}
ply.getPersistentDataContainer().set(voids, PersistentDataType.INTEGER, amount);
UpdateVoids(ply);
}
public static void add(Player ply, int amount){
try {
int curr = TheVoidRoad.db.getVoids(ply.getUniqueId());
TheVoidRoad.db.setVoids(ply.getUniqueId(), curr + amount);
} catch(SQLException e){
e.printStackTrace();
}
int curr = get(ply);
set(ply, curr + amount);
UpdateVoids(ply);
}
public static boolean subtract(Player ply, int amount, boolean force){
try {
int curr = TheVoidRoad.db.getVoids(ply.getUniqueId());
if(curr - amount < 0 && !force) return false;
TheVoidRoad.db.setVoids(ply.getUniqueId(), curr - amount);
} catch(SQLException e){
e.printStackTrace();
}
int curr = get(ply);
if(curr - amount < 0 && !force) return false;
set(ply, curr - amount);
UpdateVoids(ply);
return true;
}
public static boolean give(Player giver, Player receiver, int amount){
if(subtract(giver, amount, false)){
add(receiver, amount);
return true;
}
return false;
if( amount < 0 || !subtract(giver, amount, false))
return false;
add(receiver, amount);
giver.sendMessage("Vous avez donné " + amount + TheVoidRoad.CoinGlyph + " à " + receiver.getName());
receiver.sendMessage("Vous avez reçu " + amount + TheVoidRoad.CoinGlyph + " de " + giver.getName());
receiver.showTitle(Title.title(Component.empty(), Component.text("+" + amount + TheVoidRoad.CoinGlyph + " from " + giver.getName()).color(NamedTextColor.GREEN)));
return true;
}
public static void save(Player ply){
int curr = get(ply);
TheVoidRoad.db.setVoids(ply.getUniqueId(), curr);
}
public static HashMap<Player, Integer> scoreboard(){
Bukkit.getServer().forEachAudience(a -> {
if(a instanceof Player ply) save(ply);
});
HashMap<Player, Integer> ret = new HashMap<>();
try {
HashMap<UUID, Integer> scores_uuid = TheVoidRoad.db.getVoidsScoreboard();
@ -69,4 +84,33 @@ public final class Voids{
}
return ret;
}
public static void UpdateVoids(Player ply){
Integer count = get(ply);
String countString = count.toString() + TheVoidRoad.CoinGlyph;
Scoreboard sb = Bukkit.getScoreboardManager().getMainScoreboard();
Objective o = sb.getObjective("VOIDS") != null ? sb.getObjective("VOIDS") : sb.registerNewObjective("VOIDS", Criteria.DUMMY, "voids");
o.setDisplaySlot(DisplaySlot.BELOW_NAME);
o.displayName(Component.text(TheVoidRoad.CoinGlyph));
Score s = o.getScore(ply);
s.setScore(count);
BossBar bb = bossbars.containsKey(ply) ?
bossbars.get(ply).name(Component.text(countString)) :
BossBar.bossBar(Component.text(countString), 1, BossBar.Color.GREEN, BossBar.Overlay.PROGRESS);
bossbars.put(ply, bb);
ply.showBossBar(bb);
}
@EventHandler
public void UpdateVoids(PlayerJoinEvent e){
UpdateVoids(e.getPlayer());
}
@EventHandler
public void SaveToDbBeforeQuit(PlayerQuitEvent e){
save(e.getPlayer());
}
}

View File

@ -0,0 +1,272 @@
STONE
GRANITE
POLISHED_GRANITE
DIORITE
POLISHED_DIORITE
ANDESITE
POLISHED_ANDESITE
DEEPSLATE
COBBLED_DEEPSLATE
POLISHED_DEEPSLATE
CALCITE
TUFF
DRIPSTONE_BLOCK
GRASS_BLOCK
DIRT
COARSE_DIRT
PODZOL
ROOTED_DIRT
MUD
COBBLESTONE
OAK_PLANKS
SPRUCE_PLANKS
BIRCH_PLANKS
JUNGLE_PLANKS
ACACIA_PLANKS
CHERRY_PLANKS
DARK_OAK_PLANKS
MANGROVE_PLANKS
BAMBOO_PLANKS
BAMBOO_MOSAIC
OAK_SAPLING
SPRUCE_SAPLING
BIRCH_SAPLING
JUNGLE_SAPLING
ACACIA_SAPLING
CHERRY_SAPLING
DARK_OAK_SAPLING
MANGROVE_PROPAGULE
SAND
RED_SAND
GRAVEL
OAK_LOG
SPRUCE_LOG
BIRCH_LOG
JUNGLE_LOG
ACACIA_LOG
CHERRY_LOG
DARK_OAK_LOG
MANGROVE_LOG
MANGROVE_ROOTS
MUDDY_MANGROVE_ROOTS
BAMBOO_BLOCK
OAK_WOOD
SPRUCE_WOOD
BIRCH_WOOD
JUNGLE_WOOD
ACACIA_WOOD
CHERRY_WOOD
DARK_OAK_WOOD
MANGROVE_WOOD
OAK_LEAVES
SPRUCE_LEAVES
BIRCH_LEAVES
JUNGLE_LEAVES
ACACIA_LEAVES
CHERRY_LEAVES
DARK_OAK_LEAVES
MANGROVE_LEAVES
AZALEA_LEAVES
FLOWERING_AZALEA_LEAVES
GLASS
SANDSTONE
SHORT_GRASS
AZALEA
FLOWERING_AZALEA
SEA_PICKLE
WHITE_WOOL
BROWN_MUSHROOM
RED_MUSHROOM
SUGAR_CANE
KELP
BAMBOO
BRICKS
BOOKSHELF
MOSSY_COBBLESTONE
OBSIDIAN
TORCH
CHEST
CRAFTING_TABLE
FURNACE
LADDER
SNOW
ICE
SNOW_BLOCK
CACTUS
CLAY
JUKEBOX
PUMPKIN
STONE_BRICKS
PACKED_MUD
IRON_BARS
CHAIN
MELON
LILY_PAD
ENCHANTING_TABLE
COBBLESTONE_WALL
ANVIL
HAY_BLOCK
TERRACOTTA
PACKED_ICE
RED_SANDSTONE
MAGMA_BLOCK
BONE_BLOCK
WHITE_CONCRETE
ORANGE_CONCRETE
MAGENTA_CONCRETE
LIGHT_BLUE_CONCRETE
YELLOW_CONCRETE
LIME_CONCRETE
PINK_CONCRETE
GRAY_CONCRETE
LIGHT_GRAY_CONCRETE
CYAN_CONCRETE
PURPLE_CONCRETE
BLUE_CONCRETE
BROWN_CONCRETE
GREEN_CONCRETE
RED_CONCRETE
BLACK_CONCRETE
TURTLE_EGG
BLUE_ICE
SCAFFOLDING
REDSTONE
REDSTONE_TORCH
REDSTONE_BLOCK
REPEATER
COMPARATOR
PISTON
STICKY_PISTON
SLIME_BLOCK
HONEY_BLOCK
OBSERVER
HOPPER
DISPENSER
DROPPER
LECTERN
TARGET
LEVER
LIGHTNING_ROD
DAYLIGHT_DETECTOR
TRIPWIRE_HOOK
TRAPPED_CHEST
TNT
REDSTONE_LAMP
NOTE_BLOCK
STONE_BUTTON
STONE_PRESSURE_PLATE
LIGHT_WEIGHTED_PRESSURE_PLATE
HEAVY_WEIGHTED_PRESSURE_PLATE
OAK_PRESSURE_PLATE
SPRUCE_PRESSURE_PLATE
BIRCH_PRESSURE_PLATE
JUNGLE_PRESSURE_PLATE
ACACIA_PRESSURE_PLATE
CHERRY_PRESSURE_PLATE
DARK_OAK_PRESSURE_PLATE
MANGROVE_PRESSURE_PLATE
BAMBOO_PRESSURE_PLATE
RAIL
SADDLE
MINECART
SCUTE
FLINT_AND_STEEL
APPLE
ARROW
COAL
CHARCOAL
DIAMOND
EMERALD
LAPIS_LAZULI
AMETHYST_SHARD
RAW_IRON
IRON_INGOT
RAW_COPPER
COPPER_INGOT
RAW_GOLD
GOLD_INGOT
STICK
BOWL
MUSHROOM_STEW
STRING
FEATHER
GUNPOWDER
WHEAT_SEEDS
WHEAT
BREAD
FLINT
PORKCHOP
PAINTING
GOLDEN_APPLE
BUCKET
WATER_BUCKET
LAVA_BUCKET
POWDER_SNOW_BUCKET
SNOWBALL
LEATHER
MILK_BUCKET
BRICK
CLAY_BALL
DRIED_KELP_BLOCK
PAPER
BOOK
SLIME_BALL
EGG
COD
SALMON
TROPICAL_FISH
PUFFERFISH
INK_SAC
COCOA_BEANS
WHITE_DYE
ORANGE_DYE
MAGENTA_DYE
LIGHT_BLUE_DYE
YELLOW_DYE
LIME_DYE
PINK_DYE
GRAY_DYE
LIGHT_GRAY_DYE
CYAN_DYE
PURPLE_DYE
BLUE_DYE
BROWN_DYE
GREEN_DYE
RED_DYE
BLACK_DYE
BONE_MEAL
BONE
SUGAR
COOKIE
FILLED_MAP
MELON_SLICE
DRIED_KELP
PUMPKIN_SEEDS
MELON_SEEDS
BEEF
CHICKEN
ROTTEN_FLESH
GOLD_NUGGET
GLASS_BOTTLE
SPIDER_EYE
CARROT
POTATO
POISONOUS_POTATO
RABBIT
RABBIT_FOOT
RABBIT_HIDE
LEAD
MUTTON
BEETROOT
TOTEM_OF_UNDYING
IRON_NUGGET
PHANTOM_MEMBRANE
NAUTILUS_SHELL
GOAT_HORN
SWEET_BERRIES
GLOW_BERRIES
HONEYCOMB
BEE_NEST
HONEY_BOTTLE
HONEYCOMB_BLOCK
CANDLE

View File

@ -0,0 +1,365 @@
Ave
Civi
Denni
Gen
Genner
Gennie
Habbie
Nary
Norm
Norma
Norman
Ordie
Reg
Reggie
Ressie
Settler
Sitti
Sity
Stan
Standa
Unem
Urbie
Verage
Aegis
Armsworth
Bell
Boots
Bootsmith
Buckle
Buckler
Bullwark
Busby
Chains
Chestington
Coal
Cole
Diamonds
Feaver
Gow
Guard
Helms
Helmut
Ingot
Irons
Koval
Kowal
Lava
Magma
Mails
Schmits
Shieldrick
Shields
Ward
Barry
Beefs
Berry
Bones
Boucher
Brawn
Brawnworth
Brew
Butch
Chows
Cole
Fleischer
Grubs
Hash
Kelps
Metzner
Porkington
Rabbits
Rations
Slager
Stewie
Stews
Atlas
Banner
Bannerman
Banners
Compass
Discovery
Entrepid
Explorer
Geo
Glaser
Glass
Glazer
Globetrots
Globetrotter
Journeyman
Journeys
Path
Paths
Pioneer
Roamer
Strider
Tracer
Trailer
Trails
Trekker
Treks
Trips
Voyage
Voyager
Wander
Wayfare
Chapman
Clark
Docs
Ender
Enders
Foot
Foots
Glaser
Glass
Glazer
Glow
Heals
Ingot
Ingots
Lapis
Lazuli
Mendings
Mends
Patches
Rot
Rott
Salve
Scute
Scutes
Soothe
Warts
Akkerman
Apple
Appleton
Beetington
Beets
Boer
Carrots
Cookie
Cowman
Crops
Gorter
Grows
Harrow
Harvester
Harvests
Koeman
Landman
Miller
Morar
Moraru
Mulder
Plants
Plower
Plowright
Pumpkin
Pumpking
Ranch
Rancher
Reaper
Seeds
Sow
Tater
Taters
Tender
Till
Tiller
Tots
Wheats
Angle
Angler
Angles
Baits
Baitsman
Boatman
Boatwright
Bob
Cast
Casts
Chum
Coal
Cod
Cole
Fisch
Fisher
Haul
Lure
Marin
Marine
Net
Nets
Piscator
Pisces
Puff
Puffer
Rod
Rodman
Rods
Strings
Trawler
Trawlie
Waters
Wave
Archer
Arrowsmith
Bo
Bolt
Bowman
Bows
Bowyer
Bullseye
Dart
Feathers
Flint
Hook
Hooks
Plume
Quiver
Sticks
Trips
Attire
Boots
Cap
Caps
Flint
Garb
Glover
Hide
Hides
Hyde
Leatherman
Pantington
Raggers
Rags
Riggings
Sadler
Sandler
Scute
Shoemaker
Skinner
Skins
Tailor
Tan
Tanner
Threads
Tunics
Book
Books
Clocks
Compass
Dinter
Glass
Ink
Inkworth
Lerner
Page
Papers
Quill
Quills
Reads
Scriver
Shriver
Andy
Baumann
Boulder
Brick
Bricks
Brock
Chisel
Chisels
Clay
Claye
Cotta
Dio
Granite
Mason
Pebble
Pillars
Quartz
Rock
Rocky
Stone
Terra
Tyler
Blockhead
Bonehead
Dimdim
Dimwit
Dingbat
Dolt
Doofus
Dope
Dumbbell
Dummydum
Dummydumdum
Dunce
Ignoramus
Loony
Muttonhead
Nincompoop
Nitty
Nutters
Pinhead
Simpleton
Simpleton II
Slowpoke
Tomfool
Beds
Color
Dye
Dyer
Fuller
Paint
Paints
Pigment
Shear
Shears
Sleep
Sleeps
Wool
Wools
Woolsworth
Apparatus
Ax
Axington
Carpenter
Flint
Gizmo
Hammer
Hammers
Hatchet
Ingot
Ingots
Iron
Irons
Pick
Steels
Tools
Toolsworth
Arm
Arming
Arms
Axe
Bell
Blade
Blades
Brand
Claymore
Coal
Cole
Dirk
Edge
Epee
Falchio
Falchion
Glaive
Glaives
Hatchet
Ingot
Kris
Saber
Shank
Swords
Swordsmith

View File

@ -16,6 +16,9 @@ permissions:
void.manage:
description: "GameMaster's command"
default: op
void.score:
description: "score the voids"
default: op
void.balance:
description: "User of thevoidroad"
default: not op