Skip to content
This repository has been archived by the owner on Jan 3, 2024. It is now read-only.

Feature/remit money #47

Merged
merged 13 commits into from
Jun 3, 2022
102 changes: 78 additions & 24 deletions src/main/java/tech/inudev/metaverseplugin/define/Money.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package tech.inudev.metaverseplugin.define;

import lombok.Data;
import lombok.Getter;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
Expand All @@ -16,7 +15,9 @@
*/
public class Money {
@Getter
private int amount;
private int ownAmount;
@Getter
private int total = 0;
private UUID playerUUID;
private String bankName;
private final boolean isBankMoney;
Expand All @@ -31,7 +32,7 @@ public Money(UUID playerUUID) {
if (amount == null) {
throw new IllegalArgumentException("引数に対応するデータが存在しません。");
}
this.amount = amount;
this.ownAmount = amount;
this.playerUUID = playerUUID;
this.isBankMoney = false;
}
Expand All @@ -50,7 +51,7 @@ public Money(String bankName) {
if (amount == null) {
throw new IllegalArgumentException("引数に対応するデータが存在しません。");
}
this.amount = amount;
this.ownAmount = amount;
this.bankName = bankName;
this.isBankMoney = true;
}
Expand All @@ -64,54 +65,100 @@ public void add(int value) {
if (value < 0) {
throw new IllegalArgumentException("負の値は引数に指定できません。");
}
this.amount += value;
total += value;
}

/**
* 金額への減算
* 減算するお金が足りない場合、プレイヤーへ通知する
*
* @param value 減算する金額
* @return 正常に処理できたかどうか
* @return 正常に処理を完了したらtrueを返す。そうでなければfalseを返す。
*/
public boolean remove(int value) {
if (value < 0) {
throw new IllegalArgumentException("負の値は引数に指定できません。");
}
if (this.amount >= value) {
this.amount -= value;
if (ownAmount + total >= value) {
total -= value;
return true;
} else {
if (this.isBankMoney || playerUUID == null) {
return false;
}
// 所持金による取引の場合、プレイヤーへお金不足を通知
Player player = Bukkit.getPlayer(playerUUID);
if (player != null && player.isOnline()) {
player.sendMessage(Component.text(
"取引するためのお金が足りません"));
if (!isBankMoney && playerUUID != null) {
sendMessageToPlayer(playerUUID, "取引するためのお金が足りません。");
}
return false;
}
}

/**
* 取引後の金額をDatabaseへ反映する
* 取引の送金処理を実行する。
*
* @return 正常終了したかどうか
* @param partnerUUID 取引相手のプレイヤーUUID
* @return 送金処理が正常に完了したならばtrueを返す。そうでなければfalseを返す。
*/
public boolean push() {
if (this.isBankMoney) {
if (this.bankName.isEmpty()) {
public boolean push(UUID partnerUUID) {
return remitMoney(partnerUUID.toString());
}

/**
* 取引の送金処理を実行する。
*
* @param partnerBankName 取引相手の口座名
* @return 送金処理が正常に完了したならばtrueを返す。そうでなければfalseを返す。
*/
public boolean push(String partnerBankName) {
if (isUUID(partnerBankName)) {
throw new IllegalArgumentException("UUID形式の文字列は引数に指定できません。");
}
return remitMoney(partnerBankName);
}

private boolean remitMoney(String partnerName) {
Integer partnerAmount = DatabaseUtil.loadMoneyAmount(partnerName);
if (partnerAmount == null) {
throw new IllegalArgumentException("引数に対応するデータが存在しません。");
}
// totalが正のとき、取引相手のお金が足りなければ処理失敗
if (partnerAmount < total) {
if (!isBankMoney && playerUUID != null) {
sendMessageToPlayer(playerUUID, "取引先に問題が発生し、送金処理に失敗しました。");
}
// 取引相手にお金不足を通知
if (isUUID(partnerName)) {
sendMessageToPlayer(UUID.fromString(partnerName), "取引するためのお金が足りません。");
}
return false;
}

if (isBankMoney) {
if (bankName.isEmpty()) {
// 取引先に処理失敗を通知
if (isUUID(partnerName)) {
sendMessageToPlayer(UUID.fromString(partnerName), "送金処理に失敗しました。");
}
return false;
}
DatabaseUtil.updateMoneyAmount(this.bankName, this.amount);
DatabaseUtil.remitTransaction(
bankName,
ownAmount + total,
partnerName,
partnerAmount - total);
} else {
if (this.playerUUID == null) {
if (playerUUID == null) {
// 取引先に処理失敗を通知
if (isUUID(partnerName)) {
sendMessageToPlayer(UUID.fromString(partnerName), "送金処理に失敗しました。");
}
return false;
}
DatabaseUtil.updateMoneyAmount(this.playerUUID.toString(), this.amount);
DatabaseUtil.remitTransaction(
playerUUID.toString(),
ownAmount + total,
partnerName,
partnerAmount - total);
}
ownAmount += total;
total = 0;
return true;
}

Expand Down Expand Up @@ -172,4 +219,11 @@ public static boolean isUUID(String name) {
String regex = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
return name.toLowerCase().matches(regex);
}

private static void sendMessageToPlayer(UUID playerUUID, String message) {
Player player = Bukkit.getPlayer(playerUUID);
if (player != null && player.isOnline()) {
player.sendMessage(Component.text(message));
}
}
}
77 changes: 67 additions & 10 deletions src/main/java/tech/inudev/metaverseplugin/utils/DatabaseUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public static void connect() {
ConfigHandler configHandler = Metaverseplugin.getInstance().getConfigHandler();
try {
connection = DriverManager.getConnection(databaseUrl, configHandler.getDatabaseUsername(), configHandler.getDatabasePassword());
connection.setAutoCommit(false);
} catch (SQLException e) {
throw new RuntimeException(e);
}
Expand Down Expand Up @@ -82,32 +83,49 @@ PRIMARY KEY ('name'))
preparedStatement.execute();
preparedStatement.close();
} catch (SQLException e) {
throw new RuntimeException(e);
try {
connection.rollback();
} catch (SQLException e2) {
throw new RuntimeException(e2);
}
}
}

/**
* Databaseに新たに金額データを登録する
* Databaseに新たに金額データを登録する。
* 処理が完了した場合は、トランザクションをコミットする。
* 一方で、処理中にエラーが発生した場合は、トランザクションをロールバックする。
*
* @param name 金額データの名前
*/
public static void createMoneyRecord(String name) {
try {
createMoneyTable();

if (loadMoneyAmount(name) != null) {
throw new SQLException();
}

PreparedStatement preparedStatement = connection.prepareStatement("""
INSERT INTO money (name, amount) VALUES (?, 0)
""");
preparedStatement.setString(1, name);
preparedStatement.execute();
preparedStatement.close();

commitTransaction();
} catch (SQLException e) {
throw new RuntimeException(e);
try {
connection.rollback();
} catch (SQLException e2) {
throw new RuntimeException(e2);
}
}
}

/**
* Databaseのnameに対応する金額データを取得する
* Databaseのnameに対応する金額データを取得する。
* 処理中にエラーが発生した場合は、トランザクションをロールバックする。
*
* @param name Databaseの検索に使用する金額データの名前
* @return 金額。Database上にデータが存在しなければnullを返す
Expand All @@ -126,20 +144,43 @@ public static Integer loadMoneyAmount(String name) {
preparedStatement.close();
return result;
} catch (SQLException e) {
throw new RuntimeException(e);
try {
connection.rollback();
return null;
} catch (SQLException e2) {
throw new RuntimeException(e2);
}
}
}

/**
* Database上の金額データを更新する
* 送金処理のトランザクションを実行する。
* 処理が完了した場合は、トランザクションをコミットする。
* 一方で、処理中にエラーが発生した場合は、トランザクションはロールバックする。
*
* @param bankName 金額データの名前
* @param amount 金額データの金額
* @param selfName 自分の金額データの名前
* @param selfAmount 自分の金額データの金額
* @param partnerName 相手の金額データの名前
* @param partnerAmount 相手の金額データの金額
*/
public static void updateMoneyAmount(String bankName, int amount) {
public static void remitTransaction(
String selfName,
int selfAmount,
String partnerName,
int partnerAmount) {
updateMoneyAmount(selfName, selfAmount);
updateMoneyAmount(partnerName, partnerAmount);
commitTransaction();
}

private static void updateMoneyAmount(String bankName, int amount) {
try {
createMoneyTable();

if (loadMoneyAmount(bankName) == null) {
throw new SQLException();
}

PreparedStatement preparedStatement = connection.prepareStatement("""
UPDATE money SET amount=? WHERE name=?
""");
Expand All @@ -148,7 +189,23 @@ public static void updateMoneyAmount(String bankName, int amount) {
preparedStatement.execute();
preparedStatement.close();
} catch (SQLException e) {
throw new RuntimeException(e);
try {
connection.rollback();
} catch (SQLException e2) {
throw new RuntimeException(e2);
}
}
}

private static void commitTransaction() {
try {
connection.commit();
} catch (SQLException e) {
try {
connection.rollback();
} catch (SQLException e2) {
throw new RuntimeException(e2);
}
}
}
}
2 changes: 1 addition & 1 deletion src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ description: めたばーすぷらぐいん(仮)
website: https://www.inu-dev.tech/
depend:
- floodgate
- Geyser-Spigot
- Geyser-Spigot