Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
238c01baf4 | ||
|
|
5a4bdd343c | ||
|
|
d916502f58 | ||
|
|
1791365e0f | ||
|
|
de2a86c859 | ||
|
|
5aeed01e38 | ||
|
|
6ab1af99da | ||
|
|
c7b2d218ef | ||
|
|
01ae462b72 | ||
|
|
eb603e7ee9 | ||
|
|
b67b29def5 | ||
|
|
d22d9b603b | ||
|
|
0d684c1400 |
12
pom.xml
12
pom.xml
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>cosmic-maplestory</groupId>
|
||||
@@ -52,7 +53,8 @@
|
||||
<!-- Maven plugins -->
|
||||
<maven-surefire-plugin.version>3.2.5</maven-surefire-plugin.version> <!-- For running unit tests -->
|
||||
<maven-jar-plugin.version>3.4.1</maven-jar-plugin.version> <!-- Disabled. (for building thin jar) -->
|
||||
<maven-assembly-plugin.version>3.7.1</maven-assembly-plugin.version> <!-- For packaging the executable fat jar -->
|
||||
<maven-assembly-plugin.version>3.7.1
|
||||
</maven-assembly-plugin.version> <!-- For packaging the executable fat jar -->
|
||||
|
||||
<!-- Dependencies -->
|
||||
<slf4j-api.version>2.0.13</slf4j-api.version> <!-- Logging facade -->
|
||||
@@ -180,6 +182,12 @@
|
||||
<version>${mockito.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-junit-jupiter</artifactId>
|
||||
<version>${mockito.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -2068,7 +2068,7 @@ public class Character extends AbstractCharacterObject {
|
||||
this.getCashShop().gainCash(1, nxGain);
|
||||
|
||||
if (YamlConfig.config.server.USE_ANNOUNCE_NX_COUPON_LOOT) {
|
||||
showHint("You have earned #e#b" + nxGain + " NX#k#n. (" + this.getCashShop().getCash(1) + " NX)", 300);
|
||||
showHint("You have earned #e#b" + nxGain + " NX#k#n. (" + this.getCashShop().getCash(CashShop.NX_CREDIT) + " NX)", 300);
|
||||
}
|
||||
|
||||
this.getMap().pickItemDrop(pickupPacket, mapitem);
|
||||
@@ -2120,7 +2120,7 @@ public class Character extends AbstractCharacterObject {
|
||||
this.getCashShop().gainCash(1, nxGain);
|
||||
|
||||
if (YamlConfig.config.server.USE_ANNOUNCE_NX_COUPON_LOOT) {
|
||||
showHint("You have earned #e#b" + nxGain + " NX#k#n. (" + this.getCashShop().getCash(1) + " NX)", 300);
|
||||
showHint("You have earned #e#b" + nxGain + " NX#k#n. (" + this.getCashShop().getCash(CashShop.NX_CREDIT) + " NX)", 300);
|
||||
}
|
||||
} else if (applyConsumeOnPickup(mItem.getItemId())) {
|
||||
} else if (InventoryManipulator.addFromDrop(client, mItem, true)) {
|
||||
@@ -6063,7 +6063,8 @@ public class Character extends AbstractCharacterObject {
|
||||
sendPacket(PacketCreator.giveBuff(energybar, 0, stat));
|
||||
sendPacket(PacketCreator.showOwnBuffEffect(energycharge.getId(), 2));
|
||||
getMap().broadcastPacket(this, PacketCreator.showBuffEffect(id, energycharge.getId(), 2));
|
||||
getMap().broadcastPacket(this, PacketCreator.giveForeignBuff(energybar, stat));
|
||||
getMap().broadcastPacket(this, PacketCreator.giveForeignPirateBuff(id, energycharge.getId(),
|
||||
ceffect.getDuration(), stat));
|
||||
}
|
||||
if (energybar >= 10000 && energybar < 11000) {
|
||||
energybar = 15000;
|
||||
|
||||
@@ -312,6 +312,10 @@ public class ItemId {
|
||||
return itemId == NX_CARD_100 || itemId == NX_CARD_250;
|
||||
}
|
||||
|
||||
public static boolean isCashPackage(int itemId) {
|
||||
return itemId / 10000 == 910;
|
||||
}
|
||||
|
||||
// Face expression
|
||||
private static final int FACE_EXPRESSION_MIN = 5160000;
|
||||
private static final int FACE_EXPRESSION_MAX = 5160014;
|
||||
|
||||
@@ -82,6 +82,11 @@ public class ByteBufInPacket implements InPacket {
|
||||
return byteBuf.readerIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof ByteBufInPacket other && byteBuf.equals(other.byteBuf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final int readerIndex = byteBuf.readerIndex();
|
||||
|
||||
@@ -91,4 +91,9 @@ public class ByteBufOutPacket implements OutPacket {
|
||||
public void skip(int numberOfBytes) {
|
||||
writeBytes(new byte[numberOfBytes]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof ByteBufOutPacket other && byteBuf.equals(other.byteBuf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ public final class CashOperationHandler extends AbstractPacketHandler {
|
||||
CashItem cItem = CashItemFactory.getItem(p.readInt());
|
||||
Map<String, String> recipient = Character.getCharacterFromDatabase(p.readString());
|
||||
String message = p.readString();
|
||||
if (!canBuy(chr, cItem, cs.getCash(4)) || message.length() < 1 || message.length() > 73) {
|
||||
if (!canBuy(chr, cItem, cs.getCash(CashShop.NX_PREPAID)) || message.isEmpty() || message.length() > 73) {
|
||||
c.enableCSActions();
|
||||
return;
|
||||
}
|
||||
@@ -405,7 +405,7 @@ public final class CashOperationHandler extends AbstractPacketHandler {
|
||||
c.sendPacket(PacketCreator.showCash(c.getPlayer()));
|
||||
} else if (action == 0x2E) { //name change
|
||||
CashItem cItem = CashItemFactory.getItem(p.readInt());
|
||||
if (cItem == null || !canBuy(chr, cItem, cs.getCash(4))) {
|
||||
if (cItem == null || !canBuy(chr, cItem, cs.getCash(CashShop.NX_PREPAID))) {
|
||||
c.sendPacket(PacketCreator.showCashShopMessage((byte) 0));
|
||||
c.enableCSActions();
|
||||
return;
|
||||
@@ -434,7 +434,7 @@ public final class CashOperationHandler extends AbstractPacketHandler {
|
||||
c.enableCSActions();
|
||||
} else if (action == 0x31) { //world transfer
|
||||
CashItem cItem = CashItemFactory.getItem(p.readInt());
|
||||
if (cItem == null || !canBuy(chr, cItem, cs.getCash(4))) {
|
||||
if (cItem == null || !canBuy(chr, cItem, cs.getCash(CashShop.NX_PREPAID))) {
|
||||
c.sendPacket(PacketCreator.showCashShopMessage((byte) 0));
|
||||
c.enableCSActions();
|
||||
return;
|
||||
|
||||
@@ -24,27 +24,34 @@ import client.inventory.Item;
|
||||
import net.AbstractPacketHandler;
|
||||
import net.packet.InPacket;
|
||||
import server.CashShop;
|
||||
import server.CashShop.CashShopSurpriseResult;
|
||||
import tools.PacketCreator;
|
||||
import tools.Pair;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author RonanLana
|
||||
* @author Ponk
|
||||
*/
|
||||
public class CashShopSurpriseHandler extends AbstractPacketHandler {
|
||||
|
||||
@Override
|
||||
public final void handlePacket(InPacket p, Client c) {
|
||||
CashShop cs = c.getPlayer().getCashShop();
|
||||
|
||||
if (cs.isOpened()) {
|
||||
Pair<Item, Item> cssResult = cs.openCashShopSurprise();
|
||||
|
||||
if (cssResult != null) {
|
||||
Item cssItem = cssResult.getLeft(), cssBox = cssResult.getRight();
|
||||
c.sendPacket(PacketCreator.onCashGachaponOpenSuccess(c.getAccID(), cssBox.getSN(), cssBox.getQuantity(), cssItem, cssItem.getItemId(), cssItem.getQuantity(), true));
|
||||
c.sendPacket(PacketCreator.showCashInventory(c));
|
||||
} else {
|
||||
c.sendPacket(PacketCreator.onCashItemGachaponOpenFailed());
|
||||
}
|
||||
if (!cs.isOpened()) {
|
||||
return;
|
||||
}
|
||||
|
||||
long cashId = p.readLong();
|
||||
Optional<CashShopSurpriseResult> result = cs.openCashShopSurprise(cashId);
|
||||
if (result.isEmpty()) {
|
||||
c.sendPacket(PacketCreator.onCashItemGachaponOpenFailed());
|
||||
return;
|
||||
}
|
||||
|
||||
Item usedCashShopSurprise = result.get().usedCashShopSurprise();
|
||||
Item reward = result.get().reward();
|
||||
c.sendPacket(PacketCreator.onCashGachaponOpenSuccess(c.getAccID(), usedCashShopSurprise.getCashId(),
|
||||
usedCashShopSurprise.getQuantity(), reward, reward.getItemId(), reward.getQuantity(), true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import net.server.Server;
|
||||
import net.server.channel.Channel;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import server.CashShop;
|
||||
import server.ItemInformationProvider;
|
||||
import server.MTSItemInfo;
|
||||
import tools.DatabaseConnection;
|
||||
@@ -402,7 +403,7 @@ public final class MTSHandler extends AbstractPacketHandler {
|
||||
ResultSet rs = ps.executeQuery();
|
||||
if (rs.next()) {
|
||||
int price = rs.getInt("price") + 100 + (int) (rs.getInt("price") * 0.1); // taxes
|
||||
if (c.getPlayer().getCashShop().getCash(4) >= price) { // FIX
|
||||
if (c.getPlayer().getCashShop().getCash(CashShop.NX_PREPAID) >= price) { // FIX
|
||||
boolean alwaysnull = true;
|
||||
for (Channel cserv : Server.getInstance().getAllChannels()) {
|
||||
Character victim = cserv.getPlayerStorage().getCharacterById(rs.getInt("seller"));
|
||||
@@ -459,11 +460,11 @@ public final class MTSHandler extends AbstractPacketHandler {
|
||||
ResultSet rs = ps.executeQuery();
|
||||
if (rs.next()) {
|
||||
int price = rs.getInt("price") + 100 + (int) (rs.getInt("price") * 0.1);
|
||||
if (c.getPlayer().getCashShop().getCash(4) >= price) {
|
||||
if (c.getPlayer().getCashShop().getCash(CashShop.NX_PREPAID) >= price) {
|
||||
for (Channel cserv : Server.getInstance().getAllChannels()) {
|
||||
Character victim = cserv.getPlayerStorage().getCharacterById(rs.getInt("seller"));
|
||||
if (victim != null) {
|
||||
victim.getCashShop().gainCash(4, rs.getInt("price"));
|
||||
victim.getCashShop().gainCash(CashShop.NX_PREPAID, rs.getInt("price"));
|
||||
} else {
|
||||
try (PreparedStatement pse = con.prepareStatement("SELECT accountid FROM characters WHERE id = ?")) {
|
||||
pse.setInt(1, rs.getInt("seller"));
|
||||
|
||||
@@ -278,6 +278,10 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
|
||||
getPlayer().gainMeso(gain);
|
||||
}
|
||||
|
||||
public void gainMeso(Double gain) {
|
||||
getPlayer().gainMeso(gain.intValue());
|
||||
}
|
||||
|
||||
public void gainExp(int gain) {
|
||||
getPlayer().gainExp(gain, true, true);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import client.inventory.Pet;
|
||||
import config.YamlConfig;
|
||||
import constants.id.ItemId;
|
||||
import constants.inventory.ItemConstants;
|
||||
import net.jcip.annotations.GuardedBy;
|
||||
import net.server.Server;
|
||||
import provider.Data;
|
||||
import provider.DataProvider;
|
||||
@@ -36,7 +37,6 @@ import provider.DataProviderFactory;
|
||||
import provider.DataTool;
|
||||
import provider.wz.WZFiles;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.PacketCreator;
|
||||
import tools.Pair;
|
||||
|
||||
import java.sql.Connection;
|
||||
@@ -48,6 +48,8 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
@@ -56,8 +58,74 @@ import static java.util.concurrent.TimeUnit.HOURS;
|
||||
|
||||
/*
|
||||
* @author Flav
|
||||
* @author Ponk
|
||||
*/
|
||||
public class CashShop {
|
||||
public static final int NX_CREDIT = 1;
|
||||
public static final int MAPLE_POINT = 2;
|
||||
public static final int NX_PREPAID = 4;
|
||||
|
||||
private final int accountId;
|
||||
private final int characterId;
|
||||
private int nxCredit;
|
||||
private int maplePoint;
|
||||
private int nxPrepaid;
|
||||
private boolean opened;
|
||||
private ItemFactory factory;
|
||||
private final List<Item> inventory = new ArrayList<>();
|
||||
private final List<Integer> wishList = new ArrayList<>();
|
||||
private int notes = 0;
|
||||
private final Lock lock = new ReentrantLock();
|
||||
|
||||
public CashShop(int accountId, int characterId, int jobType) throws SQLException {
|
||||
this.accountId = accountId;
|
||||
this.characterId = characterId;
|
||||
|
||||
if (!YamlConfig.config.server.USE_JOINT_CASHSHOP_INVENTORY) {
|
||||
switch (jobType) {
|
||||
case 0:
|
||||
factory = ItemFactory.CASH_EXPLORER;
|
||||
break;
|
||||
case 1:
|
||||
factory = ItemFactory.CASH_CYGNUS;
|
||||
break;
|
||||
case 2:
|
||||
factory = ItemFactory.CASH_ARAN;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
factory = ItemFactory.CASH_OVERALL;
|
||||
}
|
||||
|
||||
try (Connection con = DatabaseConnection.getConnection()) {
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT `nxCredit`, `maplePoint`, `nxPrepaid` FROM `accounts` WHERE `id` = ?")) {
|
||||
ps.setInt(1, accountId);
|
||||
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
this.nxCredit = rs.getInt("nxCredit");
|
||||
this.maplePoint = rs.getInt("maplePoint");
|
||||
this.nxPrepaid = rs.getInt("nxPrepaid");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Pair<Item, InventoryType> item : factory.loadItems(accountId, false)) {
|
||||
inventory.add(item.getLeft());
|
||||
}
|
||||
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT `sn` FROM `wishlists` WHERE `charid` = ?")) {
|
||||
ps.setInt(1, characterId);
|
||||
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
wishList.add(rs.getInt("sn"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class CashItem {
|
||||
|
||||
private final int sn;
|
||||
@@ -113,19 +181,20 @@ public class CashShop {
|
||||
if (ItemConstants.EXPIRING_ITEMS) {
|
||||
if (period == 1) {
|
||||
switch (itemId) {
|
||||
case ItemId.DROP_COUPON_2X_4H, ItemId.EXP_COUPON_2X_4H: // 4 Hour 2X coupons, the period is 1, but we don't want them to last a day.
|
||||
item.setExpiration(Server.getInstance().getCurrentTime() + HOURS.toMillis(4));
|
||||
case ItemId.DROP_COUPON_2X_4H,
|
||||
ItemId.EXP_COUPON_2X_4H: // 4 Hour 2X coupons, the period is 1, but we don't want them to last a day.
|
||||
item.setExpiration(Server.getInstance().getCurrentTime() + HOURS.toMillis(4));
|
||||
/*
|
||||
} else if(itemId == 5211047 || itemId == 5360014) { // 3 Hour 2X coupons, unused as of now
|
||||
item.setExpiration(Server.getInstance().getCurrentTime() + HOURS.toMillis(3));
|
||||
*/
|
||||
break;
|
||||
case ItemId.EXP_COUPON_3X_2H:
|
||||
item.setExpiration(Server.getInstance().getCurrentTime() + HOURS.toMillis(2));
|
||||
break;
|
||||
default:
|
||||
item.setExpiration(Server.getInstance().getCurrentTime() + DAYS.toMillis(1));
|
||||
break;
|
||||
break;
|
||||
case ItemId.EXP_COUPON_3X_2H:
|
||||
item.setExpiration(Server.getInstance().getCurrentTime() + HOURS.toMillis(2));
|
||||
break;
|
||||
default:
|
||||
item.setExpiration(Server.getInstance().getCurrentTime() + DAYS.toMillis(1));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
item.setExpiration(Server.getInstance().getCurrentTime() + DAYS.toMillis(period));
|
||||
@@ -163,7 +232,6 @@ public class CashShop {
|
||||
|
||||
public static class CashItemFactory {
|
||||
private static volatile Map<Integer, CashItem> items = new HashMap<>();
|
||||
private static volatile List<Integer> randomitemsns = new ArrayList<>();
|
||||
private static volatile Map<Integer, List<Integer>> packages = new HashMap<>();
|
||||
private static volatile List<SpecialCashItem> specialcashitems = new ArrayList<>();
|
||||
|
||||
@@ -171,7 +239,6 @@ public class CashShop {
|
||||
DataProvider etc = DataProviderFactory.getDataProvider(WZFiles.ETC);
|
||||
|
||||
Map<Integer, CashItem> loadedItems = new HashMap<>();
|
||||
List<Integer> onSaleItems = new ArrayList<>();
|
||||
for (Data item : etc.getData("Commodity.img").getChildren()) {
|
||||
int sn = DataTool.getIntConvert("SN", item);
|
||||
int itemId = DataTool.getIntConvert("ItemId", item);
|
||||
@@ -180,13 +247,8 @@ public class CashShop {
|
||||
short count = (short) DataTool.getIntConvert("Count", item, 1);
|
||||
boolean onSale = DataTool.getIntConvert("OnSale", item, 0) == 1;
|
||||
loadedItems.put(sn, new CashItem(sn, itemId, price, period, count, onSale));
|
||||
|
||||
if (onSale) {
|
||||
onSaleItems.add(sn);
|
||||
}
|
||||
}
|
||||
CashItemFactory.items = loadedItems;
|
||||
CashItemFactory.randomitemsns = onSaleItems;
|
||||
|
||||
Map<Integer, List<Integer>> loadedPackages = new HashMap<>();
|
||||
for (Data cashPackage : etc.getData("CashPackage.img").getChildren()) {
|
||||
@@ -213,13 +275,20 @@ public class CashShop {
|
||||
CashItemFactory.specialcashitems = loadedSpecialItems;
|
||||
}
|
||||
|
||||
public static CashItem getRandomCashItem() {
|
||||
if (randomitemsns.isEmpty()) {
|
||||
return null;
|
||||
public static Optional<CashItem> getRandomCashItem() {
|
||||
if (items.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
int rnd = (int) (Math.random() * randomitemsns.size());
|
||||
return items.get(randomitemsns.get(rnd));
|
||||
List<CashItem> itemPool = items.values().stream()
|
||||
.filter(CashItem::isOnSale)
|
||||
.filter(cashItem -> !ItemId.isCashPackage(cashItem.itemId))
|
||||
.toList();
|
||||
return Optional.of(getRandomItem(itemPool));
|
||||
}
|
||||
|
||||
private static CashItem getRandomItem(List<CashItem> items) {
|
||||
return items.get(new Random().nextInt(items.size()));
|
||||
}
|
||||
|
||||
public static CashItem getItem(int sn) {
|
||||
@@ -243,107 +312,26 @@ public class CashShop {
|
||||
public static List<SpecialCashItem> getSpecialCashItems() {
|
||||
return specialcashitems;
|
||||
}
|
||||
|
||||
public static void reloadSpecialCashItems() {//Yay?
|
||||
List<SpecialCashItem> loadedSpecialItems = new ArrayList<>();
|
||||
try (Connection con = DatabaseConnection.getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("SELECT * FROM specialcashitems");
|
||||
ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
loadedSpecialItems.add(new SpecialCashItem(rs.getInt("sn"), rs.getInt("modifier"), rs.getByte("info")));
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
CashItemFactory.specialcashitems = loadedSpecialItems;
|
||||
}
|
||||
}
|
||||
|
||||
private final int accountId;
|
||||
private final int characterId;
|
||||
private int nxCredit;
|
||||
private int maplePoint;
|
||||
private int nxPrepaid;
|
||||
private boolean opened;
|
||||
private ItemFactory factory;
|
||||
private final List<Item> inventory = new ArrayList<>();
|
||||
private final List<Integer> wishList = new ArrayList<>();
|
||||
private int notes = 0;
|
||||
private final Lock lock = new ReentrantLock();
|
||||
|
||||
public CashShop(int accountId, int characterId, int jobType) throws SQLException {
|
||||
this.accountId = accountId;
|
||||
this.characterId = characterId;
|
||||
|
||||
if (!YamlConfig.config.server.USE_JOINT_CASHSHOP_INVENTORY) {
|
||||
switch (jobType) {
|
||||
case 0:
|
||||
factory = ItemFactory.CASH_EXPLORER;
|
||||
break;
|
||||
case 1:
|
||||
factory = ItemFactory.CASH_CYGNUS;
|
||||
break;
|
||||
case 2:
|
||||
factory = ItemFactory.CASH_ARAN;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
factory = ItemFactory.CASH_OVERALL;
|
||||
}
|
||||
|
||||
try (Connection con = DatabaseConnection.getConnection()) {
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT `nxCredit`, `maplePoint`, `nxPrepaid` FROM `accounts` WHERE `id` = ?")) {
|
||||
ps.setInt(1, accountId);
|
||||
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
this.nxCredit = rs.getInt("nxCredit");
|
||||
this.maplePoint = rs.getInt("maplePoint");
|
||||
this.nxPrepaid = rs.getInt("nxPrepaid");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Pair<Item, InventoryType> item : factory.loadItems(accountId, false)) {
|
||||
inventory.add(item.getLeft());
|
||||
}
|
||||
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT `sn` FROM `wishlists` WHERE `charid` = ?")) {
|
||||
ps.setInt(1, characterId);
|
||||
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
wishList.add(rs.getInt("sn"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public record CashShopSurpriseResult(Item usedCashShopSurprise, Item reward) {
|
||||
}
|
||||
|
||||
public int getCash(int type) {
|
||||
switch (type) {
|
||||
case 1:
|
||||
return nxCredit;
|
||||
case 2:
|
||||
return maplePoint;
|
||||
case 4:
|
||||
return nxPrepaid;
|
||||
}
|
||||
return switch (type) {
|
||||
case NX_CREDIT -> nxCredit;
|
||||
case MAPLE_POINT -> maplePoint;
|
||||
case NX_PREPAID -> nxPrepaid;
|
||||
default -> 0;
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void gainCash(int type, int cash) {
|
||||
switch (type) {
|
||||
case 1:
|
||||
nxCredit += cash;
|
||||
break;
|
||||
case 2:
|
||||
maplePoint += cash;
|
||||
break;
|
||||
case 4:
|
||||
nxPrepaid += cash;
|
||||
break;
|
||||
case NX_CREDIT -> nxCredit += cash;
|
||||
case MAPLE_POINT -> maplePoint += cash;
|
||||
case NX_PREPAID -> nxPrepaid += cash;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,17 +396,6 @@ public class CashShop {
|
||||
}
|
||||
}
|
||||
|
||||
public int getItemsSize() {
|
||||
int size = 0;
|
||||
lock.lock();
|
||||
try {
|
||||
size = inventory.size();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public List<Integer> getWishList() {
|
||||
return wishList;
|
||||
}
|
||||
@@ -537,47 +514,57 @@ public class CashShop {
|
||||
}
|
||||
}
|
||||
|
||||
private Item getCashShopItemByItemid(int itemid) {
|
||||
public Optional<CashShopSurpriseResult> openCashShopSurprise(long cashId) {
|
||||
lock.lock();
|
||||
try {
|
||||
for (Item it : inventory) {
|
||||
if (it.getItemId() == itemid) {
|
||||
return it;
|
||||
}
|
||||
Optional<Item> maybeCashShopSurprise = getItemByCashId(cashId);
|
||||
if (maybeCashShopSurprise.isEmpty() ||
|
||||
maybeCashShopSurprise.get().getItemId() != ItemId.CASH_SHOP_SURPRISE) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Item cashShopSurprise = maybeCashShopSurprise.get();
|
||||
if (cashShopSurprise.getQuantity() <= 0) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (getItemsSize() >= 100) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Optional<CashItem> cashItemReward = CashItemFactory.getRandomCashItem();
|
||||
if (cashItemReward.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
short newQuantity = (short) (cashShopSurprise.getQuantity() - 1);
|
||||
cashShopSurprise.setQuantity(newQuantity);
|
||||
if (newQuantity <= 0) {
|
||||
removeFromInventory(cashShopSurprise);
|
||||
}
|
||||
|
||||
Item itemReward = cashItemReward.get().toItem();
|
||||
addToInventory(itemReward);
|
||||
|
||||
return Optional.of(new CashShopSurpriseResult(cashShopSurprise, itemReward));
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized Pair<Item, Item> openCashShopSurprise() {
|
||||
Item css = getCashShopItemByItemid(ItemId.CASH_SHOP_SURPRISE);
|
||||
@GuardedBy("lock")
|
||||
private Optional<Item> getItemByCashId(long cashId) {
|
||||
return inventory.stream()
|
||||
.filter(item -> item.getCashId() == cashId)
|
||||
.findAny();
|
||||
}
|
||||
|
||||
if (css != null) {
|
||||
if (getItemsSize() >= 100) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CashItem cItem = CashItemFactory.getRandomCashItem();
|
||||
|
||||
if (cItem != null) {
|
||||
if (css.getQuantity() > 1) {
|
||||
css.setQuantity((short) (css.getQuantity() - 1));
|
||||
} else {
|
||||
removeFromInventory(css);
|
||||
}
|
||||
|
||||
Item item = cItem.toItem();
|
||||
addToInventory(item);
|
||||
|
||||
return new Pair<>(item, css);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
public int getItemsSize() {
|
||||
lock.lock();
|
||||
try {
|
||||
return inventory.size();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ import net.server.world.Party;
|
||||
import net.server.world.PartyCharacter;
|
||||
import net.server.world.PartyOperation;
|
||||
import net.server.world.World;
|
||||
import server.CashShop;
|
||||
import server.CashShop.CashItem;
|
||||
import server.CashShop.CashItemFactory;
|
||||
import server.CashShop.SpecialCashItem;
|
||||
@@ -5580,8 +5581,8 @@ public class PacketCreator {
|
||||
|
||||
public static Packet showMTSCash(Character chr) {
|
||||
final OutPacket p = OutPacket.create(SendOpcode.MTS_OPERATION2);
|
||||
p.writeInt(chr.getCashShop().getCash(4));
|
||||
p.writeInt(chr.getCashShop().getCash(2));
|
||||
p.writeInt(chr.getCashShop().getCash(CashShop.NX_PREPAID));
|
||||
p.writeInt(chr.getCashShop().getCash(CashShop.MAPLE_POINT));
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -5689,9 +5690,9 @@ public class PacketCreator {
|
||||
|
||||
public static Packet showCash(Character mc) {
|
||||
final OutPacket p = OutPacket.create(SendOpcode.QUERY_CASH_RESULT);
|
||||
p.writeInt(mc.getCashShop().getCash(1));
|
||||
p.writeInt(mc.getCashShop().getCash(2));
|
||||
p.writeInt(mc.getCashShop().getCash(4));
|
||||
p.writeInt(mc.getCashShop().getCash(CashShop.NX_CREDIT));
|
||||
p.writeInt(mc.getCashShop().getCash(CashShop.MAPLE_POINT));
|
||||
p.writeInt(mc.getCashShop().getCash(CashShop.NX_PREPAID));
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -6479,14 +6480,15 @@ public class PacketCreator {
|
||||
return p;
|
||||
}
|
||||
|
||||
public static Packet onCashGachaponOpenSuccess(int accountid, long sn, int remainingBoxes, Item item, int itemid, int nSelectedItemCount, boolean bJackpot) {
|
||||
public static Packet onCashGachaponOpenSuccess(int accountid, long boxCashId, int remainingBoxes, Item reward,
|
||||
int rewardItemId, int rewardQuantity, boolean bJackpot) {
|
||||
OutPacket p = OutPacket.create(SendOpcode.CASHSHOP_CASH_ITEM_GACHAPON_RESULT);
|
||||
p.writeByte(0xE5); // subopcode thanks to Ubaware
|
||||
p.writeLong(sn);// sn of the box used
|
||||
p.writeLong(boxCashId);
|
||||
p.writeInt(remainingBoxes);
|
||||
addCashItemInformation(p, item, accountid);
|
||||
p.writeInt(itemid);// the itemid of the liSN?
|
||||
p.writeByte(nSelectedItemCount);// the total count now? o.O
|
||||
addCashItemInformation(p, reward, accountid);
|
||||
p.writeInt(rewardItemId);
|
||||
p.writeByte(rewardQuantity); // nSelectedItemCount
|
||||
p.writeBool(bJackpot);// "CashGachaponJackpot"
|
||||
return p;
|
||||
}
|
||||
|
||||
19
src/test/java/constants/id/ItemIdTest.java
Normal file
19
src/test/java/constants/id/ItemIdTest.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package constants.id;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class ItemIdTest {
|
||||
|
||||
@Test
|
||||
void isCashPackage() {
|
||||
assertTrue(ItemId.isCashPackage(9102237));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isNotCashPackage() {
|
||||
assertFalse(ItemId.isCashPackage(4000000));
|
||||
}
|
||||
}
|
||||
@@ -235,4 +235,12 @@ class ByteBufInPacketTest {
|
||||
|
||||
assertEquals(initial.length(), afterReadingOpcode.length());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void equalsShouldCompareBytes() {
|
||||
ByteBufInPacket packet1 = new ByteBufInPacket(Unpooled.wrappedBuffer(new byte[]{ 11, 22, 33, 44 }));
|
||||
ByteBufInPacket packet2 = new ByteBufInPacket(Unpooled.wrappedBuffer(new byte[]{ 11, 22, 33, 44 }));
|
||||
|
||||
assertEquals(packet1, packet2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,4 +203,14 @@ class ByteBufOutPacketTest {
|
||||
assertEquals(0, wrapped.readByte());
|
||||
assertEquals(secondWrittenByte, wrapped.readByte());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void equalsShouldCompareBytes() {
|
||||
ByteBufOutPacket packet1 = new ByteBufOutPacket();
|
||||
packet1.writeBytes(new byte[] { 55, 66, 77, 88 });
|
||||
ByteBufOutPacket packet2 = new ByteBufOutPacket();
|
||||
packet2.writeBytes(new byte[] { 55, 66, 77, 88 });
|
||||
|
||||
assertEquals(packet1, packet2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package net.server.channel.handlers;
|
||||
|
||||
import client.inventory.Item;
|
||||
import constants.id.ItemId;
|
||||
import net.packet.InPacket;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import server.CashShop;
|
||||
import testutil.HandlerTest;
|
||||
import testutil.Items;
|
||||
import testutil.Packets;
|
||||
import tools.PacketCreator;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class CashShopSurpriseHandlerTest extends HandlerTest {
|
||||
private final CashShopSurpriseHandler handler = new CashShopSurpriseHandler();
|
||||
|
||||
@Mock
|
||||
private CashShop cashShop;
|
||||
|
||||
@BeforeEach
|
||||
void prepareCashShop() {
|
||||
when(chr.getCashShop()).thenReturn(cashShop);
|
||||
}
|
||||
|
||||
private InPacket useCashShopSurprisePacket(long cashId) {
|
||||
return Packets.buildInPacket(out -> out.writeLong(cashId));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDoNothingWhenCsIsNotOpened() {
|
||||
when(cashShop.isOpened()).thenReturn(false);
|
||||
|
||||
handler.handlePacket(useCashShopSurprisePacket(123), client);
|
||||
|
||||
verify(cashShop, never()).openCashShopSurprise(anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSendFailurePacketWhenFailToOpen() {
|
||||
when(cashShop.isOpened()).thenReturn(true);
|
||||
when(cashShop.openCashShopSurprise(anyLong())).thenReturn(Optional.empty());
|
||||
|
||||
handler.handlePacket(useCashShopSurprisePacket(456), client);
|
||||
|
||||
verify(client).sendPacket(PacketCreator.onCashItemGachaponOpenFailed());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSendSuccessPacketWhenSuccessfullyOpen() {
|
||||
when(cashShop.isOpened()).thenReturn(true);
|
||||
Item cashShopSurprise = Items.itemWithQuantity(ItemId.CASH_SHOP_SURPRISE, 3);
|
||||
Item reward = Items.itemWithQuantity(5000012, 1);
|
||||
when(cashShop.openCashShopSurprise(789)).thenReturn(Optional.of(new CashShop.CashShopSurpriseResult(
|
||||
cashShopSurprise, reward)));
|
||||
|
||||
handler.handlePacket(useCashShopSurprisePacket(789), client);
|
||||
|
||||
verify(client).sendPacket(PacketCreator.onCashGachaponOpenSuccess(ACCOUNT_ID, cashShopSurprise.getCashId(), 3,
|
||||
reward, 5000012, 1, true));
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,10 @@ public class AnyValues {
|
||||
return "string";
|
||||
}
|
||||
|
||||
public static short anyShort() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
public static DaoException daoException() {
|
||||
return new DaoException(string(), new RuntimeException());
|
||||
}
|
||||
|
||||
24
src/test/java/testutil/HandlerTest.java
Normal file
24
src/test/java/testutil/HandlerTest.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package testutil;
|
||||
|
||||
import client.Character;
|
||||
import client.Client;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.mockito.Mock;
|
||||
|
||||
import static org.mockito.Mockito.lenient;
|
||||
|
||||
public abstract class HandlerTest {
|
||||
protected static final int ACCOUNT_ID = 1702;
|
||||
|
||||
@Mock
|
||||
protected Client client;
|
||||
|
||||
@Mock
|
||||
protected Character chr;
|
||||
|
||||
@BeforeEach
|
||||
void prepareClient() {
|
||||
lenient().when(client.getAccID()).thenReturn(ACCOUNT_ID);
|
||||
lenient().when(client.getPlayer()).thenReturn(chr);
|
||||
}
|
||||
}
|
||||
10
src/test/java/testutil/Items.java
Normal file
10
src/test/java/testutil/Items.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package testutil;
|
||||
|
||||
import client.inventory.Item;
|
||||
|
||||
public class Items {
|
||||
|
||||
public static Item itemWithQuantity(int itemId, int quantity) {
|
||||
return new Item(itemId, AnyValues.anyShort(), (short) quantity);
|
||||
}
|
||||
}
|
||||
18
src/test/java/testutil/Packets.java
Normal file
18
src/test/java/testutil/Packets.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package testutil;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.packet.ByteBufInPacket;
|
||||
import net.packet.ByteBufOutPacket;
|
||||
import net.packet.InPacket;
|
||||
import net.packet.OutPacket;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class Packets {
|
||||
|
||||
public static InPacket buildInPacket(Consumer<OutPacket> contentProvider) {
|
||||
OutPacket builderInput = new ByteBufOutPacket();
|
||||
contentProvider.accept(builderInput);
|
||||
return new ByteBufInPacket(Unpooled.wrappedBuffer(builderInput.getBytes()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user