card parser

This commit is contained in:
Michael Wain 2024-06-13 03:31:35 +03:00
parent 07d7480ff0
commit 362655c389
30 changed files with 148 additions and 168 deletions

View File

@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component;
import com.alterdekim.hearthhack.config.DBFConfig;
import com.alterdekim.hearthhack.config.ServerConfig;
import com.alterdekim.hearthhack.parser.CardsXmlParser;
import com.alterdekim.hearthhack.parser.DBFParser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -35,6 +36,7 @@ public class StartupListener {
)
)
);
log.info("CardsXmlMap: {}", CardsXmlParser.parse(serverConfig.getCardsXmlPath()));
} catch (Exception e) {
log.error(e.getMessage());
}

View File

@ -0,0 +1,19 @@
package com.alterdekim.hearthhack.component.processor.client.request;
import com.alterdekim.Protocol;
import com.alterdekim.hearthhack.component.TcpConnection;
import com.alterdekim.hearthhack.util.BattleNetPacket;
import com.alterdekim.hearthhack.util.ClientRequestBody;
public class BuySellCard extends ClientRequestParser {
@Override
public void parse(BattleNetPacket packet, ClientRequestBody body, TcpConnection conn) throws Exception {
Protocol.BuySellCard request = Protocol.BuySellCard.parseFrom(body.getBody());
}
@Override
public int getId() {
return 257;
}
}

View File

@ -6,13 +6,50 @@ import com.alterdekim.hearthhack.util.BattleNetPacket;
import com.alterdekim.hearthhack.util.ClientRequestBody;
import lombok.extern.slf4j.Slf4j;
import java.util.stream.IntStream;
import static com.alterdekim.Protocol.ProductType.PRODUCT_TYPE_BOOSTER;
import static com.alterdekim.hearthhack.util.GameUtilities.generateNotification;
@Slf4j
public class PurchaseWithGold extends ClientRequestParser {
private final int PACK_COST = 100;
@Override
public void parse(BattleNetPacket packet, ClientRequestBody body, TcpConnection conn) throws Exception {
// PurchaseWithGoldResponse 280
Protocol.PurchaseWithGold request = Protocol.PurchaseWithGold.parseFrom(body.getBody());
log.info("PurchaseWithGold: {}", request);
Protocol.PurchaseWithGoldResponse response;
if( request.getProduct() != PRODUCT_TYPE_BOOSTER ) {
response = Protocol.PurchaseWithGoldResponse.newBuilder()
.setResult(Protocol.PurchaseWithGoldResponse.PurchaseResult.PR_FEATURE_NA)
.build();
} else if( conn.getUserService().getGoldForUserId(conn.getUserId()) < (PACK_COST * request.getQuantity()) ) {
response = Protocol.PurchaseWithGoldResponse.newBuilder()
.setResult(Protocol.PurchaseWithGoldResponse.PurchaseResult.PR_INSUFFICIENT_FUNDS)
.build();
} else {
IntStream.range(0, request.getQuantity())
.forEach(i -> conn.getUserService().addBooster(conn.getUserId(), request.getData()));
conn.getUserService().setGoldForUserId(conn.getUserId(), conn.getUserService().getGoldForUserId(conn.getUserId()) - (PACK_COST * request.getQuantity()));
response = Protocol.PurchaseWithGoldResponse.newBuilder()
.setResult(Protocol.PurchaseWithGoldResponse.PurchaseResult.PR_SUCCESS)
.build();
}
Protocol.Notification n = generateNotification(280, response.toByteString(), response.getSerializedSize());
Protocol.Header header = Protocol.Header.newBuilder()
.setServiceId(4)
.setMethodId(1)
.setToken(conn.nextToken())
.setObjectId(0)
.setSize(n.getSerializedSize())
.setStatus(0)
.build();
conn.send(new BattleNetPacket(header, n.toByteArray()));
}
@Override

View File

@ -13,9 +13,6 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.ACCOUNT_LICEN
public class AccountLicensesInfo extends GenericParser {
@Override
public void setResources(IService service, DBFConfig config) {}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
// Protocol.AccountLicensesInfoResponse

View File

@ -20,8 +20,6 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.FEATURES;
@Slf4j
public class AvailableFeatures extends GenericParser {
private DBFConfig config;
private Executor executor;
private void executeFeatures(TcpConnection conn) throws Exception {
@ -79,11 +77,6 @@ public class AvailableFeatures extends GenericParser {
conn.send(new BattleNetPacket(header, n.toByteArray()));
}
@Override
public void setResources(IService service, DBFConfig config) {
this.config = config;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
if( this.executor != null ) this.executor.setRunning(false);

View File

@ -15,18 +15,9 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.BOOSTERS;
public class Boosters extends GenericParser {
private DBFConfig config;
private UserService userService;
@Override
public void setResources(IService service, DBFConfig config) {
this.config = config;
this.userService = (UserService) service;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
List<Protocol.BoosterInfo> binfo = userService.getBoostersByUserId(conn.getUserId()).stream().map(b -> Protocol.BoosterInfo.newBuilder()
List<Protocol.BoosterInfo> binfo = conn.getUserService().getBoostersByUserId(conn.getUserId()).stream().map(b -> Protocol.BoosterInfo.newBuilder()
.setCount(b.getCount())
.setType(b.getType())
.build()

View File

@ -17,20 +17,11 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.CARD_BACKS;
public class CardBacks extends GenericParser {
private DBFConfig config;
private UserService userService;
@Override
public void setResources(IService service, DBFConfig config) {
this.config = config;
this.userService = (UserService) service;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
Protocol.CardBacks cardBacks = Protocol.CardBacks.newBuilder()
.setDefaultCardBack(userService.getDefaultCardBackForUserId(conn.getUserId()))
.addAllCardBacks(userService.getCardBacksForUserId(conn.getUserId()).stream()
.setDefaultCardBack(conn.getUserService().getDefaultCardBackForUserId(conn.getUserId()))
.addAllCardBacks(conn.getUserService().getCardBacksForUserId(conn.getUserId()).stream()
.map(CardBack::getBackId).collect(Collectors.toList()))
.build();

View File

@ -22,16 +22,9 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.CARD_VALUES;
@Slf4j
public class CardValues extends GenericParser {
private DBFConfig config;
@Override
public void setResources(IService service, DBFConfig config) {
this.config = config;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
CardsDBF cards = config.getCards();
CardsDBF cards = conn.getDbfConfig().getCards();
Protocol.CardValues.Builder cardVals = Protocol.CardValues.newBuilder();
cards.getRecords().forEach(c -> {

View File

@ -13,13 +13,6 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.CLIENT_OPTION
public class ClientOptions extends GenericParser {
private DBFConfig config;
@Override
public void setResources(IService service, DBFConfig config) {
this.config = config;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
Protocol.ClientOptions clientOptions = Protocol.ClientOptions.newBuilder()

View File

@ -14,15 +14,6 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.COLLECTION;
public class Collection extends GenericParser {
private DBFConfig config;
private UserService userService;
@Override
public void setResources(IService service, DBFConfig config) {
this.config = config;
this.userService = (UserService) service;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
// my collection

View File

@ -14,15 +14,6 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.DECK_LIST;
public class DeckList extends GenericParser {
private DBFConfig config;
private UserService userService;
@Override
public void setResources(IService service, DBFConfig config) {
this.userService = (UserService) service;
this.config = config;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
Protocol.DeckList deckList = Protocol.DeckList.newBuilder()

View File

@ -14,19 +14,10 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.ARCANE_DUST_B
public class DustBalance extends GenericParser {
private DBFConfig config;
private UserService userService;
@Override
public void setResources(IService service, DBFConfig config) {
this.userService = (UserService) service;
this.config = config;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
Protocol.ArcaneDustBalance dustBalance = Protocol.ArcaneDustBalance.newBuilder()
.setBalance(userService.getDustForUserId(conn.getUserId()))
.setBalance(conn.getUserService().getDustForUserId(conn.getUserId()))
.build();
Protocol.Notification n = generateNotification(262, dustBalance.toByteString(), dustBalance.getSerializedSize());

View File

@ -14,15 +14,6 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.FAVORITE_HERO
public class FavoriteHeroes extends GenericParser {
private UserService userService;
private DBFConfig config;
@Override
public void setResources(IService service, DBFConfig config) {
this.config = config;
this.userService = (UserService) service;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
Protocol.FavoriteHeroesResponse favoriteHeroesResponse = Protocol.FavoriteHeroesResponse.newBuilder()

View File

@ -20,7 +20,6 @@ public class GeneralGenericParser extends ReflectionLoader<GenericParser> {
}
try {
GenericParser parser = this.getParsers().get(req.getValue());
parser.setResources(conn.getUserService(), conn.getDbfConfig());
parser.parseGenericRequest(token, conn);
} catch (Exception e) {
log.error(e.getMessage());

View File

@ -17,8 +17,6 @@ import static com.alterdekim.hearthhack.util.GameUtilities.generateNotification;
@NoArgsConstructor
public abstract class GenericParser implements AbstractParser {
public abstract void setResources(IService service, DBFConfig config);
public abstract void parseGenericRequest(int token, TcpConnection conn) throws Exception;
@Override

View File

@ -14,21 +14,12 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.GOLD_BALANCE;
public class GoldBalance extends GenericParser {
private DBFConfig config;
private UserService userService;
@Override
public void setResources(IService service, DBFConfig config) {
this.config = config;
this.userService = (UserService) service;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
Protocol.GoldBalance gb = Protocol.GoldBalance.newBuilder()
.setCap(999999)
.setBonusBalance(0)
.setCappedBalance(userService.getGoldForUserId(conn.getUserId()))
.setCappedBalance(conn.getUserService().getGoldForUserId(conn.getUserId()))
.setCapWarning(2000)
.build();

View File

@ -14,15 +14,6 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.HERO_XP;
public class HeroXP extends GenericParser {
private DBFConfig config;
private UserService userService;
@Override
public void setResources(IService service, DBFConfig config) {
this.config = config;
this.userService = (UserService) service;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {

View File

@ -14,15 +14,6 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.MEDAL_INFO;
public class MedalInfo extends GenericParser {
private DBFConfig config;
private UserService userService;
@Override
public void setResources(IService service, DBFConfig config) {
this.userService = (UserService) service;
this.config = config;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
Protocol.MedalInfo medalInfo = Protocol.MedalInfo.newBuilder()

View File

@ -14,15 +14,6 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.NOT_SO_MASSIV
public class NotSoMassiveLoginReply extends GenericParser {
private DBFConfig config;
private UserService userService;
@Override
public void setResources(IService service, DBFConfig config) {
this.userService = (UserService) service;
this.config = config;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
Protocol.NotSoMassiveLoginReply reply = Protocol.NotSoMassiveLoginReply.newBuilder()

View File

@ -16,15 +16,6 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.PVP_QUEUE;
@Slf4j
public class PlayQueue extends GenericParser {
private DBFConfig config;
private UserService userService;
@Override
public void setResources(IService service, DBFConfig config) {
this.config = config;
this.userService = (UserService) service;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
Protocol.PlayQueue playQueue = Protocol.PlayQueue.newBuilder()

View File

@ -14,15 +14,6 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.PLAYER_RECORD
public class PlayerRecords extends GenericParser {
private DBFConfig config;
private UserService userService;
@Override
public void setResources(IService service, DBFConfig config) {
this.config = config;
this.userService = (UserService) service;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
Protocol.PlayerRecords playerRecords = Protocol.PlayerRecords.newBuilder()

View File

@ -22,8 +22,6 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.NOTICES;
public class ProfileNotices extends GenericParser {
private Executor executor;
private UserService userService;
private DBFConfig config;
private void sendNotices(TcpConnection conn) throws Exception {
Protocol.ProfileNotices notices = Protocol.ProfileNotices.newBuilder()
@ -43,12 +41,6 @@ public class ProfileNotices extends GenericParser {
conn.send(new BattleNetPacket(header, n.toByteArray()));
}
@Override
public void setResources(IService service, DBFConfig config) {
this.config = config;
this.userService = (UserService) service;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
if( this.executor != null ) this.executor.setRunning(false);

View File

@ -14,15 +14,6 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.CAMPAIGN_INFO
public class ProfileProgress extends GenericParser {
private UserService userService;
private DBFConfig config;
@Override
public void setResources(IService service, DBFConfig config) {
this.userService = (UserService) service;
this.config = config;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
Protocol.ProfileProgress profileProgress = Protocol.ProfileProgress.newBuilder()

View File

@ -14,15 +14,6 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.REWARD_PROGRE
public class RewardProgress extends GenericParser {
private UserService userService;
private DBFConfig config;
@Override
public void setResources(IService service, DBFConfig config) {
this.userService = (UserService) service;
this.config = config;
}
@Override
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
Protocol.RewardProgress rewardProgress = Protocol.RewardProgress.newBuilder()

View File

@ -12,4 +12,5 @@ public class ServerConfig {
@Value("${hearthhack.bnet_port}") private Integer bnetPort;
@Value("${hearthhack.game_port}") private Integer gamePort;
@Value("${hearthhack.host}") private String host;
@Value("${hearthhack.cards_xml_path}") private String cardsXmlPath;
}

View File

@ -40,4 +40,9 @@ public class Booster {
@Column(nullable = false)
private Long userId;
public Booster(Long userId, Integer type) {
this.type = type;
this.userId = userId;
}
}

View File

@ -0,0 +1,47 @@
package com.alterdekim.hearthhack.parser;
import com.alterdekim.hearthhack.util.Util;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class CardsXmlParser {
private static final byte[] cardDef = Util.hexStringToByteArray("3C43617264446566733E");
private static final byte[] cardDefEnd = Util.hexStringToByteArray("3C2F43617264446566733E");
public static Map<String, String> parse(String path) throws IOException {
Map<String, String> m = new HashMap<>();
byte[] b = Files.readAllBytes(Path.of(path));
byte[] a;
for( int i = 0; i < b.length; i++ ) {
if( isEq(b, i, cardDef) ) { // -8
a = Arrays.copyOfRange(b, i-8, i-4);
int f = findFirst(b, i);
m.put(new String(a), new String(Arrays.copyOfRange(b, i, f)));
i += f;
}
}
return m;
}
private static int findFirst(byte[] b, int s) {
for( int i = s; i < b.length; i++ ) {
if( !isEq(b, i, cardDefEnd) ) continue;
return i+cardDefEnd.length;
}
return 0;
}
private static boolean isEq(byte[] src, int start, byte[] m) {
for( int i = 0; i < m.length; i++ ) {
if( m[i] != src[start + i] ) return false;
}
return true;
}
}

View File

@ -16,4 +16,10 @@ public interface UserRepository extends JpaRepository<User, Long> {
@Modifying
@Query(value = "UPDATE User u SET u.defaultCardBack = :cardBackId WHERE u.id = :userId")
void updateCardBackOfUser(@Param("userId") Long userId, @Param("cardBackId") Long cardBackId);
@Transactional
@Modifying
@Query(value = "UPDATE User u SET u.goldBalance = :goldCount WHERE u.id = :userId")
void updateGoldOfUser(@Param("userId") Long userId, @Param("goldCount") Integer goldCount);
}

View File

@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.service;
import com.alterdekim.hearthhack.dto.BoosterDTO;
import com.alterdekim.hearthhack.dto.UserDTO;
import com.alterdekim.hearthhack.entity.Booster;
import com.alterdekim.hearthhack.entity.CardBack;
import com.alterdekim.hearthhack.entity.Role;
import com.alterdekim.hearthhack.entity.User;
@ -63,11 +64,19 @@ public class UserService implements IService {
return cardBackRepository.isUserHasCardBack(userId, cardBack);
}
public void addBooster(Long userId, Integer boosterType) {
boosterRepository.save(new Booster(userId, boosterType));
}
public Integer getGoldForUserId(Long userId) {
return userRepository.findById(userId).get().getGoldBalance();
}
public void setGoldForUserId(Long userId, Integer gold) {
userRepository.updateGoldOfUser(userId, gold);
}
public Integer getDustForUserId(Long userId) {
return userRepository.findById(userId).get().getDustBalance();
}

View File

@ -3342,4 +3342,19 @@ message PurchaseWithGoldResponse {
required PurchaseResult result = 1;
optional int64 gold_used = 2;
}
// ref: PegasusUtil.BuySellCard
message BuySellCard {
// ref: PegasusUtil.BuySellCard/PacketID
enum PacketID {
system = 0;
ID = 257;
}
required CardDef def = 1;
optional int32 count = 2;
required bool buying = 3;
optional int32 unit_sell_price = 4;
optional int32 unit_buy_price = 5;
}