├── .gitignore ├── .idea ├── codeStyleSettings.xml ├── compiler.xml ├── dbnavigator.xml ├── description.html ├── inspectionProfiles │ └── Project_Default.xml ├── kotlinc.xml ├── misc.xml ├── modules.xml ├── project-template.xml └── vcs.xml ├── LICENSE ├── README.md ├── pom.xml ├── private-server.iml └── src └── main ├── java └── royaleserver │ ├── Main.java │ ├── Server.java │ ├── ServerException.java │ ├── assets │ ├── ApkAssetManager.java │ ├── Asset.java │ ├── AssetManager.java │ ├── AssetManagerWrapper.java │ ├── FolderAssetManager.java │ └── ZipAssetManager.java │ ├── config │ └── Config.java │ ├── crypto │ ├── ClientCrypto.java │ ├── Crypto.java │ ├── Nonce.java │ ├── ServerCrypto.java │ └── TweetNaCl.java │ ├── csv │ ├── Column.java │ ├── Row.java │ ├── Table.java │ └── Value.java │ ├── database │ ├── DataManager.java │ ├── DataServices.java │ ├── entity │ │ ├── ArenaEntity.java │ │ ├── AssetEntity.java │ │ ├── CardEntity.java │ │ ├── ChestEntity.java │ │ ├── ClanBadgeEntity.java │ │ ├── ClanEntity.java │ │ ├── ClanRoleEntity.java │ │ ├── ClanType.java │ │ ├── ExpLevelEntity.java │ │ ├── HomeChestEntity.java │ │ ├── HomeChestStatus.java │ │ ├── LogicEntity.java │ │ ├── PlayerCardEntity.java │ │ ├── PlayerDeckCardEntity.java │ │ ├── PlayerEntity.java │ │ └── UnlockCodeEntity.java │ ├── service │ │ ├── ArenaService.java │ │ ├── AssetService.java │ │ ├── CardService.java │ │ ├── ChestService.java │ │ ├── ClanBadgeService.java │ │ ├── ClanRoleService.java │ │ ├── ClanService.java │ │ ├── ExpLevelService.java │ │ ├── HomeChestService.java │ │ ├── LogicService.java │ │ ├── PlayerCardService.java │ │ ├── PlayerDeckCardService.java │ │ ├── PlayerService.java │ │ ├── RestfulService.java │ │ ├── Service.java │ │ └── UnlockCodeService.java │ └── util │ │ ├── AssignedIdentityGenerator.java │ │ ├── CloseableTransaction.java │ │ ├── Identifiable.java │ │ └── Transaction.java │ ├── game │ ├── ChestGenerator.java │ ├── Clan.java │ ├── CodeEnterPlayer.java │ ├── Deck.java │ ├── OpeningChest.java │ ├── Player.java │ └── PlayerCard.java │ ├── logic │ ├── Arena.java │ ├── Card.java │ ├── Chest.java │ ├── ClanBadge.java │ ├── ClanRole.java │ ├── DBLogic.java │ ├── ExpLevel.java │ ├── GameMode.java │ ├── Logic.java │ ├── NamedLogic.java │ └── Rarity.java │ ├── network │ ├── Filler.java │ ├── NetworkServer.java │ ├── NetworkSession.java │ ├── NetworkSessionHandler.java │ ├── PacketDecoder.java │ ├── PacketEncoder.java │ ├── PlayerHandler.java │ ├── PlayerInitializer.java │ ├── UnhandledMessageException.java │ └── protocol │ │ ├── Command.java │ │ ├── Commands.java │ │ ├── Factory.java │ │ ├── FactoryTarget.java │ │ ├── Handler.java │ │ ├── Message.java │ │ ├── MessageHeader.java │ │ ├── Messages.java │ │ ├── client │ │ ├── ClientCommand.java │ │ ├── ClientCommandFactory.java │ │ ├── ClientCommandHandler.java │ │ ├── ClientMessage.java │ │ ├── ClientMessageFactory.java │ │ ├── ClientMessageHandler.java │ │ ├── commands │ │ │ ├── CardUpgrade.java │ │ │ ├── ChallengeBuy.java │ │ │ ├── ChestBuy.java │ │ │ ├── ChestCardNext.java │ │ │ ├── ChestDraftCardSelect.java │ │ │ ├── ChestOpen.java │ │ │ ├── ChestSeasonRewardOpen.java │ │ │ ├── DeckChange.java │ │ │ ├── DeckChangeCard.java │ │ │ └── FightStart.java │ │ └── messages │ │ │ ├── AccountUnlock.java │ │ │ ├── ClanAskData.java │ │ │ ├── ClanAskJoinable.java │ │ │ ├── ClanChatMessage.java │ │ │ ├── ClanCreate.java │ │ │ ├── ClanJoin.java │ │ │ ├── ClanLeave.java │ │ │ ├── ClanSearch.java │ │ │ ├── ClientCommands.java │ │ │ ├── ClientHello.java │ │ │ ├── ConnectionInfo.java │ │ │ ├── HomeAskData.java │ │ │ ├── HomeAskDataOwn.java │ │ │ ├── InboxAsk.java │ │ │ ├── Login.java │ │ │ ├── MatchmakeCancel.java │ │ │ ├── MatchmakeStart.java │ │ │ ├── NameChange.java │ │ │ ├── NameCheck.java │ │ │ ├── Ping.java │ │ │ └── TournamentAskJoinable.java │ │ └── server │ │ ├── ServerCommand.java │ │ ├── ServerCommandFactory.java │ │ ├── ServerMessage.java │ │ ├── ServerMessageFactory.java │ │ ├── commands │ │ ├── ChestOpenOk.java │ │ ├── ClanCreateOk.java │ │ ├── ClanLeaveOk.java │ │ └── NameSet.java │ │ ├── components │ │ ├── Card.java │ │ ├── ChestItem.java │ │ ├── ClanHeader.java │ │ ├── ClanMember.java │ │ ├── Deck.java │ │ ├── GameCard.java │ │ ├── GameDeck.java │ │ ├── HomeChest.java │ │ ├── HomeResources.java │ │ └── PlayerClan.java │ │ └── messages │ │ ├── AccountUnlockFailed.java │ │ ├── AccountUnlockOk.java │ │ ├── ClanData.java │ │ ├── ClanEvent.java │ │ ├── ClanJoinableResponse.java │ │ ├── ClanMemberAdd.java │ │ ├── ClanMemberRemove.java │ │ ├── ClanOnlineUpdate.java │ │ ├── CommandResponse.java │ │ ├── Disconnected.java │ │ ├── HomeData.java │ │ ├── HomeDataOwn.java │ │ ├── HomeDataVisited.java │ │ ├── LoginFailed.java │ │ ├── LoginOk.java │ │ ├── MatchmakeCancelOk.java │ │ ├── MatchmakeInfo.java │ │ ├── NameCheckOk.java │ │ ├── Pong.java │ │ ├── SectorState.java │ │ └── ServerHello.java │ └── utils │ ├── Bitset.java │ ├── CSVConverter.java │ ├── ChildLogger.java │ ├── DataStream.java │ ├── Dumper.java │ ├── GsonUtils.java │ ├── Hex.java │ ├── IO.java │ ├── LogLevel.java │ ├── LogManager.java │ ├── Logger.java │ ├── MainLogger.java │ ├── Pair.java │ ├── SCID.java │ ├── StringUtils.java │ └── Tag.java └── resources ├── config.json └── hibernate.cfg.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific stuff: 2 | .idea/**/workspace.xml 3 | .idea/**/tasks.xml 4 | .idea/dictionaries 5 | 6 | # Sensitive or high-churn files: 7 | .idea/**/dataSources/ 8 | .idea/**/dataSources.ids 9 | .idea/**/dataSources.xml 10 | .idea/**/dataSources.local.xml 11 | .idea/**/sqlDataSources.xml 12 | .idea/**/dynamic.xml 13 | .idea/**/uiDesigner.xml 14 | 15 | # Gradle: 16 | .idea/**/gradle.xml 17 | .idea/**/libraries 18 | 19 | 20 | /temp 21 | /server.log 22 | /workdir/server.log 23 | /target 24 | /out 25 | 26 | /config.json 27 | /clashroyale.db 28 | 29 | /user 30 | -------------------------------------------------------------------------------- /.idea/codeStyleSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 75 | 77 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/description.html: -------------------------------------------------------------------------------- 1 | Simple Java application that includes a class with main() method -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/project-template.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Clash Royale Private Server 2 | ## Warning. The server has been abandoned. Please do not ask anything about it. We won't answer. 3 | We do not see perspective of development, because we can't do battles. There are needed checksum, that is very hard to get it. 4 | The way to do it is to load `libg.so` and write wrapper for it, it's also very hard. 5 | Thanks for patience. 6 | 7 | Authors: 8 | - https://vk.com/tarik02_coder 9 | - https://vk.com/xset_official 10 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | royaleleaks 8 | private-server 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | 14 | org.apache.maven.plugins 15 | maven-compiler-plugin 16 | 3.1 17 | 18 | 19 | compile 20 | compile 21 | 22 | compile 23 | 24 | 25 | 26 | testCompile 27 | test-compile 28 | 29 | testCompile 30 | 31 | 32 | 33 | 34 | 1.8 35 | 1.8 36 | 37 | 38 | 39 | 40 | 41 | 42 | 5.2.10.Final 43 | 4.1.6.Final 44 | 45 | 46 | 47 | 48 | com.google.code.gson 49 | gson 50 | 2.8.0 51 | 52 | 53 | com.google.guava 54 | guava 55 | 20.0 56 | 57 | 58 | org.javassist 59 | javassist 60 | 3.21.0-GA 61 | 62 | 63 | com.caligollc 64 | nacl 65 | 1.0.2 66 | 67 | 68 | ove 69 | ove.blake2b 70 | alpha.0 71 | 72 | 73 | org.reflections 74 | reflections 75 | 0.9.11 76 | 77 | 78 | org.tukaani 79 | xz 80 | 1.6 81 | 82 | 83 | org.hibernate 84 | hibernate-core 85 | ${hibernate.version} 86 | 87 | 88 | org.hibernate 89 | hibernate-c3p0 90 | ${hibernate.version} 91 | 92 | 93 | mysql 94 | mysql-connector-java 95 | 5.1.6 96 | 97 | 98 | io.netty 99 | netty-all 100 | ${netty.version} 101 | 102 | 103 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/Main.java: -------------------------------------------------------------------------------- 1 | package royaleserver; 2 | 3 | import royaleserver.utils.LogManager; 4 | import royaleserver.utils.Logger; 5 | 6 | public class Main { 7 | private static Logger logger = LogManager.getLogger(Main.class); 8 | 9 | public static void main(String[] args) throws Throwable { 10 | try { 11 | Server server = new Server(); 12 | try { 13 | if (server.start()) { 14 | System.gc(); 15 | server.loop(); 16 | } 17 | } finally { 18 | server.stop(); 19 | } 20 | } catch (Throwable e) { 21 | logger.fatal(e.getMessage(), e); 22 | } 23 | 24 | LogManager.shutdown(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/ServerException.java: -------------------------------------------------------------------------------- 1 | package royaleserver; 2 | 3 | public class ServerException extends Exception { 4 | public ServerException(String message) { 5 | super(message); 6 | } 7 | 8 | public ServerException(String message, Throwable e) { 9 | super(message, e); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/assets/ApkAssetManager.java: -------------------------------------------------------------------------------- 1 | package royaleserver.assets; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.zip.ZipFile; 6 | 7 | public class ApkAssetManager extends ZipAssetManager { 8 | public ApkAssetManager(File file) throws IOException { 9 | super(new ZipFile(file), "assets/"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/assets/Asset.java: -------------------------------------------------------------------------------- 1 | package royaleserver.assets; 2 | 3 | import royaleserver.csv.Table; 4 | import royaleserver.database.entity.AssetEntity; 5 | import royaleserver.utils.IO; 6 | import royaleserver.utils.StringUtils; 7 | 8 | import java.io.InputStream; 9 | import java.util.Date; 10 | 11 | public abstract class Asset { 12 | public abstract InputStream open(); 13 | public abstract String name(); 14 | public abstract long lastUpdated(); 15 | 16 | public final byte[] bytes() { 17 | return IO.getByteArray(open()); 18 | } 19 | 20 | public final String content() { 21 | return StringUtils.from(open()); 22 | } 23 | 24 | public final Table csv() { 25 | return new Table(bytes()); 26 | } 27 | 28 | public final boolean isNewerThan(long time) { 29 | return lastUpdated() < time; 30 | } 31 | 32 | public final boolean isNewerThan(Date date) { 33 | return isNewerThan(date.getTime()); 34 | } 35 | 36 | public final boolean isNewerThan(AssetEntity assetEntity) { 37 | return isNewerThan(assetEntity.getLastUpdated()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/assets/AssetManager.java: -------------------------------------------------------------------------------- 1 | package royaleserver.assets; 2 | 3 | public abstract class AssetManager { 4 | public abstract Asset open(String path); 5 | public abstract void close(); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/assets/AssetManagerWrapper.java: -------------------------------------------------------------------------------- 1 | package royaleserver.assets; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class AssetManagerWrapper extends AssetManager { 7 | private final List assetManagers = new ArrayList<>(); 8 | 9 | /** 10 | * The first added manager has the highest priority. 11 | * @param assetManager AssetManager instance to use 12 | */ 13 | public void add(AssetManager assetManager) { 14 | assetManagers.add(assetManager); 15 | } 16 | 17 | public AssetManager simplify() { 18 | if (assetManagers.size() == 1) { 19 | return assetManagers.get(0); 20 | } 21 | 22 | return this; 23 | } 24 | 25 | @Override 26 | public Asset open(String path) { 27 | for (AssetManager assetManager : assetManagers) { 28 | Asset asset = assetManager.open(path); 29 | if (asset != null) { 30 | return asset; 31 | } 32 | } 33 | 34 | return null; 35 | } 36 | 37 | @Override 38 | public void close() { 39 | for (AssetManager assetManager : assetManagers) { 40 | assetManager.close(); 41 | } 42 | 43 | assetManagers.clear(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/assets/FolderAssetManager.java: -------------------------------------------------------------------------------- 1 | package royaleserver.assets; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.InputStream; 7 | 8 | public class FolderAssetManager extends AssetManager { 9 | private final File root; 10 | 11 | public FolderAssetManager(File root) { 12 | this.root = root; 13 | } 14 | 15 | @Override 16 | public Asset open(String path) { 17 | File file = new File(root, path); 18 | if (file.exists()) { 19 | return new FileAsset(file.getAbsolutePath().substring(root.getAbsolutePath().length() + File.pathSeparator.length()), file); 20 | } 21 | 22 | return null; 23 | } 24 | 25 | @Override 26 | public void close() { 27 | } 28 | 29 | private static class FileAsset extends Asset { 30 | private final String name; 31 | private final File file; 32 | 33 | public FileAsset(String name, File file) { 34 | this.name = name; 35 | this.file = file; 36 | } 37 | 38 | @Override 39 | public InputStream open() { 40 | try { 41 | return new FileInputStream(file); 42 | } catch (FileNotFoundException ignored) {} 43 | 44 | return null; 45 | } 46 | 47 | @Override 48 | public String name() { 49 | return this.name; 50 | } 51 | 52 | @Override 53 | public long lastUpdated() { 54 | return file.lastModified(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/assets/ZipAssetManager.java: -------------------------------------------------------------------------------- 1 | package royaleserver.assets; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.util.zip.ZipEntry; 6 | import java.util.zip.ZipFile; 7 | 8 | public class ZipAssetManager extends AssetManager { 9 | private final ZipFile file; 10 | private final String root; 11 | 12 | public ZipAssetManager(ZipFile file) { 13 | this(file, ""); 14 | } 15 | 16 | public ZipAssetManager(ZipFile file, String root) { 17 | if (file == null) { 18 | throw new IllegalArgumentException("file"); 19 | } 20 | 21 | if (root == null) { 22 | throw new IllegalArgumentException("root"); 23 | } 24 | 25 | if (root.length() != 0 && !root.endsWith("/")) { 26 | root = root + "/"; 27 | } 28 | 29 | this.file = file; 30 | this.root = root; 31 | } 32 | 33 | @Override 34 | public Asset open(String path) { 35 | ZipEntry entry = file.getEntry(root + path); 36 | if (entry == null) { 37 | return null; 38 | } 39 | 40 | return new ZipEntryAsset(path, file, entry); 41 | } 42 | 43 | @Override 44 | public void close() { 45 | try { 46 | file.close(); 47 | } catch (IOException e) { 48 | e.printStackTrace(); 49 | } 50 | } 51 | 52 | private static class ZipEntryAsset extends Asset { 53 | private final String name; 54 | private final ZipFile file; 55 | private final ZipEntry entry; 56 | 57 | public ZipEntryAsset(String name, ZipFile file, ZipEntry entry) { 58 | this.name = name; 59 | this.file = file; 60 | this.entry = entry; 61 | } 62 | 63 | @Override 64 | public InputStream open() { 65 | try { 66 | return file.getInputStream(entry); 67 | } catch (IOException e) { 68 | e.printStackTrace(); 69 | } 70 | 71 | return null; 72 | } 73 | 74 | @Override 75 | public String name() { 76 | return name; 77 | } 78 | 79 | @Override 80 | public long lastUpdated() { 81 | return entry.getLastModifiedTime().toMillis(); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/config/Config.java: -------------------------------------------------------------------------------- 1 | package royaleserver.config; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonElement; 5 | import com.google.gson.JsonObject; 6 | import com.google.gson.JsonParser; 7 | import com.google.gson.stream.JsonWriter; 8 | import royaleserver.ServerException; 9 | import royaleserver.utils.GsonUtils; 10 | import royaleserver.utils.IO; 11 | import royaleserver.utils.LogManager; 12 | import royaleserver.utils.Logger; 13 | 14 | import java.io.*; 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | import java.util.function.Function; 18 | 19 | public final class Config { 20 | private static final Logger logger = LogManager.getLogger(Config.class); 21 | 22 | private Map map = new HashMap<>(); 23 | 24 | public Config(JsonObject json) { 25 | fill("", json); 26 | } 27 | 28 | public JsonElement get(String key) { 29 | return get(key, null); 30 | } 31 | 32 | public JsonElement get(String key, JsonElement def) { 33 | return map.getOrDefault(key, def); 34 | } 35 | 36 | public static Config load(int configVersion, File configFile, Function defaultConfigFactory) throws ServerException { 37 | try { 38 | int version = 0; 39 | 40 | JsonObject configObject = null; 41 | if (configFile.exists()) { 42 | try { 43 | configObject = new JsonParser().parse(new InputStreamReader(new FileInputStream(configFile))).getAsJsonObject(); 44 | JsonElement jversion = configObject.get("_version"); 45 | if (jversion != null && !jversion.isJsonNull()) { 46 | version = jversion.getAsInt(); 47 | } 48 | } catch (Exception ignored) {} 49 | } 50 | 51 | if (version == 0 || version < configVersion) { 52 | InputStream configInputStream = defaultConfigFactory.apply(null); 53 | if (configInputStream == null) { 54 | throw new ServerException("Failed to get default config resource."); 55 | } 56 | 57 | if (version == 0) { 58 | logger.warn("Resetting your config..."); 59 | 60 | final byte[] bytes = IO.getByteArray(configInputStream, true); 61 | if (bytes == null) { 62 | throw new ServerException("Failed to get default config."); 63 | } 64 | 65 | configObject = new JsonParser().parse(new InputStreamReader(new ByteArrayInputStream(bytes))).getAsJsonObject(); 66 | try (OutputStream os = new FileOutputStream(configFile)) { 67 | os.write(bytes); 68 | } 69 | } else if (version < configVersion) { 70 | JsonObject defaultConfig = new JsonParser().parse(new InputStreamReader(configInputStream)).getAsJsonObject(); 71 | GsonUtils.extendJsonObject(defaultConfig, GsonUtils.ConflictStrategy.PREFER_FIRST_OBJ, configObject); 72 | configObject = defaultConfig; 73 | } 74 | 75 | configObject.addProperty("_version", configVersion); 76 | 77 | logger.warn("Saving config..."); 78 | JsonWriter writer = new JsonWriter(new FileWriter(configFile)); 79 | writer.setIndent("\t"); 80 | new Gson().toJson(configObject, writer); 81 | writer.close(); 82 | 83 | logger.warn("Check out your config and start the server."); 84 | return null; 85 | } 86 | 87 | return new Config(configObject); 88 | } catch (Throwable e) { 89 | logger.fatal("Cannot read config.", e); 90 | throw new ServerException("Cannot read config."); 91 | } 92 | } 93 | 94 | private void fill(String prefix, JsonObject json) { 95 | for (Map.Entry child : json.entrySet()) { 96 | String key = child.getKey(); 97 | JsonElement element = child.getValue(); 98 | 99 | if (element instanceof JsonObject) { 100 | fill(prefix + key + ".", (JsonObject)element); 101 | } else { 102 | map.put(prefix + key, element); 103 | } 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/crypto/ClientCrypto.java: -------------------------------------------------------------------------------- 1 | package royaleserver.crypto; 2 | 3 | import royaleserver.network.protocol.Messages; 4 | import royaleserver.network.protocol.MessageHeader; 5 | 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.IOException; 8 | import java.nio.ByteBuffer; 9 | import java.nio.ByteOrder; 10 | import java.util.Arrays; 11 | 12 | public class ClientCrypto extends Crypto { 13 | protected ServerCrypto server; 14 | 15 | public ClientCrypto(byte[] serverKey) { 16 | super(); 17 | 18 | TweetNaCl.crypto_sign_keypair(privateKey, clientKey, false); 19 | this.serverKey = serverKey; 20 | 21 | sharedKey = Curve25519.scalarMult(privateKey, serverKey); 22 | sharedKey = Salsa.HSalsa20(new byte[16], sharedKey, Salsa.SIGMA); 23 | 24 | encryptNonce = new Nonce(); 25 | } 26 | 27 | public void setServer(ServerCrypto server) { 28 | this.server = server; 29 | } 30 | 31 | @Override 32 | public void decryptPacket(MessageHeader message) { 33 | switch (message.id) { 34 | case Messages.SERVER_HELLO: 35 | case Messages.LOGIN_FAILED: 36 | int len = ByteBuffer.wrap(message.payload, 0, 4).order(ByteOrder.LITTLE_ENDIAN).getInt(0); 37 | sessionKey = Arrays.copyOfRange(message.payload, 4, 4 + len); 38 | message.decrypted = message.payload; 39 | break; 40 | case Messages.LOGIN_OK: 41 | Nonce nonce = new Nonce(clientKey, serverKey, encryptNonce.getBytes()); 42 | message.decrypted = decrypt(message.payload, nonce); 43 | 44 | if (message.decrypted != null) { 45 | try { 46 | decryptNonce = new Nonce(Arrays.copyOfRange(message.decrypted, 0, 24)); 47 | server.encryptNonce = new Nonce(Arrays.copyOfRange(message.decrypted, 0, 24)); 48 | } catch (Exception e) { 49 | e.printStackTrace(); 50 | } 51 | 52 | sharedKey = Arrays.copyOfRange(message.decrypted, 24, 56); 53 | 54 | message.decrypted = Arrays.copyOfRange(message.decrypted, 56, message.decrypted.length); 55 | } 56 | break; 57 | default: 58 | message.decrypted = decrypt(message.payload); 59 | } 60 | } 61 | 62 | @Override 63 | public void encryptPacket(MessageHeader message) { 64 | switch (message.id) { 65 | case Messages.CLIENT_HELLO: 66 | message.payload = message.decrypted; 67 | break; 68 | case Messages.LOGIN: 69 | Nonce nonce = new Nonce(clientKey, serverKey); 70 | ByteArrayOutputStream toEncrypt = new ByteArrayOutputStream(); 71 | 72 | try { 73 | toEncrypt.write(sessionKey); 74 | toEncrypt.write(encryptNonce.getBytes()); 75 | toEncrypt.write(message.decrypted); 76 | } catch (IOException ignored) {} 77 | 78 | ByteArrayOutputStream encrypted = new ByteArrayOutputStream(); 79 | 80 | try { 81 | encrypted.write(clientKey); 82 | encrypted.write(encrypt(toEncrypt.toByteArray(), nonce)); 83 | } catch (IOException ignored) {} 84 | 85 | message.payload = encrypted.toByteArray(); 86 | break; 87 | default: 88 | message.payload = encrypt(message.decrypted); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/crypto/Crypto.java: -------------------------------------------------------------------------------- 1 | package royaleserver.crypto; 2 | 3 | import royaleserver.network.protocol.MessageHeader; 4 | import royaleserver.utils.LogManager; 5 | import royaleserver.utils.Logger; 6 | 7 | public abstract class Crypto { 8 | public static class CryptoException extends Exception { 9 | public CryptoException(String message) { 10 | super(message); 11 | } 12 | } 13 | 14 | private static Logger logger = LogManager.getLogger(Crypto.class); 15 | 16 | protected byte[] privateKey = new byte[TweetNaCl.SIGN_PUBLIC_KEY_BYTES]; 17 | protected byte[] serverKey; 18 | protected byte[] clientKey = new byte[TweetNaCl.SIGN_SECRET_KEY_BYTES]; 19 | protected byte[] sharedKey; 20 | protected Nonce decryptNonce = new Nonce(); 21 | protected Nonce encryptNonce = new Nonce(); 22 | protected byte[] sessionKey; 23 | 24 | public byte[] getSessionKey() { 25 | return sessionKey; 26 | } 27 | 28 | public void setSessionKey(byte[] sessionKey) { 29 | this.sessionKey = sessionKey; 30 | } 31 | 32 | public byte[] getSharedKey() { 33 | return sharedKey; 34 | } 35 | 36 | public void setSharedKey(byte[] sharedKey) throws CryptoException { 37 | if (sharedKey.length != 32) { 38 | throw new CryptoException("sharedKey.length must be 32"); 39 | } 40 | 41 | this.sharedKey = sharedKey; 42 | } 43 | 44 | public byte[] encrypt(byte[] message) { 45 | return encrypt(message, null); 46 | } 47 | 48 | public byte[] encrypt(byte[] message, Nonce nonce) { 49 | if (nonce == null) { 50 | encryptNonce.increment(); 51 | nonce = encryptNonce; 52 | } 53 | 54 | return TweetNaCl.secretbox(message, nonce.getBytes(), sharedKey); 55 | } 56 | 57 | public byte[] decrypt(byte[] message) { 58 | return decrypt(message, null); 59 | } 60 | 61 | public byte[] decrypt(byte[] message, Nonce nonce) { 62 | if (nonce == null) { 63 | decryptNonce.increment(); 64 | nonce = decryptNonce; 65 | } 66 | 67 | return TweetNaCl.secretbox_open(message, nonce.getBytes(), sharedKey); 68 | } 69 | 70 | public abstract void decryptPacket(MessageHeader message); 71 | public abstract void encryptPacket(MessageHeader message); 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/crypto/Nonce.java: -------------------------------------------------------------------------------- 1 | package royaleserver.crypto; 2 | 3 | import ove.crypto.digest.Blake2b; 4 | 5 | import java.nio.ByteBuffer; 6 | import java.nio.ByteOrder; 7 | import java.security.SecureRandom; 8 | 9 | public class Nonce { 10 | public static class NonceException extends Exception { 11 | public NonceException(String message) { 12 | super(message); 13 | } 14 | } 15 | 16 | private byte[] bytes; 17 | 18 | public Nonce() { 19 | bytes = new byte[24]; 20 | SecureRandom r = new SecureRandom(); 21 | r.nextBytes(bytes); 22 | } 23 | 24 | public Nonce(byte[] nonce) throws NonceException { 25 | if (nonce.length != 24) { 26 | throw new NonceException("nonce.length must be 24"); 27 | } 28 | 29 | bytes = nonce; 30 | } 31 | 32 | public Nonce(byte[] clientKey, byte[] serverKey) { 33 | this(clientKey, serverKey, null); 34 | } 35 | 36 | public Nonce(byte[] clientKey, byte[] serverKey, byte[] nonce) { 37 | final Blake2b hash = Blake2b.Digest.newInstance(24); 38 | if (nonce != null) { 39 | hash.update(nonce); 40 | } 41 | 42 | hash.update(clientKey); 43 | hash.update(serverKey); 44 | 45 | bytes = hash.digest(); 46 | } 47 | 48 | public void increment() { 49 | ByteBuffer buffer = ByteBuffer.wrap(bytes, 0, 2); 50 | buffer.order(ByteOrder.LITTLE_ENDIAN); 51 | short val = buffer.getShort(0); 52 | val += 2; 53 | buffer.putShort(0, val); 54 | 55 | bytes[0] = buffer.get(0); 56 | bytes[1] = buffer.get(1); 57 | } 58 | 59 | public byte[] getBytes() { 60 | return bytes; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/crypto/ServerCrypto.java: -------------------------------------------------------------------------------- 1 | package royaleserver.crypto; 2 | 3 | import royaleserver.network.protocol.Messages; 4 | import royaleserver.network.protocol.MessageHeader; 5 | import royaleserver.utils.Hex; 6 | 7 | import java.io.ByteArrayOutputStream; 8 | import java.io.IOException; 9 | import java.util.Arrays; 10 | 11 | public class ServerCrypto extends Crypto { 12 | protected ClientCrypto client; 13 | protected Nonce nonce; 14 | 15 | public ServerCrypto() { 16 | privateKey = Hex.toByteArray("1891d401fadb51d25d3a9174d472a9f691a45b974285d47729c45c6538070d85"); 17 | serverKey = Hex.toByteArray("72f1a4a4c48e44da0c42310f800e96624e6dc6a641a9d41c3b5039d8dfadc27e"); 18 | } 19 | 20 | public void setClient(ClientCrypto client) { 21 | this.client = client; 22 | sharedKey = client.sharedKey; 23 | } 24 | 25 | @Override 26 | public void decryptPacket(MessageHeader message) { 27 | switch (message.id) { 28 | case Messages.CLIENT_HELLO: 29 | message.decrypted = message.payload; 30 | break; 31 | case Messages.LOGIN: 32 | clientKey = Arrays.copyOfRange(message.payload, 0, 32); 33 | byte[] cipherText = Arrays.copyOfRange(message.payload, 32, message.payload.length); 34 | 35 | sharedKey = Curve25519.scalarMult(privateKey, clientKey); 36 | sharedKey = Salsa.HSalsa20(new byte[16], sharedKey, Salsa.SIGMA); 37 | 38 | Nonce nonce = new Nonce(clientKey, serverKey); 39 | message.decrypted = decrypt(cipherText, nonce); 40 | 41 | if (message.decrypted != null) { 42 | sessionKey = Arrays.copyOfRange(message.decrypted, 0, 24); 43 | try { 44 | decryptNonce = new Nonce(Arrays.copyOfRange(message.decrypted, 24, 48)); 45 | client.encryptNonce = new Nonce(Arrays.copyOfRange(message.decrypted, 24, 48)); 46 | } catch (Exception e) { 47 | e.printStackTrace(); 48 | } 49 | 50 | message.decrypted = Arrays.copyOfRange(message.decrypted, 48, message.decrypted.length); 51 | } 52 | break; 53 | default: 54 | message.decrypted = decrypt(message.payload); 55 | } 56 | } 57 | 58 | @Override 59 | public void encryptPacket(MessageHeader message) { 60 | switch (message.id) { 61 | case Messages.SERVER_HELLO: 62 | message.payload = message.decrypted; 63 | break; 64 | case Messages.LOGIN_FAILED: 65 | if(nonce != null) { 66 | message.payload = encrypt(message.decrypted); 67 | break; 68 | } 69 | case Messages.LOGIN_OK: 70 | nonce = new Nonce(clientKey, serverKey, decryptNonce.getBytes()); 71 | ByteArrayOutputStream toEncrypt = new ByteArrayOutputStream(); 72 | 73 | try { 74 | toEncrypt.write(encryptNonce.getBytes()); 75 | toEncrypt.write(sharedKey); 76 | toEncrypt.write(message.decrypted); 77 | } catch (IOException ignored) {} 78 | 79 | message.payload = encrypt(toEncrypt.toByteArray(), nonce); 80 | break; 81 | default: 82 | message.payload = encrypt(message.decrypted); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/csv/Column.java: -------------------------------------------------------------------------------- 1 | package royaleserver.csv; 2 | 3 | public class Column { 4 | private Table table; 5 | private int index; 6 | 7 | public Column(Table table, int index) { 8 | this.table = table; 9 | this.index = index; 10 | } 11 | 12 | public Table getTable() { 13 | return table; 14 | } 15 | 16 | public int getIndex() { 17 | return index; 18 | } 19 | 20 | public String getName() { 21 | return table.getColumnName(index); 22 | } 23 | 24 | public String getType() { 25 | return table.getColumnType(index); 26 | } 27 | 28 | public Value getValue(int row) { 29 | return table.getValue(index, row); 30 | } 31 | 32 | public Value getValue(Row row) { 33 | if (table != row.getTable()) { 34 | return null; 35 | } 36 | 37 | return table.getValue(index, row.getIndex()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/csv/Row.java: -------------------------------------------------------------------------------- 1 | package royaleserver.csv; 2 | 3 | public class Row { 4 | private Table table; 5 | private int index; 6 | 7 | public Row(Table table, int index) { 8 | this.table = table; 9 | this.index = index; 10 | } 11 | 12 | public Table getTable() { 13 | return table; 14 | } 15 | 16 | public int getIndex() { 17 | return index; 18 | } 19 | 20 | public Value getValue(int row) { 21 | return table.getValue(row, index); 22 | } 23 | 24 | public Value getValue(Column column) { 25 | if (table != column.getTable()) { 26 | return null; 27 | } 28 | 29 | return table.getValue(column.getIndex(), index); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/csv/Value.java: -------------------------------------------------------------------------------- 1 | package royaleserver.csv; 2 | 3 | public class Value { 4 | private Table table; 5 | private int column, row; 6 | 7 | public Value(Table table, int column, int row) { 8 | this.table = table; 9 | this.column = column; 10 | this.row = row; 11 | } 12 | 13 | public int getColumnId() { 14 | return column; 15 | } 16 | 17 | public int getRowId() { 18 | return row; 19 | } 20 | 21 | public Column getColumn() { 22 | return table.getColumn(column); 23 | } 24 | 25 | public Row getRow() { 26 | return table.getRow(row); 27 | } 28 | 29 | public String getType() { 30 | return table.getColumnType(column); 31 | } 32 | 33 | public String getValue() { 34 | return table.getValueValue(column, row); 35 | } 36 | 37 | public String[] getValues() { 38 | return getValue().split("\n"); 39 | } 40 | 41 | 42 | public boolean empty() { 43 | return getValue().trim().length() == 0; 44 | } 45 | 46 | public String asString() { 47 | return asString(false); 48 | } 49 | 50 | public String asString(boolean nullIfEmpty) { 51 | return (nullIfEmpty && empty()) ? null : getValue(); 52 | } 53 | 54 | public String asString(String def) { 55 | return empty() ? def : asString(); 56 | } 57 | 58 | public boolean asBoolean() { 59 | return getValue().equalsIgnoreCase("TRUE"); 60 | } 61 | 62 | public boolean asBoolean(boolean def) { 63 | return empty() ? def : asBoolean(); 64 | } 65 | 66 | public int asInt() { 67 | return Integer.valueOf(getValue()); 68 | } 69 | 70 | public int asInt(int def) { 71 | return empty() ? def : asInt(); 72 | } 73 | 74 | public Integer asIntNullable() { 75 | return empty() ? null : Integer.valueOf(getValue()); 76 | } 77 | 78 | public float asFloat() { 79 | return Float.valueOf(getValue()); 80 | } 81 | 82 | public float asFloat(float def) { 83 | return empty() ? def : asFloat(); 84 | } 85 | 86 | public Float asFloatNullable() { 87 | return empty() ? null : Float.valueOf(getValue()); 88 | } 89 | 90 | 91 | public String[] asStringArray() { 92 | return getValues(); 93 | } 94 | 95 | public boolean[] asBooleanArray() { 96 | String[] values = getValues(); 97 | boolean[] results = new boolean[values.length]; 98 | 99 | for (int i = 0; i < values.length; ++i) { 100 | results[i] = values[i].equalsIgnoreCase("TRUE"); 101 | } 102 | 103 | return results; 104 | } 105 | 106 | public int[] asIntArray() { 107 | String[] values = getValues(); 108 | int[] results = new int[values.length]; 109 | 110 | for (int i = 0; i < values.length; ++i) { 111 | results[i] = Integer.valueOf(values[i]); 112 | } 113 | 114 | return results; 115 | } 116 | 117 | public float[] asFloatArray() { 118 | String[] values = getValues(); 119 | float[] results = new float[values.length]; 120 | 121 | for (int i = 0; i < values.length; ++i) { 122 | results[i] = Float.valueOf(values[i]); 123 | } 124 | 125 | return results; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/DataServices.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database; 2 | 3 | import org.hibernate.SessionFactory; 4 | import royaleserver.database.service.*; 5 | 6 | /** 7 | * A class that contains all the services. 8 | */ 9 | public final class DataServices { 10 | public final ArenaService arenaService; 11 | public final AssetService assetService; 12 | public final CardService cardService; 13 | public final ChestService chestService; 14 | public final ClanBadgeService clanBadgeService; 15 | public final ClanRoleService clanRoleService; 16 | public final ClanService clanService; 17 | public final ExpLevelService expLevelService; 18 | public final HomeChestService homeChestService; 19 | public final PlayerCardService playerCardService; 20 | public final PlayerDeckCardService playerDeckCardService; 21 | public final PlayerService playerService; 22 | public final UnlockCodeService unlockCodeService; 23 | 24 | public DataServices(SessionFactory sessionFactory) { 25 | arenaService = new ArenaService(sessionFactory); 26 | assetService = new AssetService(sessionFactory); 27 | cardService = new CardService(sessionFactory); 28 | chestService = new ChestService(sessionFactory); 29 | clanBadgeService = new ClanBadgeService(sessionFactory); 30 | clanRoleService = new ClanRoleService(sessionFactory); 31 | clanService = new ClanService(sessionFactory); 32 | expLevelService = new ExpLevelService(sessionFactory); 33 | homeChestService = new HomeChestService(sessionFactory); 34 | playerCardService = new PlayerCardService(sessionFactory); 35 | playerDeckCardService = new PlayerDeckCardService(sessionFactory); 36 | playerService = new PlayerService(sessionFactory); 37 | unlockCodeService = new UnlockCodeService(sessionFactory); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/entity/ArenaEntity.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.entity; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.NamedQuery; 5 | import javax.persistence.Table; 6 | 7 | @Entity 8 | @Table(name = "arenas") 9 | @NamedQuery(name = "ArenaEntity.all", query = "SELECT arenaEntity FROM ArenaEntity arenaEntity") 10 | public class ArenaEntity extends LogicEntity { 11 | public ArenaEntity() {} 12 | 13 | public ArenaEntity(String name) { 14 | super(name); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/entity/AssetEntity.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.entity; 2 | 3 | import javax.persistence.*; 4 | import java.util.Date; 5 | 6 | @Entity 7 | @Table(name = "assets") 8 | @NamedQuery(name = "AssetEntity.byName", query = "SELECT assetEntity FROM AssetEntity assetEntity WHERE assetEntity.name = :name") 9 | public class AssetEntity { 10 | @Id 11 | @GeneratedValue(strategy = GenerationType.IDENTITY) 12 | private long id; 13 | 14 | @Column(length = 128, unique = true, nullable = false) 15 | private String name; 16 | 17 | @Column(nullable = false, columnDefinition = "TIMESTAMP") 18 | @Temporal(value = TemporalType.TIMESTAMP) 19 | private Date lastUpdated; 20 | 21 | public long getId() { 22 | return id; 23 | } 24 | 25 | public AssetEntity setId(long id) { 26 | this.id = id; 27 | return this; 28 | } 29 | 30 | public String getName() { 31 | return name; 32 | } 33 | 34 | public AssetEntity setName(String name) { 35 | this.name = name; 36 | return this; 37 | } 38 | 39 | public Date getLastUpdated() { 40 | return lastUpdated; 41 | } 42 | 43 | public AssetEntity setLastUpdated(Date lastUpdated) { 44 | this.lastUpdated = lastUpdated; 45 | return this; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/entity/CardEntity.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.entity; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.NamedQuery; 5 | import javax.persistence.Table; 6 | 7 | @Entity 8 | @Table(name = "cards") 9 | @NamedQuery(name = "CardEntity.all", query = "SELECT cardEntity FROM CardEntity cardEntity") 10 | public class CardEntity extends LogicEntity { 11 | public CardEntity() {} 12 | 13 | public CardEntity(String name) { 14 | super(name); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/entity/ChestEntity.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.entity; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.NamedQuery; 5 | import javax.persistence.Table; 6 | 7 | @Entity 8 | @Table(name = "chests") 9 | @NamedQuery(name = "ChestEntity.all", query = "SELECT chestEntity FROM ChestEntity chestEntity") 10 | public class ChestEntity extends LogicEntity { 11 | public ChestEntity() {} 12 | 13 | public ChestEntity(String name) { 14 | super(name); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/entity/ClanBadgeEntity.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.entity; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.NamedQuery; 5 | import javax.persistence.Table; 6 | 7 | @Entity 8 | @Table(name = "clan_badges") 9 | @NamedQuery(name = "ClanBadgeEntity.all", query = "SELECT clanBadgeEntity FROM ClanBadgeEntity clanBadgeEntity") 10 | public class ClanBadgeEntity extends LogicEntity { 11 | public ClanBadgeEntity() {} 12 | 13 | public ClanBadgeEntity(String name) { 14 | super(name); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/entity/ClanEntity.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.entity; 2 | 3 | import royaleserver.logic.ClanBadge; 4 | 5 | import javax.persistence.*; 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | @Entity 10 | @Table(name = "clans") 11 | 12 | @NamedQueries(value = { 13 | @NamedQuery(name = "ClanEntity.byId", query = "SELECT clan from ClanEntity clan WHERE clan.id = :id"), 14 | @NamedQuery(name = "ClanEntity.byName", query = "SELECT clan FROM ClanEntity clan WHERE LOWER(clan.name) LIKE LOWER(:name)") 15 | }) 16 | public class ClanEntity { 17 | @Id 18 | @GeneratedValue(strategy = GenerationType.IDENTITY) 19 | private long id; 20 | 21 | @Column(nullable = false) 22 | private String name = ""; 23 | 24 | @Column(nullable = false, columnDefinition = "TEXT") 25 | private String description = ""; 26 | 27 | @ManyToOne(optional = false) 28 | @JoinColumn(name = "badge_id") 29 | private ClanBadgeEntity badge; 30 | 31 | @Column(nullable = false) 32 | private int score = 0; 33 | 34 | @Column(nullable = false) 35 | private int donationsPerWeek = 0; 36 | 37 | @Column(nullable = false) 38 | @Enumerated(EnumType.ORDINAL) 39 | private ClanType type = ClanType.OPEN; 40 | 41 | @Column(nullable = false) 42 | private int requiredTrophies = 0; 43 | 44 | // TODO: Location 45 | 46 | @OneToMany(fetch = FetchType.LAZY, mappedBy = "clan") 47 | private Set members = new HashSet<>(); 48 | 49 | 50 | public long getId() { 51 | return id; 52 | } 53 | 54 | public ClanEntity setId(long id) { 55 | this.id = id; 56 | return this; 57 | } 58 | 59 | public String getName() { 60 | return name; 61 | } 62 | 63 | public ClanEntity setName(String name) { 64 | this.name = name; 65 | return this; 66 | } 67 | 68 | public String getDescription() { 69 | return description; 70 | } 71 | 72 | public ClanEntity setDescription(String description) { 73 | this.description = description; 74 | return this; 75 | } 76 | 77 | public ClanBadgeEntity getBadge() { 78 | return badge; 79 | } 80 | 81 | public ClanEntity setBadge(ClanBadgeEntity badge) { 82 | this.badge = badge; 83 | return this; 84 | } 85 | 86 | public int getScore() { 87 | return score; 88 | } 89 | 90 | public ClanEntity setScore(int score) { 91 | this.score = score; 92 | return this; 93 | } 94 | 95 | public int getDonationsPerWeek() { 96 | return donationsPerWeek; 97 | } 98 | 99 | public ClanEntity setDonationsPerWeek(int donationsPerWeek) { 100 | this.donationsPerWeek = donationsPerWeek; 101 | return this; 102 | } 103 | 104 | public ClanType getType() { 105 | return type; 106 | } 107 | 108 | public ClanEntity setType(ClanType type) { 109 | this.type = type; 110 | return this; 111 | } 112 | 113 | public int getRequiredTrophies() { 114 | return requiredTrophies; 115 | } 116 | 117 | public ClanEntity setRequiredTrophies(int requiredTrophies) { 118 | this.requiredTrophies = requiredTrophies; 119 | return this; 120 | } 121 | 122 | public Set getMembers() { 123 | return members; 124 | } 125 | 126 | public ClanEntity setMembers(Set players) { 127 | this.members = players; 128 | return this; 129 | } 130 | 131 | 132 | public ClanBadge getLogicBadge() { 133 | return ClanBadge.byDB(badge.getId()); 134 | } 135 | 136 | public ClanEntity setLogicBadge(ClanBadge badge) { 137 | return setBadge(badge.getDbEntity()); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/entity/ClanRoleEntity.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.entity; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.NamedQuery; 5 | import javax.persistence.Table; 6 | 7 | @Entity 8 | @Table(name = "clan_roles") 9 | @NamedQuery(name = "ClanRoleEntity.all", query = "SELECT clanRoleEntity FROM ClanRoleEntity clanRoleEntity") 10 | public class ClanRoleEntity extends LogicEntity { 11 | public ClanRoleEntity() {} 12 | 13 | public ClanRoleEntity(String name) { 14 | super(name); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/entity/ClanType.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.entity; 2 | 3 | public enum ClanType { 4 | OPEN, 5 | INVITE, 6 | CLOSED, 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/entity/ExpLevelEntity.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.entity; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.NamedQuery; 5 | import javax.persistence.Table; 6 | 7 | @Entity 8 | @Table(name = "exp_levels") 9 | @NamedQuery(name = "ExpLevelEntity.all", query = "SELECT expLevelEntity FROM ExpLevelEntity expLevelEntity") 10 | public class ExpLevelEntity extends LogicEntity { 11 | public ExpLevelEntity() {} 12 | 13 | public ExpLevelEntity(String name) { 14 | super(name); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/entity/HomeChestEntity.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.entity; 2 | 3 | import royaleserver.logic.Chest; 4 | 5 | import javax.persistence.*; 6 | import java.util.Date; 7 | 8 | @Entity 9 | @Table(name = "home_chest", indexes = { 10 | @Index(unique = true, columnList = "player_id,slot") 11 | }) 12 | public class HomeChestEntity implements java.io.Serializable { 13 | @Id 14 | @ManyToOne 15 | @PrimaryKeyJoinColumn(name = "player_id", referencedColumnName = "id") 16 | private PlayerEntity player; 17 | 18 | @Id 19 | private int slot; 20 | 21 | @ManyToOne 22 | @PrimaryKeyJoinColumn(name = "chest_id", referencedColumnName = "id") 23 | private ChestEntity chest; 24 | 25 | @Enumerated(EnumType.ORDINAL) 26 | @Column(nullable = false) 27 | private HomeChestStatus status; 28 | 29 | @Column(nullable = true) 30 | @Temporal(value = TemporalType.TIMESTAMP) 31 | private Date openStart = null; 32 | 33 | @Column(nullable = true) 34 | @Temporal(value = TemporalType.TIMESTAMP) 35 | private Date openEnd = null; 36 | 37 | 38 | public PlayerEntity getPlayer() { 39 | return player; 40 | } 41 | 42 | public HomeChestEntity setPlayer(PlayerEntity player) { 43 | this.player = player; 44 | return this; 45 | } 46 | 47 | public int getSlot() { 48 | return slot; 49 | } 50 | 51 | public HomeChestEntity setSlot(int slot) { 52 | this.slot = slot; 53 | return this; 54 | } 55 | 56 | public ChestEntity getChest() { 57 | return chest; 58 | } 59 | 60 | public HomeChestEntity setChest(ChestEntity chest) { 61 | this.chest = chest; 62 | return this; 63 | } 64 | 65 | public HomeChestStatus getStatus() { 66 | return status; 67 | } 68 | 69 | public HomeChestEntity setStatus(HomeChestStatus status) { 70 | this.status = status; 71 | return this; 72 | } 73 | 74 | public Date getOpenStart() { 75 | return openStart; 76 | } 77 | 78 | public HomeChestEntity setOpenStart(Date openStart) { 79 | this.openStart = openStart; 80 | return this; 81 | } 82 | 83 | public Date getOpenEnd() { 84 | return openEnd; 85 | } 86 | 87 | public HomeChestEntity setOpenEnd(Date openEnd) { 88 | this.openEnd = openEnd; 89 | return this; 90 | } 91 | 92 | public Chest getLogicChest() { 93 | return Chest.byDB(chest.getId()); 94 | } 95 | 96 | public HomeChestEntity setLogicChest(Chest chest) { 97 | return setChest(chest.getDbEntity()); 98 | } 99 | 100 | @Override 101 | public boolean equals(Object o) { 102 | if (this == o) { 103 | return true; 104 | } 105 | if (!(o instanceof HomeChestEntity)) { 106 | return false; 107 | } 108 | 109 | HomeChestEntity that = (HomeChestEntity)o; 110 | 111 | return slot == that.slot && player.equals(that.player); 112 | } 113 | 114 | @Override 115 | public int hashCode() { 116 | int result = player.hashCode(); 117 | result = 31 * result + slot; 118 | return result; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/entity/HomeChestStatus.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.entity; 2 | 3 | public enum HomeChestStatus { 4 | IDLE, 5 | OPENING, 6 | OPENED 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/entity/LogicEntity.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.entity; 2 | 3 | import javax.persistence.*; 4 | 5 | @MappedSuperclass 6 | public abstract class LogicEntity { 7 | @Id 8 | @GeneratedValue(strategy = GenerationType.IDENTITY) 9 | private long id; 10 | 11 | @Column(nullable = false, unique = true) 12 | private String name; 13 | 14 | public LogicEntity() {} 15 | 16 | public LogicEntity(String name) { 17 | this.name = name; 18 | } 19 | 20 | public long getId() { 21 | return id; 22 | } 23 | 24 | public String getName() { 25 | return name; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/entity/PlayerCardEntity.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.entity; 2 | 3 | import royaleserver.logic.Card; 4 | 5 | import javax.persistence.*; 6 | import java.io.Serializable; 7 | 8 | @Entity 9 | @Table(name = "player_card", indexes = { 10 | @Index(unique = true, columnList = "player_id,card_id") 11 | }) 12 | public class PlayerCardEntity implements Serializable { 13 | @Id 14 | @ManyToOne 15 | @PrimaryKeyJoinColumn(name = "player_id", referencedColumnName = "id") 16 | private PlayerEntity player; 17 | 18 | @Id 19 | @ManyToOne 20 | @PrimaryKeyJoinColumn(name = "card_id", referencedColumnName = "id") 21 | private CardEntity card; 22 | 23 | @Column(nullable = false) 24 | private int level = 1; 25 | 26 | @Column(nullable = false) 27 | private int count = 0; 28 | 29 | public PlayerCardEntity() { 30 | } 31 | 32 | public PlayerCardEntity(PlayerEntity player, CardEntity card, int level, int count) { 33 | this.player = player; 34 | this.card = card; 35 | this.level = level; 36 | this.count = count; 37 | } 38 | 39 | public PlayerEntity getPlayer() { 40 | return player; 41 | } 42 | 43 | public CardEntity getCard() { 44 | return card; 45 | } 46 | 47 | public int getLevel() { 48 | return level; 49 | } 50 | 51 | public PlayerCardEntity setLevel(int level) { 52 | this.level = level; 53 | return this; 54 | } 55 | 56 | public int getCount() { 57 | return count; 58 | } 59 | 60 | public PlayerCardEntity setCount(int count) { 61 | this.count = count; 62 | return this; 63 | } 64 | 65 | public Card getLogicCard() { 66 | return Card.byDB(card.getId()); 67 | } 68 | 69 | @Override 70 | public boolean equals(Object o) { 71 | if (this == o) { 72 | return true; 73 | } 74 | if (!(o instanceof PlayerCardEntity)) { 75 | return false; 76 | } 77 | 78 | PlayerCardEntity that = (PlayerCardEntity)o; 79 | 80 | if (player != null ? !player.equals(that.player) : that.player != null) { 81 | return false; 82 | } 83 | return card != null ? card.equals(that.card) : that.card == null; 84 | } 85 | 86 | @Override 87 | public int hashCode() { 88 | int result = player != null ? player.hashCode() : 0; 89 | result = 31 * result + (card != null ? card.hashCode() : 0); 90 | return result; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/entity/PlayerDeckCardEntity.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.entity; 2 | 3 | import royaleserver.logic.Card; 4 | 5 | import javax.persistence.*; 6 | import java.io.Serializable; 7 | 8 | @Entity 9 | @Table(name = "player_deck_card", indexes = { 10 | @Index(unique = true, columnList = "player_id,deck_slot,card_slot") 11 | }) 12 | public class PlayerDeckCardEntity implements Serializable { 13 | @Id 14 | @ManyToOne 15 | @PrimaryKeyJoinColumn(name = "player_id", referencedColumnName = "id") 16 | private PlayerEntity player; 17 | 18 | @Id 19 | @Column(name = "deck_slot") 20 | private int deckSlot; 21 | 22 | @Id 23 | @Column(name = "card_slot") 24 | private int cardSlot; 25 | 26 | @ManyToOne(optional = false, fetch = FetchType.LAZY) 27 | private CardEntity card; 28 | 29 | public PlayerDeckCardEntity() { 30 | } 31 | 32 | public PlayerDeckCardEntity(PlayerEntity player, int deckSlot, int cardSlot, CardEntity card) { 33 | this.player = player; 34 | this.deckSlot = deckSlot; 35 | this.cardSlot = cardSlot; 36 | this.card = card; 37 | } 38 | 39 | public PlayerEntity getPlayer() { 40 | return player; 41 | } 42 | 43 | public int getDeckSlot() { 44 | return deckSlot; 45 | } 46 | 47 | public int getCardSlot() { 48 | return cardSlot; 49 | } 50 | 51 | public CardEntity getCard() { 52 | return card; 53 | } 54 | 55 | public void setCard(CardEntity card) { 56 | this.card = card; 57 | } 58 | 59 | public Card getLogicCard() { 60 | return Card.byDB(card.getId()); 61 | } 62 | 63 | public void setLogicCard(Card card) { 64 | setCard(card.getDbEntity()); 65 | } 66 | 67 | @Override 68 | public boolean equals(Object o) { 69 | if (this == o) { 70 | return true; 71 | } 72 | if (!(o instanceof PlayerDeckCardEntity)) { 73 | return false; 74 | } 75 | 76 | PlayerDeckCardEntity that = (PlayerDeckCardEntity)o; 77 | 78 | if (deckSlot != that.deckSlot) { 79 | return false; 80 | } 81 | if (cardSlot != that.cardSlot) { 82 | return false; 83 | } 84 | return player != null ? player.equals(that.player) : that.player == null; 85 | } 86 | 87 | @Override 88 | public int hashCode() { 89 | int result = player != null ? player.hashCode() : 0; 90 | result = 31 * result + deckSlot; 91 | result = 31 * result + cardSlot; 92 | return result; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/entity/UnlockCodeEntity.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.entity; 2 | 3 | import javax.persistence.*; 4 | 5 | @Entity 6 | @Table(name = "unlock_codes") 7 | @NamedQueries({ 8 | @NamedQuery(name = "UnlockCodeEntity.use", query = "DELETE FROM UnlockCodeEntity unlockCode WHERE unlockCode.code=:code") 9 | }) 10 | public class UnlockCodeEntity { 11 | public static final int CODE_LENGTH = 12; 12 | 13 | @Id 14 | @Column(unique = true, nullable = false, length = CODE_LENGTH, updatable = false) 15 | private String code; 16 | 17 | public UnlockCodeEntity() { 18 | } 19 | 20 | public UnlockCodeEntity(String code) { 21 | assert code.length() == CODE_LENGTH; 22 | this.code = code; 23 | } 24 | 25 | public String getCode() { 26 | return code; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/service/ArenaService.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.service; 2 | 3 | import org.hibernate.SessionFactory; 4 | import royaleserver.database.entity.ArenaEntity; 5 | 6 | public class ArenaService extends LogicService { 7 | public ArenaService(SessionFactory sessionFactory) { 8 | super(sessionFactory, ArenaEntity.class); 9 | } 10 | 11 | @Override 12 | protected ArenaEntity createEntity(String name) { 13 | return new ArenaEntity(name); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/service/AssetService.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.service; 2 | 3 | import org.hibernate.Session; 4 | import org.hibernate.SessionFactory; 5 | import royaleserver.database.entity.AssetEntity; 6 | import royaleserver.database.util.Transaction; 7 | 8 | import javax.persistence.NoResultException; 9 | import java.util.Date; 10 | 11 | public class AssetService extends Service { 12 | public AssetService(SessionFactory sessionFactory) { 13 | super(sessionFactory); 14 | } 15 | 16 | public AssetEntity get(String name) { 17 | AssetEntity entity; 18 | 19 | try (Session session = session()) { 20 | try { 21 | entity = session.createNamedQuery("AssetEntity.byName", AssetEntity.class) 22 | .setParameter("name", name) 23 | .getSingleResult(); 24 | } catch (NoResultException ignored) { 25 | entity = new AssetEntity(); 26 | entity.setName(name); 27 | entity.setLastUpdated(new Date(System.currentTimeMillis())); 28 | } 29 | } 30 | 31 | return entity; 32 | } 33 | 34 | public void update(AssetEntity entity) { 35 | entity.setLastUpdated(new Date(System.currentTimeMillis())); 36 | 37 | try (Session session = session(); Transaction transaction = transaction(session)) { 38 | session.merge(entity); 39 | transaction.commit(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/service/CardService.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.service; 2 | 3 | import org.hibernate.SessionFactory; 4 | import royaleserver.database.entity.CardEntity; 5 | 6 | public class CardService extends LogicService { 7 | public CardService(SessionFactory sessionFactory) { 8 | super(sessionFactory, CardEntity.class); 9 | } 10 | 11 | @Override 12 | protected CardEntity createEntity(String name) { 13 | return new CardEntity(name); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/service/ChestService.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.service; 2 | 3 | import org.hibernate.SessionFactory; 4 | import royaleserver.database.entity.ChestEntity; 5 | 6 | public class ChestService extends LogicService { 7 | public ChestService(SessionFactory sessionFactory) { 8 | super(sessionFactory, ChestEntity.class); 9 | } 10 | 11 | @Override 12 | protected ChestEntity createEntity(String name) { 13 | return new ChestEntity(name); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/service/ClanBadgeService.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.service; 2 | 3 | import org.hibernate.SessionFactory; 4 | import royaleserver.database.entity.ClanBadgeEntity; 5 | 6 | public class ClanBadgeService extends LogicService { 7 | public ClanBadgeService(SessionFactory sessionFactory) { 8 | super(sessionFactory, ClanBadgeEntity.class); 9 | } 10 | 11 | @Override 12 | protected ClanBadgeEntity createEntity(String name) { 13 | return new ClanBadgeEntity(name); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/service/ClanRoleService.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.service; 2 | 3 | import org.hibernate.SessionFactory; 4 | import royaleserver.database.entity.ClanRoleEntity; 5 | 6 | public class ClanRoleService extends LogicService { 7 | public ClanRoleService(SessionFactory sessionFactory) { 8 | super(sessionFactory, ClanRoleEntity.class); 9 | } 10 | 11 | @Override 12 | protected ClanRoleEntity createEntity(String name) { 13 | return new ClanRoleEntity(name); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/service/ClanService.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.service; 2 | 3 | import org.hibernate.Session; 4 | import org.hibernate.SessionFactory; 5 | import royaleserver.database.entity.ClanEntity; 6 | import royaleserver.database.entity.ClanType; 7 | import royaleserver.database.util.Transaction; 8 | 9 | import javax.persistence.criteria.CriteriaBuilder; 10 | import javax.persistence.criteria.CriteriaQuery; 11 | import javax.persistence.criteria.Root; 12 | import java.util.List; 13 | 14 | public class ClanService extends Service { 15 | public ClanService(SessionFactory sessionFactory) { 16 | super(sessionFactory); 17 | } 18 | 19 | public ClanEntity add(ClanEntity entity){ 20 | try (Session session = session(); Transaction transaction = transaction(session)) { 21 | ClanEntity fromDB = (ClanEntity)session.merge(entity); 22 | transaction.commit(); 23 | return fromDB; 24 | } 25 | } 26 | 27 | public void remove(ClanEntity entity) { 28 | try (Session session = session(); Transaction transaction = transaction(session)) { 29 | session.remove(entity); 30 | transaction.commit(); 31 | } 32 | } 33 | 34 | public ClanEntity searchById(long id) { 35 | try (Session session = session()) { 36 | return session.createNamedQuery("ClanEntity.byId", ClanEntity.class).setParameter("id", id).getSingleResult(); 37 | } 38 | } 39 | 40 | public List searchByName(String name) { 41 | try (Session session = session()) { 42 | return session.createNamedQuery("ClanEntity.byName", ClanEntity.class).setParameter("name", name).getResultList(); 43 | } 44 | } 45 | 46 | public List search(String name, int minMembers, int maxMembers, int minTrophies, boolean onlyJoinable) { 47 | try (Session session = session()) { 48 | CriteriaBuilder builder = session.getCriteriaBuilder(); 49 | CriteriaQuery query = builder.createQuery(ClanEntity.class); 50 | Root root = query.from(ClanEntity.class); 51 | query.select(root); 52 | 53 | if (name != null && !name.isEmpty()) { 54 | query.where(builder.like(root.get("name"), "%" + name + "%")); 55 | } 56 | 57 | // TODO: Check min and max members 58 | 59 | if (minTrophies != 0) { 60 | query.where(builder.greaterThan(root.get("score"), minTrophies)); 61 | } 62 | 63 | if (onlyJoinable) { 64 | query.where(builder.equal(root.get("type"), builder.literal(ClanType.OPEN))); 65 | // TODO: Check members 66 | } 67 | 68 | return session.createQuery(query).getResultList(); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/service/ExpLevelService.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.service; 2 | 3 | import org.hibernate.SessionFactory; 4 | import royaleserver.database.entity.ExpLevelEntity; 5 | 6 | public class ExpLevelService extends LogicService { 7 | public ExpLevelService(SessionFactory sessionFactory) { 8 | super(sessionFactory, ExpLevelEntity.class); 9 | } 10 | 11 | @Override 12 | protected ExpLevelEntity createEntity(String name) { 13 | return new ExpLevelEntity(name); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/service/HomeChestService.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.service; 2 | 3 | import org.hibernate.Session; 4 | import org.hibernate.SessionFactory; 5 | import royaleserver.database.entity.HomeChestEntity; 6 | import royaleserver.database.util.Transaction; 7 | 8 | public class HomeChestService extends Service { 9 | public HomeChestService(SessionFactory sessionFactory) { 10 | super(sessionFactory); 11 | } 12 | 13 | public void put(HomeChestEntity entity) { 14 | try (Session session = session(); Transaction transaction = transaction(session)) { 15 | session.merge(entity); 16 | transaction.commit(); 17 | } 18 | } 19 | 20 | public void delete(HomeChestEntity entity) { 21 | try (Session session = session(); Transaction transaction = transaction(session)) { 22 | session.remove(entity); 23 | transaction.commit(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/service/LogicService.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.service; 2 | 3 | import org.hibernate.Session; 4 | import org.hibernate.SessionFactory; 5 | import royaleserver.database.entity.LogicEntity; 6 | import royaleserver.database.util.Transaction; 7 | 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | public abstract class LogicService extends Service { 12 | private final Class entityClass; 13 | private final String entityClassName; 14 | 15 | public LogicService(SessionFactory sessionFactory, Class entityClass) { 16 | super(sessionFactory); 17 | 18 | this.entityClass = entityClass; 19 | this.entityClassName = entityClass.getSimpleName(); 20 | } 21 | 22 | protected abstract EntityType createEntity(String name); 23 | 24 | public List all() { 25 | try (Session session = session()) { 26 | return session.createNamedQuery(entityClassName + ".all", entityClass).getResultList(); 27 | } 28 | } 29 | 30 | public void store(Map entries) { 31 | try (Session session = session(); Transaction transaction = transaction(session)) { 32 | for (Map.Entry entry : entries.entrySet()) { 33 | EntityType entity = createEntity(entry.getKey()); 34 | session.save(entity); 35 | entry.setValue(entity); 36 | } 37 | 38 | transaction.commit(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/service/PlayerCardService.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.service; 2 | 3 | import org.hibernate.SessionFactory; 4 | import royaleserver.database.entity.PlayerCardEntity; 5 | 6 | public class PlayerCardService extends RestfulService { 7 | public PlayerCardService(SessionFactory sessionFactory) { 8 | super(sessionFactory); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/service/PlayerDeckCardService.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.service; 2 | 3 | import org.hibernate.SessionFactory; 4 | import royaleserver.database.entity.PlayerDeckCardEntity; 5 | 6 | public class PlayerDeckCardService extends RestfulService { 7 | public PlayerDeckCardService(SessionFactory sessionFactory) { 8 | super(sessionFactory); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/service/PlayerService.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.service; 2 | 3 | import org.hibernate.Session; 4 | import org.hibernate.SessionFactory; 5 | import royaleserver.database.entity.PlayerEntity; 6 | import royaleserver.database.util.Transaction; 7 | import royaleserver.logic.Arena; 8 | import royaleserver.logic.ExpLevel; 9 | import royaleserver.utils.StringUtils; 10 | 11 | import java.util.Random; 12 | 13 | public class PlayerService extends Service { 14 | private final Random random = new Random(System.currentTimeMillis()); 15 | 16 | public PlayerService(SessionFactory sessionFactory) { 17 | super(sessionFactory); 18 | } 19 | 20 | public PlayerEntity create() { 21 | PlayerEntity playerEntity = new PlayerEntity(); 22 | playerEntity.setPassToken(StringUtils.randomString(32, 64)); 23 | playerEntity.setTrophies(6400); 24 | playerEntity.setLogicArena(Arena.by("Arena_L9")); 25 | playerEntity.setLogicLastExpLevel(ExpLevel.by(13)); 26 | playerEntity.setLogicExpLevel(ExpLevel.by(13)); 27 | playerEntity.setGold(10000); 28 | playerEntity.setGems(100000); 29 | playerEntity.setRandomSeed(random.nextLong()); 30 | playerEntity.setRareChance(random.nextFloat()); 31 | playerEntity.setEpicChance(random.nextFloat()); 32 | playerEntity.setLegendaryChance(random.nextFloat()); 33 | return add(playerEntity); 34 | } 35 | 36 | public PlayerEntity add(PlayerEntity entity){ 37 | try (Session session = session(); Transaction transaction = transaction(session)) { 38 | PlayerEntity fromDB = (PlayerEntity)session.merge(entity); 39 | transaction.commit(); 40 | return fromDB; 41 | } 42 | } 43 | 44 | public PlayerEntity get(long id){ 45 | try (Session session = session()) { 46 | return session.find(PlayerEntity.class, id); 47 | } 48 | } 49 | 50 | public void update(PlayerEntity entity){ 51 | try (Session session = session(); Transaction transaction = transaction(session)) { 52 | session.update(entity); 53 | transaction.commit(); 54 | } 55 | } 56 | 57 | public void clear() { 58 | try (Session session = session(); Transaction transaction = transaction(session)) { 59 | session.createNamedQuery(".clear").executeUpdate(); 60 | transaction.commit(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/service/Service.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.service; 2 | 3 | import org.hibernate.Session; 4 | import org.hibernate.SessionFactory; 5 | import royaleserver.database.util.CloseableTransaction; 6 | import royaleserver.database.util.Transaction; 7 | 8 | public abstract class Service { 9 | protected final SessionFactory sessionFactory; 10 | 11 | protected Service(SessionFactory sessionFactory) { 12 | this.sessionFactory = sessionFactory; 13 | } 14 | 15 | protected Session session() { 16 | return sessionFactory.openSession(); 17 | } 18 | 19 | protected Transaction transaction(Session session) { 20 | return new CloseableTransaction(session.beginTransaction()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/service/UnlockCodeService.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.service; 2 | 3 | import org.hibernate.Session; 4 | import org.hibernate.SessionFactory; 5 | import royaleserver.database.entity.UnlockCodeEntity; 6 | import royaleserver.database.util.Transaction; 7 | import royaleserver.utils.StringUtils; 8 | 9 | public class UnlockCodeService extends Service { 10 | public UnlockCodeService(SessionFactory sessionFactory) { 11 | super(sessionFactory); 12 | } 13 | 14 | /** 15 | * Generate, store, and return random unlock key. 16 | * @return Generated key 17 | */ 18 | public String generate() { 19 | String code = StringUtils.randomString(UnlockCodeEntity.CODE_LENGTH); 20 | 21 | try (Session session = session(); Transaction transaction = transaction(session)) { 22 | session.merge(new UnlockCodeEntity(code)); 23 | transaction.commit(); 24 | } 25 | 26 | return code; 27 | } 28 | 29 | public boolean use(String code) { 30 | boolean result; 31 | try (Session session = session(); Transaction transaction = transaction(session)) { 32 | try { 33 | result = session.createNamedQuery("UnlockCodeEntity.use") 34 | .setParameter("code", code) 35 | .executeUpdate() == 1; 36 | transaction.commit(); 37 | } catch (Throwable e) { 38 | e.printStackTrace(); 39 | result = false; 40 | } 41 | } 42 | 43 | return result; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/util/AssignedIdentityGenerator.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.util; 2 | 3 | import org.hibernate.engine.spi.SharedSessionContractImplementor; 4 | import org.hibernate.id.IdentityGenerator; 5 | 6 | import java.io.Serializable; 7 | 8 | public class AssignedIdentityGenerator extends IdentityGenerator { 9 | @Override 10 | public Serializable generate(SharedSessionContractImplementor session, Object obj) { 11 | if (obj instanceof Identifiable) { 12 | Identifiable identifiable = (Identifiable)obj; 13 | Serializable id = identifiable.getId(); 14 | if (id != null) { 15 | return id; 16 | } 17 | } 18 | 19 | return super.generate(session, obj); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/util/CloseableTransaction.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.util; 2 | 3 | import org.hibernate.Transaction; 4 | 5 | public class CloseableTransaction extends royaleserver.database.util.Transaction { 6 | private final Transaction transaction; 7 | 8 | public CloseableTransaction(Transaction transaction) { 9 | this.transaction = transaction; 10 | } 11 | 12 | @Override 13 | public void commit() { 14 | transaction.commit(); 15 | } 16 | 17 | @Override 18 | public void rollback() { 19 | transaction.rollback(); 20 | } 21 | 22 | @Override 23 | public void close() { 24 | if (transaction.isActive()) { 25 | transaction.rollback(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/util/Identifiable.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.util; 2 | 3 | import java.io.Serializable; 4 | 5 | public interface Identifiable { 6 | T getId(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/database/util/Transaction.java: -------------------------------------------------------------------------------- 1 | package royaleserver.database.util; 2 | 3 | public abstract class Transaction implements AutoCloseable { 4 | public abstract void commit(); 5 | public abstract void rollback(); 6 | public abstract void close(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/game/CodeEnterPlayer.java: -------------------------------------------------------------------------------- 1 | package royaleserver.game; 2 | 3 | import royaleserver.Server; 4 | import royaleserver.database.entity.PlayerEntity; 5 | import royaleserver.network.NetworkSession; 6 | import royaleserver.network.NetworkSessionHandler; 7 | import royaleserver.network.protocol.client.ClientMessageHandler; 8 | import royaleserver.network.protocol.client.messages.AccountUnlock; 9 | import royaleserver.network.protocol.client.messages.Ping; 10 | import royaleserver.network.protocol.server.messages.AccountUnlockFailed; 11 | import royaleserver.network.protocol.server.messages.AccountUnlockOk; 12 | import royaleserver.network.protocol.server.messages.LoginFailed; 13 | 14 | public class CodeEnterPlayer extends NetworkSession implements ClientMessageHandler { 15 | public CodeEnterPlayer(Server server, NetworkSessionHandler session) { 16 | super(server, session); 17 | 18 | LoginFailed loginFailed = new LoginFailed(); 19 | loginFailed.errorCode = LoginFailed.ERROR_CODE_ACCOUNT_BLOCKED; 20 | loginFailed.resourceFingerprintData = ""; 21 | loginFailed.redirectDomain = ""; 22 | loginFailed.contentURL = ""; 23 | loginFailed.updateURL = ""; 24 | loginFailed.reason = ""; 25 | loginFailed.secondsUntilMaintenanceEnd = 0; 26 | loginFailed.unknown_7 = (byte)0; 27 | loginFailed.unknown_8 = ""; 28 | session.sendMessage(loginFailed); 29 | } 30 | 31 | @Override 32 | public boolean handleAccountUnlock(AccountUnlock message) throws Throwable { 33 | if (server.getDataManager().getUnlockCodeService().use(message.unlockCode)) { 34 | AccountUnlockOk response = new AccountUnlockOk(); 35 | session.sendMessage(response); 36 | 37 | PlayerEntity playerEntity = server.getDataManager().getPlayerService().create(); 38 | session.replace(new Player(playerEntity, server, session)); 39 | } else { 40 | AccountUnlockFailed response = new AccountUnlockFailed(); 41 | session.sendMessage(response); 42 | } 43 | 44 | return true; 45 | } 46 | 47 | @Override 48 | public boolean handlePing(Ping message) throws Throwable { 49 | // Server do not have to response ping message, when account activation window is opened, so ignore it. 50 | return true; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/game/Deck.java: -------------------------------------------------------------------------------- 1 | package royaleserver.game; 2 | 3 | import royaleserver.database.entity.PlayerDeckCardEntity; 4 | 5 | public final class Deck { 6 | public static final int DECK_CARDS_COUNT = 8; 7 | 8 | private final PlayerCard[] cards = new PlayerCard[DECK_CARDS_COUNT]; 9 | private final PlayerDeckCardEntity[] entities = new PlayerDeckCardEntity[DECK_CARDS_COUNT]; 10 | private boolean changed = false; 11 | 12 | public Deck() { 13 | 14 | } 15 | 16 | public boolean changed() { 17 | return changed; 18 | } 19 | 20 | /** 21 | * Marks changed to false 22 | * @return old changed value 23 | */ 24 | public boolean markUnchanged() { 25 | boolean changed = this.changed; 26 | this.changed = false; 27 | return changed; 28 | } 29 | 30 | public boolean hasCard(PlayerCard card) { 31 | for (int i = 0; i < DECK_CARDS_COUNT; ++i) { 32 | if (cards[i] == card) { 33 | return true; 34 | } 35 | } 36 | 37 | return false; 38 | } 39 | 40 | public PlayerCard getCard(int slot) { 41 | if (slot < 0 || slot >= DECK_CARDS_COUNT) { 42 | throw new IllegalArgumentException("slot"); 43 | } 44 | 45 | return cards[slot]; 46 | } 47 | 48 | public void swapCards(int slot1, int slot2) { 49 | changed = true; 50 | 51 | if (slot1 < 0 || slot1 >= DECK_CARDS_COUNT) { 52 | throw new IllegalArgumentException("slot1"); 53 | } 54 | 55 | if (slot2 < 0 || slot2 >= DECK_CARDS_COUNT) { 56 | throw new IllegalArgumentException("slot2"); 57 | } 58 | 59 | PlayerCard temp = cards[slot1]; 60 | cards[slot1] = cards[slot2]; 61 | cards[slot2] = temp; 62 | } 63 | 64 | public PlayerCard swapCard(int slot, PlayerCard targetCard) { 65 | changed = true; 66 | 67 | if (slot < 0 || slot >= DECK_CARDS_COUNT) { 68 | throw new IllegalArgumentException("slot"); 69 | } 70 | 71 | if (targetCard == null) { 72 | throw new IllegalArgumentException("targetCard"); 73 | } 74 | 75 | PlayerCard result = cards[slot]; 76 | cards[slot] = targetCard; 77 | return result; 78 | } 79 | 80 | public PlayerDeckCardEntity getEntity(int slot) { 81 | if (slot < 0 || slot >= DECK_CARDS_COUNT) { 82 | throw new IllegalArgumentException("slot"); 83 | } 84 | 85 | return entities[slot]; 86 | } 87 | 88 | public void setEntity(int slot, PlayerDeckCardEntity entity) { 89 | if (slot < 0 || slot >= DECK_CARDS_COUNT) { 90 | throw new IllegalArgumentException("slot"); 91 | } 92 | 93 | entities[slot] = entity; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/game/OpeningChest.java: -------------------------------------------------------------------------------- 1 | package royaleserver.game; 2 | 3 | import royaleserver.logic.Card; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.Comparator; 8 | import java.util.List; 9 | 10 | public class OpeningChest { 11 | public static class CardStack { 12 | public final Card card; 13 | public final int count; 14 | 15 | public CardStack(Card card, int count) { 16 | this.card = card; 17 | this.count = count; 18 | } 19 | } 20 | 21 | public static class Builder { 22 | private final int optionSize; 23 | 24 | private final List cards = new ArrayList<>(); 25 | private int gold = 0; 26 | private int gems = 0; 27 | 28 | private Builder(int optionSize) { 29 | this.optionSize = optionSize; 30 | } 31 | 32 | public int optionSize() { 33 | return optionSize; 34 | } 35 | 36 | public Builder add(CardStack[] option) { 37 | if (option.length != optionSize) { 38 | throw new RuntimeException("Option length is not right."); 39 | } 40 | 41 | cards.add(option); 42 | return this; 43 | } 44 | 45 | public Builder gold(int gold) { 46 | this.gold = gold; 47 | return this; 48 | } 49 | 50 | public Builder gems(int gems) { 51 | this.gems = gems; 52 | return this; 53 | } 54 | 55 | public OpeningChest build() { 56 | cards.sort(Comparator.comparingInt(a -> a[0].card.getRarity().getSortCapacity() * a[0].count)); 57 | return new OpeningChest(cards, gold, gems); 58 | } 59 | } 60 | 61 | private final List cards; 62 | private final List selectedCards; 63 | private final int gold, gems; 64 | private int currentCard = 0; 65 | 66 | private OpeningChest(List cards, int gold, int gems) { 67 | this.cards = Collections.unmodifiableList(cards); 68 | this.selectedCards = new ArrayList<>(cards.size()); 69 | this.gold = gold; 70 | this.gems = gems; 71 | } 72 | 73 | public int optionSize() { 74 | return cards.size() == 0 ? 0 : cards.get(0).length; 75 | } 76 | 77 | public List cards() { 78 | return cards; 79 | } 80 | 81 | public List selectedCards() { 82 | return selectedCards; 83 | } 84 | 85 | public int gold() { 86 | return gold; 87 | } 88 | 89 | public int gems() { 90 | return gems; 91 | } 92 | 93 | public CardStack next(int selection) { 94 | CardStack card = null; 95 | if (hasCards()) { 96 | this.selectedCards.add(currentCard, card = cards.get(currentCard)[selection >= optionSize() ? 0 : selection]); 97 | ++currentCard; 98 | } 99 | 100 | return card; 101 | } 102 | 103 | public boolean hasCards() { 104 | return currentCard < cards.size(); 105 | } 106 | 107 | public void end() { 108 | while (next(0) != null); 109 | } 110 | 111 | public static Builder builder(boolean draft) { 112 | return new Builder(draft ? 2 : 1); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/game/PlayerCard.java: -------------------------------------------------------------------------------- 1 | package royaleserver.game; 2 | 3 | import royaleserver.logic.Card; 4 | import royaleserver.database.entity.PlayerCardEntity; 5 | 6 | public final class PlayerCard { 7 | private Card card; 8 | private int level; 9 | private int count; 10 | 11 | private PlayerCardEntity entity; 12 | 13 | public PlayerCard(Card card, int level, int count) { 14 | this(card, level, count, null); 15 | } 16 | 17 | public PlayerCard(Card card, int level, int count, PlayerCardEntity entity) { 18 | this.card = card; 19 | this.level = level; 20 | this.count = count; 21 | this.entity = entity; 22 | } 23 | 24 | public Card getCard() { 25 | return card; 26 | } 27 | 28 | public int getLevel() { 29 | return level; 30 | } 31 | 32 | public PlayerCard setLevel(int level) { 33 | this.level = level; 34 | return this; 35 | } 36 | 37 | public int getCount() { 38 | return count; 39 | } 40 | 41 | public PlayerCard setCount(int count) { 42 | this.count = count; 43 | return this; 44 | } 45 | 46 | public PlayerCard addCount(int count) { 47 | this.count += count; 48 | return this; 49 | } 50 | 51 | public PlayerCardEntity getEntity() { 52 | return entity; 53 | } 54 | 55 | public void setEntity(PlayerCardEntity entity) { 56 | this.entity = entity; 57 | } 58 | 59 | @Override 60 | public boolean equals(Object o) { 61 | if (this == o) { 62 | return true; 63 | } 64 | if (!(o instanceof PlayerCard)) { 65 | return false; 66 | } 67 | 68 | PlayerCard that = (PlayerCard)o; 69 | 70 | return card.equals(that.card); 71 | } 72 | 73 | @Override 74 | public int hashCode() { 75 | return card.hashCode(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/logic/ClanBadge.java: -------------------------------------------------------------------------------- 1 | package royaleserver.logic; 2 | 3 | import royaleserver.Server; 4 | import royaleserver.ServerException; 5 | import royaleserver.csv.Column; 6 | import royaleserver.csv.Row; 7 | import royaleserver.csv.Table; 8 | import royaleserver.database.entity.ClanBadgeEntity; 9 | import royaleserver.utils.SCID; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | public final class ClanBadge extends DBLogic { 15 | public static final int SCID_HIGH = 16; 16 | 17 | private SCID scid; 18 | 19 | private ClanBadge() {} 20 | 21 | public SCID getScid() { 22 | return scid; 23 | } 24 | 25 | 26 | private static boolean initialized = false; 27 | private static List values = new ArrayList<>(); 28 | 29 | public static void init(Server server) throws ServerException { 30 | if (initialized) { 31 | return; 32 | } 33 | 34 | Table csv_badges = server.getAssetManager().open("csv_logic/alliance_badges.csv").csv(); 35 | Column csv_Name = csv_badges.getColumn("Name"); 36 | 37 | int i = 0; 38 | for (Row csv_badge : csv_badges.getRows()) { 39 | ClanBadge badge = new ClanBadge(); 40 | 41 | badge.scid = new SCID(SCID_HIGH, i++); 42 | badge.name = csv_badge.getValue(csv_Name).asString(); 43 | 44 | values.add(badge); 45 | } 46 | 47 | init(values, server.getDataManager().getClanBadgeService()); 48 | 49 | initialized = true; 50 | } 51 | 52 | public static ClanBadge by(String name) { 53 | for (ClanBadge badge : values) { 54 | if (badge.name.equals(name)) { 55 | return badge; 56 | } 57 | } 58 | 59 | return null; 60 | } 61 | 62 | public static ClanBadge by(SCID scid) { 63 | for (ClanBadge badge : values) { 64 | if (badge.scid.equals(scid)) { 65 | return badge; 66 | } 67 | } 68 | 69 | return null; 70 | } 71 | 72 | public static ClanBadge byDB(long id) { 73 | for (ClanBadge badge : values) { 74 | if (badge.dbId == id) { 75 | return badge; 76 | } 77 | } 78 | 79 | return null; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/logic/DBLogic.java: -------------------------------------------------------------------------------- 1 | package royaleserver.logic; 2 | 3 | import royaleserver.database.entity.LogicEntity; 4 | import royaleserver.database.service.LogicService; 5 | 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | public abstract class DBLogic extends NamedLogic { 11 | protected long dbId; 12 | protected Entity dbEntity; 13 | 14 | public final long getDbId() { 15 | return dbId; 16 | } 17 | 18 | public final Entity getDbEntity() { 19 | return dbEntity; 20 | } 21 | 22 | protected static < 23 | Logic extends DBLogic, 24 | Entity extends LogicEntity, 25 | Service extends LogicService 26 | > void init(List values, Service service) { 27 | final Map entities = new HashMap<>(); 28 | final HashMap entitiesToAdd = new HashMap<>(); 29 | for (Entity entity : service.all()) { 30 | entities.put(entity.getName(), entity); 31 | } 32 | 33 | for (Logic logic : values) { 34 | LogicEntity entity = entities.getOrDefault(logic.getName(), null); 35 | if (entity == null) { 36 | entitiesToAdd.put(logic.getName(), null); 37 | } else { 38 | logic.dbId = entity.getId(); 39 | logic.dbEntity = entity; 40 | } 41 | } 42 | 43 | if (entitiesToAdd.size() > 0) { 44 | service.store(entitiesToAdd); 45 | for (Map.Entry entry : entitiesToAdd.entrySet()) { 46 | for (Logic logic : values) { 47 | if (logic.name.equals(entry.getKey())) { 48 | logic.dbEntity = entry.getValue(); 49 | logic.dbId = logic.dbEntity.getId(); 50 | break; 51 | } 52 | } 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/logic/ExpLevel.java: -------------------------------------------------------------------------------- 1 | package royaleserver.logic; 2 | 3 | import royaleserver.Server; 4 | import royaleserver.ServerException; 5 | import royaleserver.csv.Column; 6 | import royaleserver.csv.Row; 7 | import royaleserver.csv.Table; 8 | import royaleserver.database.entity.ExpLevelEntity; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public final class ExpLevel extends DBLogic { 14 | private int index; 15 | private int numericName; 16 | private int expToNextLevel; 17 | private int totalExp; 18 | 19 | private ExpLevel() {} 20 | 21 | public int getIndex() { 22 | return index; 23 | } 24 | 25 | public int getNumericName() { 26 | return numericName; 27 | } 28 | 29 | public int getExpToNextLevel() { 30 | return expToNextLevel; 31 | } 32 | 33 | public int getTotalExp() { 34 | return totalExp; 35 | } 36 | 37 | private static boolean initialized = false; 38 | private static List values = new ArrayList<>(); 39 | 40 | public static void init(Server server) throws ServerException { 41 | if (initialized) { 42 | return; 43 | } 44 | 45 | Table csv_levels = server.getAssetManager().open("csv_logic/exp_levels.csv").csv(); 46 | Column csv_Name = csv_levels.getColumn("Name"); 47 | Column csv_ExpToNextLevel = csv_levels.getColumn("ExpToNextLevel"); 48 | 49 | int i = 1, totalExp = 0; 50 | for (Row csv_level : csv_levels.getRows()) { 51 | ExpLevel expLevel = new ExpLevel(); 52 | 53 | expLevel.index = i++; 54 | expLevel.name = String.valueOf(expLevel.numericName = csv_level.getValue(csv_Name).asInt()); 55 | expLevel.expToNextLevel = csv_level.getValue(csv_ExpToNextLevel).asInt(); 56 | expLevel.totalExp = totalExp; 57 | totalExp += expLevel.expToNextLevel; 58 | 59 | values.add(expLevel); 60 | } 61 | 62 | init(values, server.getDataManager().getExpLevelService()); 63 | 64 | initialized = true; 65 | } 66 | 67 | public static ExpLevel by(int name) { 68 | for (ExpLevel expLevel : values) { 69 | if (expLevel.numericName == name) { 70 | return expLevel; 71 | } 72 | } 73 | 74 | return null; 75 | } 76 | 77 | public static ExpLevel byIndex(int index) { 78 | for (ExpLevel expLevel : values) { 79 | if (expLevel.index == index) { 80 | return expLevel; 81 | } 82 | } 83 | 84 | return null; 85 | } 86 | 87 | public static ExpLevel byDB(long id) { 88 | for (ExpLevel expLevel : values) { 89 | if (expLevel.dbId == id) { 90 | return expLevel; 91 | } 92 | } 93 | 94 | return null; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/logic/Logic.java: -------------------------------------------------------------------------------- 1 | package royaleserver.logic; 2 | 3 | public abstract class Logic { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/logic/NamedLogic.java: -------------------------------------------------------------------------------- 1 | package royaleserver.logic; 2 | 3 | public abstract class NamedLogic extends Logic { 4 | protected String name; 5 | 6 | public String getName() { 7 | return name; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/NetworkServer.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioServerSocketChannel; 9 | import royaleserver.Server; 10 | import royaleserver.config.Config; 11 | import royaleserver.network.protocol.client.ClientCommandFactory; 12 | import royaleserver.network.protocol.client.ClientMessageFactory; 13 | import royaleserver.network.protocol.server.ServerCommandFactory; 14 | import royaleserver.network.protocol.server.ServerMessageFactory; 15 | import royaleserver.utils.Hex; 16 | import royaleserver.utils.LogManager; 17 | import royaleserver.utils.Logger; 18 | 19 | public final class NetworkServer { 20 | private static final Logger logger = LogManager.getLogger(NetworkServer.class); 21 | public static final byte[] SERVER_KEY = Hex.toByteArray("9e6657f2b419c237f6aeef37088690a642010586a7bd9018a15652bab8370f4f"); 22 | public static final byte[] SESSION_KEY = Hex.toByteArray("74794DE40D62A03AC6F6E86A9815C6262AA12BEDD518F883"); 23 | 24 | private final Server server; 25 | private EventLoopGroup bossGroup; 26 | private EventLoopGroup workerGroup; 27 | private Channel channel; 28 | 29 | private final boolean requireLoginCode; 30 | 31 | public NetworkServer(Server server, Config config) { 32 | this.server = server; 33 | 34 | requireLoginCode = config.get("server.require_login_code").getAsBoolean(); 35 | 36 | ClientCommandFactory.instance.init(); 37 | ClientMessageFactory.instance.init(); 38 | ServerCommandFactory.instance.init(); 39 | ServerMessageFactory.instance.init(); 40 | } 41 | 42 | public void start() { 43 | bossGroup = new NioEventLoopGroup(); 44 | workerGroup = new NioEventLoopGroup(); 45 | 46 | ServerBootstrap bootstrap = new ServerBootstrap(); 47 | bootstrap 48 | .group(bossGroup, workerGroup) 49 | .channel(NioServerSocketChannel.class) 50 | .option(ChannelOption.SO_BACKLOG, 1024) 51 | .childOption(ChannelOption.SO_KEEPALIVE, true) 52 | .childHandler(new PlayerInitializer(this)); 53 | 54 | try { 55 | channel = bootstrap.bind(server.getConfig().get("server.port").getAsShort()).sync().channel(); 56 | } catch (InterruptedException e) { 57 | e.printStackTrace(); 58 | } 59 | } 60 | 61 | public void stop() { 62 | } 63 | 64 | public void close() { 65 | try { 66 | channel.closeFuture().sync(); 67 | } catch (InterruptedException e) { 68 | e.printStackTrace(); 69 | } 70 | 71 | bossGroup.shutdownGracefully(); 72 | workerGroup.shutdownGracefully(); 73 | } 74 | 75 | public Server getServer() { 76 | return server; 77 | } 78 | 79 | public boolean isRequireLoginCode() { 80 | return requireLoginCode; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/NetworkSessionHandler.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network; 2 | 3 | import royaleserver.network.protocol.Message; 4 | 5 | public interface NetworkSessionHandler { 6 | void sendMessage(Message message); 7 | void replace(NetworkSession newSession); 8 | void close(); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/PacketDecoder.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.ByteToMessageDecoder; 6 | import royaleserver.crypto.ServerCrypto; 7 | import royaleserver.network.protocol.MessageHeader; 8 | import royaleserver.network.protocol.Messages; 9 | import royaleserver.network.protocol.client.ClientMessage; 10 | import royaleserver.network.protocol.client.ClientMessageFactory; 11 | import royaleserver.utils.DataStream; 12 | import royaleserver.utils.Hex; 13 | import royaleserver.utils.LogManager; 14 | import royaleserver.utils.Logger; 15 | 16 | import java.util.List; 17 | 18 | public class PacketDecoder extends ByteToMessageDecoder { 19 | private static final Logger logger = LogManager.getLogger(PacketDecoder.class); 20 | 21 | private final ServerCrypto crypto; 22 | 23 | private boolean hasHeader = false; 24 | private final MessageHeader header = new MessageHeader(); 25 | 26 | public PacketDecoder(ServerCrypto crypto) { 27 | this.crypto = crypto; 28 | } 29 | 30 | @Override 31 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { 32 | if (!hasHeader) { 33 | if (in.readableBytes() >= 7) { 34 | short id = in.readShort(); 35 | int payloadLength = in.readMedium(); 36 | short version = in.readShort(); 37 | 38 | hasHeader = true; 39 | header.id = id; 40 | header.payload = new byte[payloadLength]; 41 | } 42 | } else { 43 | if (in.readableBytes() >= header.payload.length) { 44 | in.readBytes(header.payload); 45 | hasHeader = false; 46 | 47 | crypto.decryptPacket(header); 48 | 49 | ClientMessage message = processPacket(); 50 | if (message != null) { 51 | out.add(message); 52 | } 53 | } 54 | } 55 | } 56 | 57 | private ClientMessage processPacket() { 58 | ClientMessage message = ClientMessageFactory.instance.create(header.id); 59 | 60 | if (header.decrypted == null) { 61 | logger.error("Failed to decrypt packet %d, encrypted payload:\n%s", header.id, Hex.dump(header.payload)); 62 | return null; 63 | } 64 | 65 | if (message == null) { 66 | String name = null; 67 | if (Messages.messagesMap.containsKey(header.id)) { 68 | name = Messages.messagesMap.get(header.id); 69 | } 70 | 71 | if (name == null) { 72 | logger.warn("Received unknown packet %d:\n%s", header.id, Hex.dump(header.decrypted)); 73 | } else { 74 | logger.warn("Received undefined packet %s:\n%s", name, Hex.dump(header.decrypted)); 75 | } 76 | 77 | return null; 78 | } 79 | 80 | try { 81 | DataStream dataStream = new DataStream(header.decrypted); 82 | message.decode(dataStream); 83 | 84 | // Messages must be decoded fully, because it can contain useful information, so we will try to decode it fully 85 | if (!dataStream.eof()) { 86 | logger.warn("Message %s is not decoded fully.\n\tDecoded part:\n%s\n\tOther part:\n%s", 87 | message.getClass().getSimpleName(), 88 | Hex.dump(header.decrypted, 0, dataStream.getOffset()), 89 | Hex.dump(header.decrypted, dataStream.getOffset(), header.decrypted.length - dataStream.getOffset())); 90 | } 91 | } catch (Exception e) { 92 | logger.error("Failed to decode packet %s, payload:\n%s", message.getClass().getSimpleName(), 93 | Hex.dump(header.decrypted)); 94 | return null; 95 | } 96 | 97 | return message; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/PacketEncoder.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.MessageToByteEncoder; 6 | import royaleserver.crypto.ServerCrypto; 7 | import royaleserver.network.protocol.MessageHeader; 8 | import royaleserver.network.protocol.server.ServerMessage; 9 | import royaleserver.utils.DataStream; 10 | 11 | public class PacketEncoder extends MessageToByteEncoder { 12 | private final ServerCrypto crypto; 13 | 14 | private final DataStream stream = new DataStream(); 15 | private final MessageHeader header = new MessageHeader(); 16 | 17 | public PacketEncoder(ServerCrypto crypto) { 18 | this.crypto = crypto; 19 | } 20 | 21 | @Override 22 | protected void encode(ChannelHandlerContext context, ServerMessage message, ByteBuf out) throws Exception { 23 | message.encode(stream); 24 | 25 | header.id = message.id; 26 | header.decrypted = stream.getBuffer(); 27 | stream.reset(true); 28 | crypto.encryptPacket(header); 29 | 30 | out.writeShort(message.id); 31 | out.writeMedium(header.payload.length); 32 | out.writeShort((short)5); 33 | 34 | out.writeBytes(header.payload); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/PlayerInitializer.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import royaleserver.crypto.ClientCrypto; 7 | import royaleserver.crypto.ServerCrypto; 8 | 9 | public class PlayerInitializer extends ChannelInitializer { 10 | private final NetworkServer server; 11 | 12 | public PlayerInitializer(NetworkServer server) { 13 | this.server = server; 14 | } 15 | 16 | @Override 17 | public void initChannel(SocketChannel channel) throws Exception { 18 | ClientCrypto clientCrypto = new ClientCrypto(NetworkServer.SERVER_KEY); 19 | ServerCrypto serverCrypto = new ServerCrypto(); 20 | 21 | clientCrypto.setServer(serverCrypto); 22 | serverCrypto.setClient(clientCrypto); 23 | 24 | ChannelPipeline pipeline = channel.pipeline(); 25 | pipeline.addLast(new PacketDecoder(serverCrypto)); 26 | pipeline.addLast(new PacketEncoder(serverCrypto)); 27 | pipeline.addLast(new PlayerHandler(server)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/UnhandledMessageException.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network; 2 | 3 | import royaleserver.network.protocol.Message; 4 | 5 | public final class UnhandledMessageException extends RuntimeException { 6 | public UnhandledMessageException(Message message) { 7 | super("The handler do not handle message " + message.getClass().getSimpleName() + "."); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/Command.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol; 2 | 3 | public abstract class Command { 4 | public final short id; 5 | 6 | protected Command(short id) { 7 | this.id = id; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/Commands.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Modifier; 5 | import java.util.Collections; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | public final class Commands { 10 | private Commands() {} 11 | 12 | // Server commands 13 | public static final short NAME_SET = 201; 14 | public static final short CLAN_LEAVE_OK = 205; 15 | public static final short CLAN_CREATE_OK = 206; 16 | public static final short CHEST_OPEN_OK = 210; 17 | 18 | // Client commands 19 | public static final short DECK_CHANGE_CARD = 500; 20 | public static final short DECK_CHANGE = 501; 21 | public static final short CHEST_OPEN = 503; 22 | public static final short CARD_UPGRADE = 504; 23 | public static final short CHEST_BUY = 516; 24 | public static final short FIGHT_START = 525; 25 | public static final short CHEST_CARD_NEXT = 526; 26 | public static final short CHALLENGE_BUY = 537; 27 | public static final short CHEST_DRAFT_CARD_SELECT = 553; 28 | public static final short CHEST_SEASON_REWARD_OPEN = 556; 29 | 30 | 31 | public static final Map commandsMap = createMap(); 32 | 33 | private static Map createMap() { 34 | Map map = new HashMap<>(); 35 | 36 | for (Field field : Commands.class.getFields()) { 37 | int modifiers = field.getModifiers(); 38 | if (Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers) && field.getType() == short.class) { 39 | try { 40 | map.put(field.getShort(null), field.getName()); 41 | } catch (IllegalAccessException e) { 42 | e.printStackTrace(); 43 | } 44 | } 45 | } 46 | 47 | return Collections.unmodifiableMap(map); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/Factory.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol; 2 | 3 | import org.reflections.Reflections; 4 | import royaleserver.utils.LogManager; 5 | import royaleserver.utils.Logger; 6 | 7 | import java.lang.reflect.Modifier; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | public abstract class Factory { 12 | private static final Logger logger = LogManager.getLogger(Factory.class); 13 | 14 | private final String packagePrefix; 15 | private final Class targetClass; 16 | 17 | private final Map> creators = new HashMap<>(); 18 | private boolean initialized = false; 19 | 20 | protected Factory(String packagePrefix, Class targetClass) { 21 | this.packagePrefix = packagePrefix; 22 | this.targetClass = targetClass; 23 | } 24 | 25 | public final void init() { 26 | if (initialized) { 27 | return; 28 | } 29 | initialized = true; 30 | 31 | for (Class clazz : new Reflections(packagePrefix).getSubTypesOf(targetClass)) { 32 | int modifiers = clazz.getModifiers(); 33 | 34 | if (Modifier.isAbstract(modifiers)) { 35 | continue; 36 | } 37 | 38 | try { 39 | KeyType key = (KeyType)clazz.getDeclaredField("ID").get(null); 40 | FactoryTarget value = null; 41 | try { 42 | value = clazz.newInstance(); 43 | } catch (InstantiationException | IllegalAccessException e) { 44 | logger.error("Cannot create object of %s.", e, clazz.getName()); 45 | continue; 46 | } 47 | 48 | if (!clazz.equals(value.create().getClass())) { 49 | logger.fatal("Class %s has bad FactoryTarget.create.", clazz.getName()); 50 | } 51 | 52 | creators.put(key, value); 53 | } catch (IllegalAccessException | NoSuchFieldException e) { 54 | logger.error("Class %s must have static field ID.", e, clazz.getName()); 55 | } 56 | } 57 | } 58 | 59 | public final TargetClass create(KeyType key) { 60 | FactoryTarget creator = creators.getOrDefault(key, null); 61 | return creator == null ? null : creator.create(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/FactoryTarget.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol; 2 | 3 | public interface FactoryTarget { 4 | Target create(); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/Handler.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol; 2 | 3 | public interface Handler { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/Message.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol; 2 | 3 | public abstract class Message { 4 | public final short id; 5 | 6 | protected Message(short id) { 7 | this.id = id; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/MessageHeader.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol; 2 | 3 | public final class MessageHeader { 4 | public short id; 5 | public byte[] payload; 6 | public byte[] decrypted; 7 | 8 | public MessageHeader() {} 9 | 10 | public MessageHeader(short id, byte[] bytes) { 11 | this.id = id; 12 | payload = bytes; 13 | } 14 | 15 | public byte[] toBuffer() { 16 | return payload; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/ClientCommand.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client; 2 | 3 | import royaleserver.network.protocol.*; 4 | 5 | import royaleserver.utils.DataStream; 6 | 7 | public abstract class ClientCommand extends Command implements FactoryTarget { 8 | public ClientCommand(short id) { 9 | super(id); 10 | } 11 | 12 | public abstract void decode(DataStream stream); 13 | public abstract boolean handle(ClientCommandHandler handler) throws Throwable; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/ClientCommandFactory.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client; 2 | 3 | import royaleserver.network.protocol.Factory; 4 | 5 | public final class ClientCommandFactory extends Factory { 6 | public static final ClientCommandFactory instance = new ClientCommandFactory(); 7 | 8 | private ClientCommandFactory() { 9 | super("royaleserver.network.protocol.client.commands", ClientCommand.class); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/ClientCommandHandler.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client; 2 | 3 | import royaleserver.network.protocol.client.commands.*; 4 | 5 | public interface ClientCommandHandler { 6 | boolean handleCardUpgrade(CardUpgrade command) throws Throwable; 7 | boolean handleChallengeBuy(ChallengeBuy command) throws Throwable; 8 | boolean handleChestBuy(ChestBuy command) throws Throwable; 9 | boolean handleChestCardNext(ChestCardNext command) throws Throwable; 10 | boolean handleChestDraftCardSelect(ChestDraftCardSelect command) throws Throwable; 11 | boolean handleChestOpen(ChestOpen command) throws Throwable; 12 | boolean handleChestSeasonRewardOpen(ChestSeasonRewardOpen command) throws Throwable; 13 | boolean handleDeckChange(DeckChange command) throws Throwable; 14 | boolean handleDeckChangeCard(DeckChangeCard command) throws Throwable; 15 | boolean handleFightStart(FightStart command) throws Throwable; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/ClientMessage.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client; 2 | 3 | import royaleserver.network.protocol.*; 4 | 5 | import royaleserver.utils.DataStream; 6 | 7 | public abstract class ClientMessage extends Message implements FactoryTarget { 8 | protected ClientMessage(short id) { 9 | super(id); 10 | } 11 | 12 | public abstract void decode(DataStream stream); 13 | public abstract boolean handle(ClientMessageHandler handler) throws Throwable; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/ClientMessageFactory.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client; 2 | 3 | import royaleserver.network.protocol.Factory; 4 | 5 | public final class ClientMessageFactory extends Factory { 6 | public static final ClientMessageFactory instance = new ClientMessageFactory(); 7 | 8 | private ClientMessageFactory() { 9 | super("royaleserver.network.protocol.client.messages", ClientMessage.class); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/ClientMessageHandler.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client; 2 | 3 | import royaleserver.network.protocol.Handler; 4 | import royaleserver.network.protocol.client.messages.*; 5 | 6 | public interface ClientMessageHandler extends Handler { 7 | boolean handleAccountUnlock(AccountUnlock message) throws Throwable; 8 | boolean handleClanAskData(ClanAskData message) throws Throwable; 9 | boolean handleClanAskJoinable(ClanAskJoinable message) throws Throwable; 10 | boolean handleClanChatMessage(ClanChatMessage message) throws Throwable; 11 | boolean handleClanCreate(ClanCreate message) throws Throwable; 12 | boolean handleClanJoin(ClanJoin message) throws Throwable; 13 | boolean handleClanLeave(ClanLeave message) throws Throwable; 14 | boolean handleClanSearch(ClanSearch message) throws Throwable; 15 | boolean handleClientCommands(ClientCommands message) throws Throwable; 16 | boolean handleClientHello(ClientHello message) throws Throwable; 17 | boolean handleConnectionInfo(ConnectionInfo message) throws Throwable; 18 | boolean handleHomeAskData(HomeAskData message) throws Throwable; 19 | boolean handleHomeAskDataOwn(HomeAskDataOwn message) throws Throwable; 20 | boolean handleInboxAsk(InboxAsk message) throws Throwable; 21 | boolean handleLogin(Login message) throws Throwable; 22 | boolean handleMatchmakeCancel(MatchmakeCancel message) throws Throwable; 23 | boolean handleMatchmakeStart(MatchmakeStart message) throws Throwable; 24 | boolean handleNameChange(NameChange message) throws Throwable; 25 | boolean handleNameCheck(NameCheck message) throws Throwable; 26 | boolean handlePing(Ping message) throws Throwable; 27 | boolean handleTournamentAskJoinable(TournamentAskJoinable message) throws Throwable; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/commands/CardUpgrade.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.commands; 2 | 3 | import royaleserver.network.protocol.Commands; 4 | import royaleserver.network.protocol.client.ClientCommand; 5 | import royaleserver.network.protocol.client.ClientCommandHandler; 6 | import royaleserver.utils.DataStream; 7 | import royaleserver.utils.SCID; 8 | 9 | public final class CardUpgrade extends ClientCommand { 10 | public static final short ID = Commands.CARD_UPGRADE; 11 | 12 | public int tickStart; 13 | public int tickEnd; 14 | 15 | public long accountID; 16 | public SCID cardSCID; 17 | 18 | public CardUpgrade() { 19 | super(ID); 20 | } 21 | 22 | @Override 23 | public ClientCommand create() { 24 | return new CardUpgrade(); 25 | } 26 | 27 | @Override 28 | public boolean handle(ClientCommandHandler handler) throws Throwable { 29 | return handler.handleCardUpgrade(this); 30 | } 31 | 32 | @Override 33 | public void decode(DataStream stream) { 34 | tickStart = stream.getRrsInt32(); 35 | tickEnd = stream.getRrsInt32(); 36 | 37 | accountID = stream.getRrsLong(); 38 | cardSCID = stream.getSCID(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/commands/ChallengeBuy.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.commands; 2 | 3 | import royaleserver.network.protocol.Commands; 4 | import royaleserver.network.protocol.client.ClientCommand; 5 | import royaleserver.network.protocol.client.ClientCommandHandler; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class ChallengeBuy extends ClientCommand { 9 | public static final short ID = Commands.CHALLENGE_BUY; 10 | 11 | public ChallengeBuy() { 12 | super(ID); 13 | } 14 | 15 | @Override 16 | public ClientCommand create() { 17 | return new ChallengeBuy(); 18 | } 19 | 20 | @Override 21 | public boolean handle(ClientCommandHandler handler) throws Throwable { 22 | return handler.handleChallengeBuy(this); 23 | } 24 | 25 | @Override 26 | public void decode(DataStream stream) { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/commands/ChestBuy.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.commands; 2 | 3 | import royaleserver.logic.Chest; 4 | import royaleserver.network.protocol.Commands; 5 | import royaleserver.network.protocol.client.ClientCommand; 6 | import royaleserver.network.protocol.client.ClientCommandHandler; 7 | import royaleserver.utils.DataStream; 8 | 9 | public final class ChestBuy extends ClientCommand { 10 | public static final short ID = Commands.CHEST_BUY; 11 | 12 | public int tickStart; 13 | public int tickEnd; 14 | public long accountId; 15 | 16 | public byte unknown_3; 17 | public Chest chest; 18 | 19 | public ChestBuy() { 20 | super(ID); 21 | } 22 | 23 | @Override 24 | public ClientCommand create() { 25 | return new ChestBuy(); 26 | } 27 | 28 | @Override 29 | public boolean handle(ClientCommandHandler handler) throws Throwable { 30 | return handler.handleChestBuy(this); 31 | } 32 | 33 | @Override 34 | public void decode(DataStream stream) { 35 | tickStart = stream.getRrsInt32(); 36 | tickEnd = stream.getRrsInt32(); 37 | 38 | accountId = stream.getRrsLong(); 39 | unknown_3 = stream.getByte(); 40 | 41 | chest = Chest.by(stream.getRrsInt32()); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/commands/ChestCardNext.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.commands; 2 | 3 | import royaleserver.network.protocol.Commands; 4 | import royaleserver.network.protocol.client.ClientCommand; 5 | import royaleserver.network.protocol.client.ClientCommandHandler; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class ChestCardNext extends ClientCommand { 9 | public static final short ID = Commands.CHEST_CARD_NEXT; 10 | 11 | public ChestCardNext() { 12 | super(ID); 13 | } 14 | 15 | @Override 16 | public ClientCommand create() { 17 | return new ChestCardNext(); 18 | } 19 | 20 | @Override 21 | public boolean handle(ClientCommandHandler handler) throws Throwable { 22 | return handler.handleChestCardNext(this); 23 | } 24 | 25 | @Override 26 | public void decode(DataStream stream) { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/commands/ChestDraftCardSelect.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.commands; 2 | 3 | import royaleserver.network.protocol.Commands; 4 | import royaleserver.network.protocol.client.ClientCommand; 5 | import royaleserver.network.protocol.client.ClientCommandHandler; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class ChestDraftCardSelect extends ClientCommand { 9 | public static final short ID = Commands.CHEST_DRAFT_CARD_SELECT; 10 | 11 | public int tickStart; 12 | public int tickEnd; 13 | 14 | public int unknown_2, unknown_3; 15 | 16 | public int selection; 17 | 18 | public ChestDraftCardSelect() { 19 | super(ID); 20 | } 21 | 22 | @Override 23 | public ClientCommand create() { 24 | return new ChestDraftCardSelect(); 25 | } 26 | 27 | @Override 28 | public boolean handle(ClientCommandHandler handler) throws Throwable { 29 | return handler.handleChestDraftCardSelect(this); 30 | } 31 | 32 | @Override 33 | public void decode(DataStream stream) { 34 | tickStart = stream.getRrsInt32(); 35 | tickEnd = stream.getRrsInt32(); 36 | 37 | unknown_2 = stream.getRrsInt32(); // Always 00 38 | unknown_3 = stream.getRrsInt32(); // Always 01 39 | 40 | selection = stream.getRrsInt32(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/commands/ChestOpen.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.commands; 2 | 3 | import royaleserver.network.protocol.Commands; 4 | import royaleserver.network.protocol.client.ClientCommand; 5 | import royaleserver.network.protocol.client.ClientCommandHandler; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class ChestOpen extends ClientCommand { 9 | public static final short ID = Commands.CHEST_OPEN; 10 | 11 | public int tickStart; 12 | public int tickEnd; 13 | 14 | public int unknown_0; 15 | public int unknown_1; 16 | 17 | public int slot; 18 | 19 | public ChestOpen() { 20 | super(ID); 21 | } 22 | 23 | @Override 24 | public ClientCommand create() { 25 | return new ChestOpen(); 26 | } 27 | 28 | @Override 29 | public boolean handle(ClientCommandHandler handler) throws Throwable { 30 | return handler.handleChestOpen(this); 31 | } 32 | 33 | @Override 34 | public void decode(DataStream stream) { 35 | tickStart = stream.getRrsInt32(); 36 | tickEnd = stream.getRrsInt32(); 37 | 38 | unknown_0 = stream.getRrsInt32(); 39 | unknown_1 = stream.getRrsInt32(); 40 | 41 | slot = stream.getRrsInt32(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/commands/ChestSeasonRewardOpen.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.commands; 2 | 3 | import royaleserver.network.protocol.Commands; 4 | import royaleserver.network.protocol.client.ClientCommand; 5 | import royaleserver.network.protocol.client.ClientCommandHandler; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class ChestSeasonRewardOpen extends ClientCommand { 9 | public static final short ID = Commands.CHEST_SEASON_REWARD_OPEN; 10 | 11 | public ChestSeasonRewardOpen() { 12 | super(ID); 13 | } 14 | 15 | @Override 16 | public ClientCommand create() { 17 | return new ChestSeasonRewardOpen(); 18 | } 19 | 20 | @Override 21 | public boolean handle(ClientCommandHandler handler) throws Throwable { 22 | return handler.handleChestSeasonRewardOpen(this); 23 | } 24 | 25 | @Override 26 | public void decode(DataStream stream) { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/commands/DeckChange.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.commands; 2 | 3 | import royaleserver.network.protocol.Commands; 4 | import royaleserver.network.protocol.client.ClientCommand; 5 | import royaleserver.network.protocol.client.ClientCommandHandler; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class DeckChange extends ClientCommand { 9 | public static final short ID = Commands.DECK_CHANGE; 10 | 11 | public int tickStart; 12 | public int tickEnd; 13 | 14 | public int unknown_2; 15 | public int unknown_3; 16 | 17 | public int slot; 18 | 19 | public DeckChange() { 20 | super(ID); 21 | } 22 | 23 | @Override 24 | public ClientCommand create() { 25 | return new DeckChange(); 26 | } 27 | 28 | @Override 29 | public boolean handle(ClientCommandHandler handler) throws Throwable { 30 | return handler.handleDeckChange(this); 31 | } 32 | 33 | @Override 34 | public void decode(DataStream stream) { 35 | tickStart = stream.getRrsInt32(); 36 | tickEnd = stream.getRrsInt32(); 37 | 38 | unknown_2 = stream.getRrsInt32(); 39 | unknown_3 = stream.getRrsInt32(); 40 | 41 | slot = stream.getRrsInt32(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/commands/DeckChangeCard.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.commands; 2 | 3 | import royaleserver.network.protocol.Commands; 4 | import royaleserver.network.protocol.client.ClientCommand; 5 | import royaleserver.network.protocol.client.ClientCommandHandler; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class DeckChangeCard extends ClientCommand { 9 | public static final short ID = Commands.DECK_CHANGE_CARD; 10 | 11 | public int tickStart; 12 | public int tickEnd; 13 | 14 | public long accountId; 15 | public int cardIndex; 16 | public int slot; 17 | public int slot2; 18 | 19 | public DeckChangeCard() { 20 | super(ID); 21 | } 22 | 23 | @Override 24 | public ClientCommand create() { 25 | return new DeckChangeCard(); 26 | } 27 | 28 | @Override 29 | public boolean handle(ClientCommandHandler handler) throws Throwable { 30 | return handler.handleDeckChangeCard(this); 31 | } 32 | 33 | @Override 34 | public void decode(DataStream stream) { 35 | tickStart = stream.getRrsInt32(); 36 | tickEnd = stream.getRrsInt32(); 37 | 38 | accountId = stream.getRrsLong(); 39 | cardIndex = stream.getRrsInt32(); 40 | slot = stream.getRrsInt32(); 41 | slot2 = stream.getRrsInt32(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/commands/FightStart.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.commands; 2 | 3 | import royaleserver.network.protocol.Commands; 4 | import royaleserver.network.protocol.client.ClientCommand; 5 | import royaleserver.network.protocol.client.ClientCommandHandler; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class FightStart extends ClientCommand { 9 | public static final short ID = Commands.FIGHT_START; 10 | 11 | public FightStart() { 12 | super(ID); 13 | } 14 | 15 | @Override 16 | public ClientCommand create() { 17 | return new FightStart(); 18 | } 19 | 20 | @Override 21 | public boolean handle(ClientCommandHandler handler) throws Throwable { 22 | return handler.handleFightStart(this); 23 | } 24 | 25 | @Override 26 | public void decode(DataStream stream) { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/AccountUnlock.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.Messages; 4 | import royaleserver.network.protocol.client.ClientMessage; 5 | import royaleserver.network.protocol.client.ClientMessageHandler; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class AccountUnlock extends ClientMessage { 9 | public static final short ID = Messages.ACCOUNT_UNLOCK; 10 | 11 | public int unknown_0; 12 | public int unknown_1; 13 | 14 | public String deviceToken; 15 | public String unlockCode; 16 | 17 | public AccountUnlock() { 18 | super(ID); 19 | } 20 | 21 | @Override 22 | public ClientMessage create() { 23 | return new AccountUnlock(); 24 | } 25 | 26 | @Override 27 | public boolean handle(ClientMessageHandler handler) throws Throwable { 28 | return handler.handleAccountUnlock(this); 29 | } 30 | 31 | @Override 32 | public void decode(DataStream stream) { 33 | unknown_0 = stream.getBInt(); 34 | unknown_1 = stream.getBInt(); 35 | 36 | deviceToken = stream.getString(); 37 | unlockCode = stream.getString(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/ClanAskData.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class ClanAskData extends ClientMessage { 9 | public static final short ID = Messages.CLAN_ASK_DATA; 10 | 11 | public long clanId; 12 | 13 | public ClanAskData() { 14 | super(ID); 15 | } 16 | 17 | @Override 18 | public ClientMessage create() { 19 | return new ClanAskData(); 20 | } 21 | 22 | @Override 23 | public boolean handle(ClientMessageHandler handler) throws Throwable { 24 | return handler.handleClanAskData(this); 25 | } 26 | 27 | @Override 28 | public void decode(DataStream stream) { 29 | clanId = stream.getBLong(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/ClanAskJoinable.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class ClanAskJoinable extends ClientMessage { 9 | public static final short ID = Messages.CLAN_ASK_JOINABLE; 10 | 11 | public ClanAskJoinable() { 12 | super(ID); 13 | } 14 | 15 | @Override 16 | public ClientMessage create() { 17 | return new ClanAskJoinable(); 18 | } 19 | 20 | @Override 21 | public boolean handle(ClientMessageHandler handler) throws Throwable { 22 | return handler.handleClanAskJoinable(this); 23 | } 24 | 25 | @Override 26 | public void decode(DataStream stream) { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/ClanChatMessage.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class ClanChatMessage extends ClientMessage { 9 | public static final short ID = Messages.CLAN_CHAT_MESSAGE; 10 | 11 | public String message; 12 | 13 | public ClanChatMessage() { 14 | super(ID); 15 | } 16 | 17 | @Override 18 | public ClientMessage create() { 19 | return new ClanChatMessage(); 20 | } 21 | 22 | @Override 23 | public boolean handle(ClientMessageHandler handler) throws Throwable { 24 | return handler.handleClanChatMessage(this); 25 | } 26 | 27 | @Override 28 | public void decode(DataStream stream) { 29 | message = stream.getString(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/ClanCreate.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | import royaleserver.utils.SCID; 8 | 9 | public final class ClanCreate extends ClientMessage { 10 | public static final short ID = Messages.CLAN_CREATE; 11 | 12 | public static final int TYPE_OPEN = 1; 13 | public static final int TYPE_INVITE = 2; 14 | public static final int TYPE_CLOSED = 3; 15 | 16 | public String name; 17 | public String description; 18 | public SCID badge; 19 | public int type; 20 | public int minTrophies; 21 | public SCID location; 22 | 23 | public ClanCreate() { 24 | super(ID); 25 | } 26 | 27 | @Override 28 | public ClientMessage create() { 29 | return new ClanCreate(); 30 | } 31 | 32 | @Override 33 | public boolean handle(ClientMessageHandler handler) throws Throwable { 34 | return handler.handleClanCreate(this); 35 | } 36 | 37 | @Override 38 | public void decode(DataStream stream) { 39 | name = stream.getString(); 40 | description = stream.getString(); 41 | badge = stream.getSCID(); 42 | type = stream.getRrsInt32(); 43 | minTrophies = stream.getRrsInt32(); 44 | location = stream.getSCID(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/ClanJoin.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.Messages; 4 | import royaleserver.network.protocol.client.ClientMessage; 5 | import royaleserver.network.protocol.client.ClientMessageHandler; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class ClanJoin extends ClientMessage { 9 | public static final short ID = Messages.CLAN_JOIN; 10 | 11 | public long clanId; 12 | public byte unknown_1; 13 | public byte unknown_2; 14 | public byte unknown_3; 15 | public byte unknown_4; 16 | 17 | public ClanJoin() { 18 | super(ID); 19 | } 20 | 21 | @Override 22 | public ClientMessage create() { 23 | return new ClanJoin(); 24 | } 25 | 26 | @Override 27 | public boolean handle(ClientMessageHandler handler) throws Throwable { 28 | return handler.handleClanJoin(this); 29 | } 30 | 31 | @Override 32 | public void decode(DataStream stream) { 33 | clanId = stream.getBLong(); 34 | unknown_1 = stream.getByte(); 35 | unknown_2 = stream.getByte(); 36 | unknown_3 = stream.getByte(); 37 | unknown_4 = stream.getByte(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/ClanLeave.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class ClanLeave extends ClientMessage { 9 | public static final short ID = Messages.CLAN_LEAVE; 10 | 11 | public ClanLeave() { 12 | super(ID); 13 | } 14 | 15 | @Override 16 | public ClientMessage create() { 17 | return new ClanLeave(); 18 | } 19 | 20 | @Override 21 | public boolean handle(ClientMessageHandler handler) throws Throwable { 22 | return handler.handleClanLeave(this); 23 | } 24 | 25 | @Override 26 | public void decode(DataStream stream) { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/ClanSearch.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | import royaleserver.utils.SCID; 9 | 10 | public final class ClanSearch extends ClientMessage { 11 | public static final short ID = Messages.CLAN_SEARCH; 12 | 13 | public String searchString; 14 | public SCID desiredRegion; 15 | public int minMembers; 16 | public int maxMembers; 17 | public int minTrophies; 18 | public boolean findOnlyJoinableClans; 19 | public int unknown_6; 20 | public int unknown_7; 21 | 22 | public ClanSearch() { 23 | super(ID); 24 | } 25 | 26 | @Override 27 | public ClientMessage create() { 28 | return new ClanSearch(); 29 | } 30 | 31 | @Override 32 | public boolean handle(ClientMessageHandler handler) throws Throwable { 33 | return handler.handleClanSearch(this); 34 | } 35 | 36 | @Override 37 | public void decode(DataStream stream) { 38 | searchString = stream.getString(); 39 | desiredRegion = stream.getSCID(); 40 | minMembers = stream.getBInt(); 41 | maxMembers = stream.getBInt(); 42 | minTrophies = stream.getBInt(); 43 | findOnlyJoinableClans = stream.getBoolean(); 44 | unknown_6 = stream.getBInt(); 45 | unknown_7 = stream.getBInt(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/ClientCommands.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.Messages; 4 | import royaleserver.network.protocol.client.ClientCommand; 5 | import royaleserver.network.protocol.client.ClientCommandFactory; 6 | import royaleserver.network.protocol.client.ClientMessage; 7 | import royaleserver.network.protocol.client.ClientMessageHandler; 8 | import royaleserver.utils.DataStream; 9 | import royaleserver.utils.Hex; 10 | import royaleserver.utils.LogManager; 11 | import royaleserver.utils.Logger; 12 | 13 | public final class ClientCommands extends ClientMessage { 14 | public static final Logger logger = LogManager.getLogger(ClientCommands.class); 15 | 16 | public static final short ID = Messages.CLIENT_COMMANDS; 17 | 18 | public int tick; 19 | public int checksum; 20 | public ClientCommand[] commands; 21 | 22 | public ClientCommands() { 23 | super(ID); 24 | } 25 | 26 | @Override 27 | public ClientMessage create() { 28 | return new ClientCommands(); 29 | } 30 | 31 | @Override 32 | public boolean handle(ClientMessageHandler handler) throws Throwable { 33 | return handler.handleClientCommands(this); 34 | } 35 | 36 | @Override 37 | public void decode(DataStream stream) { 38 | tick = stream.getRrsInt32(); 39 | checksum = stream.getRrsInt32(); 40 | 41 | commands = new ClientCommand[stream.getRrsInt32()]; 42 | for (int i = 0; i < commands.length; i++) { 43 | short commandId = (short)stream.getRrsInt32(); 44 | ClientCommand command = ClientCommandFactory.instance.create(commandId); 45 | 46 | if (command == null) { 47 | logger.warn("Unknown command %d.", commandId); 48 | 49 | break; 50 | } 51 | 52 | command.decode(stream); 53 | commands[i] = command; 54 | } 55 | 56 | if (stream.remaining() > 4) { 57 | byte[] remaining = stream.get(stream.remaining() - 4); 58 | logger.warn("Commands is not decoded fully. Not decoded content:\n%s", Hex.dump(remaining)); 59 | } 60 | 61 | if (stream.remaining() == 4) { 62 | stream.skip(4); // Always 0xFFFFFFFF 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/ClientHello.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class ClientHello extends ClientMessage { 9 | public static final short ID = Messages.CLIENT_HELLO; 10 | 11 | public int protocol; 12 | public int keyVersion; 13 | public int majorVersion; 14 | public int minorVersion; 15 | public int build; 16 | public String contentHash; 17 | public int deviceType; 18 | public int appStore; 19 | 20 | public ClientHello() { 21 | super(ID); 22 | } 23 | 24 | @Override 25 | public ClientMessage create() { 26 | return new ClientHello(); 27 | } 28 | 29 | @Override 30 | public boolean handle(ClientMessageHandler handler) throws Throwable { 31 | return handler.handleClientHello(this); 32 | } 33 | 34 | @Override 35 | public void decode(DataStream stream) { 36 | protocol = stream.getBInt(); 37 | keyVersion = stream.getBInt(); 38 | majorVersion = stream.getBInt(); 39 | minorVersion = stream.getBInt(); 40 | build = stream.getBInt(); 41 | contentHash = stream.getString(); 42 | deviceType = stream.getBInt(); 43 | appStore = stream.getBInt(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/ConnectionInfo.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class ConnectionInfo extends ClientMessage { 9 | public static final short ID = Messages.CONNECTION_INFO; 10 | 11 | public int ping; 12 | public String connectionInterface; 13 | 14 | public ConnectionInfo() { 15 | super(ID); 16 | } 17 | 18 | @Override 19 | public ClientMessage create() { 20 | return new ConnectionInfo(); 21 | } 22 | 23 | @Override 24 | public boolean handle(ClientMessageHandler handler) throws Throwable { 25 | return handler.handleConnectionInfo(this); 26 | } 27 | 28 | @Override 29 | public void decode(DataStream stream) { 30 | ping = stream.getRrsInt32(); 31 | connectionInterface = stream.getString(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/HomeAskData.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class HomeAskData extends ClientMessage { 9 | public static final short ID = Messages.HOME_ASK_DATA; 10 | 11 | public long accountId; 12 | 13 | public HomeAskData() { 14 | super(ID); 15 | } 16 | 17 | @Override 18 | public ClientMessage create() { 19 | return new HomeAskData(); 20 | } 21 | 22 | @Override 23 | public boolean handle(ClientMessageHandler handler) throws Throwable { 24 | return handler.handleHomeAskData(this); 25 | } 26 | 27 | @Override 28 | public void decode(DataStream stream) { 29 | accountId = stream.getBLong(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/HomeAskDataOwn.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class HomeAskDataOwn extends ClientMessage { 9 | public static final short ID = Messages.HOME_ASK_DATA_OWN; 10 | 11 | public HomeAskDataOwn() { 12 | super(ID); 13 | } 14 | 15 | @Override 16 | public ClientMessage create() { 17 | return new HomeAskDataOwn(); 18 | } 19 | 20 | @Override 21 | public boolean handle(ClientMessageHandler handler) throws Throwable { 22 | return handler.handleHomeAskDataOwn(this); 23 | } 24 | 25 | @Override 26 | public void decode(DataStream stream) { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/InboxAsk.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class InboxAsk extends ClientMessage { 9 | public static final short ID = Messages.INBOX_ASK; 10 | 11 | public InboxAsk() { 12 | super(ID); 13 | } 14 | 15 | @Override 16 | public ClientMessage create() { 17 | return new InboxAsk(); 18 | } 19 | 20 | @Override 21 | public boolean handle(ClientMessageHandler handler) throws Throwable { 22 | return handler.handleInboxAsk(this); 23 | } 24 | 25 | @Override 26 | public void decode(DataStream stream) { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/Login.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class Login extends ClientMessage { 9 | public static final short ID = Messages.LOGIN; 10 | 11 | public long accountId; 12 | public String passToken; 13 | public int clientMajorVersion; 14 | public int clientMinorVersion; 15 | public int clientBuild; 16 | public String resourceSha; 17 | public String UDID; 18 | public String openUdid; 19 | public String macAddress; 20 | public String device; 21 | public String advertisingGuid; 22 | public String osVersion; 23 | public byte isAndroid; 24 | public String unknown_13; 25 | public String androidID; 26 | public String preferredDeviceLanguage; 27 | public byte unknown_16; 28 | public byte preferredLanguage; 29 | public String facebookAttributionId; 30 | public byte advertisingEnabled; 31 | public String appleIFV; 32 | public int appStore; 33 | public String kunlunSSO; 34 | public String kunlunUID; 35 | public String unknown_24; 36 | public String unknown_25; 37 | public byte unknown_26; 38 | 39 | public Login() { 40 | super(ID); 41 | } 42 | 43 | @Override 44 | public ClientMessage create() { 45 | return new Login(); 46 | } 47 | 48 | @Override 49 | public boolean handle(ClientMessageHandler handler) throws Throwable { 50 | return handler.handleLogin(this); 51 | } 52 | 53 | @Override 54 | public void decode(DataStream stream) { 55 | accountId = stream.getBLong(); 56 | passToken = stream.getString(); 57 | clientMajorVersion = stream.getRrsInt32(); 58 | clientMinorVersion = stream.getRrsInt32(); 59 | clientBuild = stream.getRrsInt32(); 60 | resourceSha = stream.getString(); 61 | UDID = stream.getString(); 62 | openUdid = stream.getString(); 63 | macAddress = stream.getString(); 64 | device = stream.getString(); 65 | advertisingGuid = stream.getString(); 66 | osVersion = stream.getString(); 67 | isAndroid = stream.getByte(); 68 | unknown_13 = stream.getString(); 69 | androidID = stream.getString(); 70 | preferredDeviceLanguage = stream.getString(); 71 | unknown_16 = stream.getByte(); 72 | preferredLanguage = stream.getByte(); 73 | facebookAttributionId = stream.getString(); 74 | advertisingEnabled = stream.getByte(); 75 | appleIFV = stream.getString(); 76 | appStore = stream.getRrsInt32(); 77 | kunlunSSO = stream.getString(); 78 | kunlunUID = stream.getString(); 79 | unknown_24 = stream.getString(); 80 | unknown_25 = stream.getString(); 81 | unknown_26 = stream.getByte(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/MatchmakeCancel.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class MatchmakeCancel extends ClientMessage { 9 | public static final short ID = Messages.MATCHMAKE_CANCEL; 10 | 11 | public MatchmakeCancel() { 12 | super(ID); 13 | } 14 | 15 | @Override 16 | public ClientMessage create() { 17 | return new MatchmakeCancel(); 18 | } 19 | 20 | @Override 21 | public boolean handle(ClientMessageHandler handler) throws Throwable { 22 | return handler.handleMatchmakeCancel(this); 23 | } 24 | 25 | @Override 26 | public void decode(DataStream stream) { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/MatchmakeStart.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class MatchmakeStart extends ClientMessage { 9 | public static final short ID = Messages.MATCHMAKE_START; 10 | 11 | public MatchmakeStart() { 12 | super(ID); 13 | } 14 | 15 | @Override 16 | public ClientMessage create() { 17 | return new MatchmakeStart(); 18 | } 19 | 20 | @Override 21 | public boolean handle(ClientMessageHandler handler) throws Throwable { 22 | return handler.handleMatchmakeStart(this); 23 | } 24 | 25 | @Override 26 | public void decode(DataStream stream) { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/NameChange.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class NameChange extends ClientMessage { 9 | public static final short ID = Messages.NAME_CHANGE; 10 | 11 | public String name; 12 | 13 | public NameChange() { 14 | super(ID); 15 | } 16 | 17 | @Override 18 | public ClientMessage create() { 19 | return new NameChange(); 20 | } 21 | 22 | @Override 23 | public boolean handle(ClientMessageHandler handler) throws Throwable { 24 | return handler.handleNameChange(this); 25 | } 26 | 27 | @Override 28 | public void decode(DataStream stream) { 29 | name = stream.getString(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/NameCheck.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class NameCheck extends ClientMessage { 9 | public static final short ID = Messages.NAME_CHECK; 10 | 11 | public String name; 12 | 13 | public NameCheck() { 14 | super(ID); 15 | } 16 | 17 | @Override 18 | public ClientMessage create() { 19 | return new NameCheck(); 20 | } 21 | 22 | @Override 23 | public boolean handle(ClientMessageHandler handler) throws Throwable { 24 | return handler.handleNameCheck(this); 25 | } 26 | 27 | @Override 28 | public void decode(DataStream stream) { 29 | name = stream.getString(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/Ping.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class Ping extends ClientMessage { 9 | public static final short ID = Messages.PING; 10 | 11 | public Ping() { 12 | super(ID); 13 | } 14 | 15 | @Override 16 | public ClientMessage create() { 17 | return new Ping(); 18 | } 19 | 20 | @Override 21 | public boolean handle(ClientMessageHandler handler) throws Throwable { 22 | return handler.handlePing(this); 23 | } 24 | 25 | @Override 26 | public void decode(DataStream stream) { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/client/messages/TournamentAskJoinable.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.client.messages; 2 | 3 | import royaleserver.network.protocol.client.ClientMessage; 4 | import royaleserver.network.protocol.client.ClientMessageHandler; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class TournamentAskJoinable extends ClientMessage { 9 | public static final short ID = Messages.TOURNAMENT_ASK_JOINABLE; 10 | 11 | public TournamentAskJoinable() { 12 | super(ID); 13 | } 14 | 15 | @Override 16 | public ClientMessage create() { 17 | return new TournamentAskJoinable(); 18 | } 19 | 20 | @Override 21 | public boolean handle(ClientMessageHandler handler) throws Throwable { 22 | return handler.handleTournamentAskJoinable(this); 23 | } 24 | 25 | @Override 26 | public void decode(DataStream stream) { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/ServerCommand.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server; 2 | 3 | import royaleserver.network.protocol.*; 4 | 5 | import royaleserver.utils.DataStream; 6 | 7 | public abstract class ServerCommand extends Command implements FactoryTarget { 8 | public ServerCommand(short id) { 9 | super(id); 10 | } 11 | 12 | public abstract void encode(DataStream stream); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/ServerCommandFactory.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server; 2 | 3 | import royaleserver.network.protocol.Factory; 4 | import royaleserver.network.protocol.client.ClientCommand; 5 | 6 | public final class ServerCommandFactory extends Factory { 7 | public static final ServerCommandFactory instance = new ServerCommandFactory(); 8 | 9 | private ServerCommandFactory() { 10 | super("royaleserver.network.protocol.server.commands", ServerCommand.class); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/ServerMessage.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server; 2 | 3 | import royaleserver.network.protocol.*; 4 | 5 | import royaleserver.utils.DataStream; 6 | 7 | public abstract class ServerMessage extends Message implements FactoryTarget { 8 | protected ServerMessage(short id) { 9 | super(id); 10 | } 11 | 12 | public abstract void encode(DataStream stream); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/ServerMessageFactory.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server; 2 | 3 | import royaleserver.network.protocol.Factory; 4 | import royaleserver.network.protocol.client.ClientMessage; 5 | 6 | public final class ServerMessageFactory extends Factory { 7 | public static final ServerMessageFactory instance = new ServerMessageFactory(); 8 | 9 | private ServerMessageFactory() { 10 | super("royaleserver.network.protocol.client.messages", ServerMessage.class); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/commands/ChestOpenOk.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.commands; 2 | 3 | import royaleserver.network.protocol.Commands; 4 | import royaleserver.network.protocol.server.ServerCommand; 5 | import royaleserver.network.protocol.server.components.ChestItem; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class ChestOpenOk extends ServerCommand { 9 | public static final short ID = Commands.CHEST_OPEN_OK; 10 | 11 | public int gold; 12 | public int gems; 13 | public ChestItem[] items; 14 | public int chestId; 15 | 16 | public byte unknown_7; 17 | public byte unknown_8; 18 | 19 | public boolean isDraft; 20 | 21 | public ChestOpenOk() { 22 | super(ID); 23 | } 24 | 25 | @Override 26 | public ServerCommand create() { 27 | return new ChestOpenOk(); 28 | } 29 | 30 | @Override 31 | public void encode(DataStream stream) { 32 | stream.putByte((byte)1); 33 | stream.putBoolean(isDraft); 34 | 35 | stream.putRrsInt32(items.length); 36 | for (ChestItem chestItem : items) { 37 | chestItem.encode(stream); 38 | } 39 | 40 | stream.putByte((byte)127); 41 | 42 | stream.putRrsInt32(gold); 43 | stream.putRrsInt32(gems); 44 | 45 | stream.putRrsInt32(chestId); 46 | 47 | if (isDraft) { 48 | stream.putRrsInt32(0); 49 | stream.putRrsInt32(0); 50 | stream.putRrsInt32(0); 51 | stream.putRrsInt32(0); 52 | stream.putRrsInt32(5787); 53 | stream.putRrsInt32(10); 54 | 55 | stream.putRrsInt32(-64); 56 | stream.putRrsInt32(-64); 57 | } 58 | 59 | stream.putByte(unknown_7); 60 | stream.putByte(unknown_8); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/commands/ClanCreateOk.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.commands; 2 | 3 | import royaleserver.network.protocol.Commands; 4 | import royaleserver.network.protocol.server.ServerCommand; 5 | import royaleserver.utils.DataStream; 6 | import royaleserver.utils.SCID; 7 | 8 | public final class ClanCreateOk extends ServerCommand { 9 | public static final short ID = Commands.CLAN_CREATE_OK; 10 | 11 | public long clanId; 12 | public String name; 13 | public SCID badge; 14 | public byte unknown_3; 15 | public byte accepted; 16 | 17 | public ClanCreateOk() { 18 | super(ID); 19 | } 20 | 21 | @Override 22 | public ServerCommand create() { 23 | return new ClanCreateOk(); 24 | } 25 | 26 | @Override 27 | public void encode(DataStream stream) { 28 | stream.putBLong(clanId); 29 | stream.putString(name); 30 | stream.putSCID(badge); 31 | stream.putByte(unknown_3); 32 | stream.putByte(accepted); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/commands/ClanLeaveOk.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.commands; 2 | 3 | import royaleserver.network.protocol.Commands; 4 | import royaleserver.network.protocol.server.ServerCommand; 5 | import royaleserver.utils.DataStream; 6 | 7 | public final class ClanLeaveOk extends ServerCommand { 8 | public static final short ID = Commands.CLAN_LEAVE_OK; 9 | 10 | public long clanId; 11 | 12 | public ClanLeaveOk() { 13 | super(ID); 14 | } 15 | 16 | @Override 17 | public ServerCommand create() { 18 | return new ClanLeaveOk(); 19 | } 20 | 21 | @Override 22 | public void encode(DataStream stream) { 23 | stream.putBLong(clanId); 24 | 25 | stream.putRrsInt32(0); 26 | stream.putRrsInt32(4); 27 | 28 | stream.putByte((byte)127); 29 | stream.putByte((byte)127); 30 | 31 | stream.putRrsInt32(0); 32 | stream.putRrsInt32(0); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/commands/NameSet.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.commands; 2 | 3 | import royaleserver.network.protocol.Commands; 4 | import royaleserver.network.protocol.server.ServerCommand; 5 | import royaleserver.utils.DataStream; 6 | 7 | public final class NameSet extends ServerCommand { 8 | public static final short ID = Commands.NAME_SET; 9 | 10 | public String name; 11 | 12 | public NameSet() { 13 | super(ID); 14 | } 15 | 16 | @Override 17 | public ServerCommand create() { 18 | return new NameSet(); 19 | } 20 | 21 | @Override 22 | public void encode(DataStream stream) { 23 | stream.putString(name); 24 | 25 | stream.putRrsInt32(0); 26 | stream.putRrsInt32(0); 27 | stream.putRrsInt32(0); 28 | 29 | stream.putRrsInt32(1); 30 | stream.putRrsInt32(1); 31 | stream.putRrsInt32(1); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/components/Card.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.components; 2 | 3 | import royaleserver.utils.DataStream; 4 | 5 | public class Card { 6 | public static final int LABEL_NONE = 0; 7 | public static final int LABEL_UPGRADABLE = 1; 8 | public static final int LABEL_NEW = 2; 9 | 10 | public royaleserver.logic.Card card; 11 | public int level; 12 | public int count; 13 | public int label; 14 | public int boughtTimes; // in shop 15 | public int unknown_2; 16 | public int unknown_3; 17 | 18 | public void encode(DataStream stream) { 19 | stream.putRrsInt32(card == null ? 1 : card.getIndex()); // If 0 then crash 20 | stream.putRrsInt32(level - 1); 21 | stream.putRrsInt32(boughtTimes); 22 | stream.putRrsInt32(count); 23 | stream.putRrsInt32(unknown_2); 24 | stream.putByte((byte)label); 25 | stream.putRrsInt32(unknown_3); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/components/ChestItem.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.components; 2 | 3 | import royaleserver.logic.Card; 4 | import royaleserver.utils.DataStream; 5 | 6 | public class ChestItem { 7 | public Card card; 8 | public byte unknown_1; 9 | public int unknown_2; 10 | public int count; 11 | public byte unknown_4; 12 | public byte unknown_5; 13 | public byte cardOrder; 14 | 15 | public void encode(DataStream stream) { 16 | stream.putRrsInt32(card.getIndex()); 17 | stream.putByte(unknown_1); 18 | stream.putRrsInt32(unknown_2); 19 | stream.putRrsInt32(count); 20 | stream.putByte(unknown_4); 21 | stream.putByte(unknown_5); 22 | stream.putByte(cardOrder); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/components/ClanHeader.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.components; 2 | 3 | import royaleserver.utils.DataStream; 4 | import royaleserver.utils.SCID; 5 | 6 | public class ClanHeader { 7 | public static final byte CLAN_OPEN = 1; 8 | public static final byte CLAN_INVITE = 2; 9 | public static final byte CLAN_CLOSED = 3; 10 | 11 | public long id; 12 | public String name; 13 | public SCID badge; 14 | public byte type; 15 | public int numberOfMembers; 16 | public int score; 17 | public int requiredScore; 18 | public byte unknown_7; 19 | public byte unknown_8; 20 | public int currentRank; 21 | public int unknown_10; 22 | public int donations; 23 | public int unknown_12; 24 | public byte unknown_13; 25 | public byte unknown_14; 26 | public byte unknown_15; 27 | public int region; 28 | public byte unknown_17; 29 | 30 | public void encode(DataStream stream) { 31 | stream.putBLong(id); 32 | stream.putString(name); 33 | stream.putSCID(badge); 34 | stream.putByte(type); 35 | stream.putByte((byte)numberOfMembers); 36 | stream.putRrsInt32(score); 37 | stream.putRrsInt32(requiredScore); 38 | stream.putByte(unknown_7); 39 | stream.putByte(unknown_8); 40 | stream.putRrsInt32(currentRank); 41 | stream.putRrsInt32(unknown_10); 42 | stream.putRrsInt32(donations); 43 | stream.putRrsInt32(unknown_12); 44 | stream.putByte(unknown_13); 45 | stream.putByte(unknown_14); 46 | stream.putByte(unknown_15); 47 | stream.putRrsInt32(region); 48 | stream.putByte(unknown_17); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/components/ClanMember.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.components; 2 | 3 | import royaleserver.utils.DataStream; 4 | import royaleserver.utils.SCID; 5 | 6 | public class ClanMember { 7 | public long avatarId; 8 | public String facebookId; 9 | public String name; 10 | public SCID arena; 11 | public byte role; 12 | public int expLevel; 13 | public int score; 14 | public int donations; 15 | public int unknown_8; 16 | public byte currentRank; 17 | public byte previousRank; 18 | public int clanChestCrowns; 19 | public int unknown_12; 20 | public int unknown_13; 21 | public int unknown_14; 22 | public byte unknown_15; 23 | public byte unknown_16; 24 | public long homeID; 25 | 26 | public void encode(DataStream stream) { 27 | stream.putBLong(avatarId); 28 | stream.putString(facebookId); 29 | stream.putString(name); 30 | stream.putSCID(arena); 31 | stream.putByte(role); 32 | stream.putRrsInt32(expLevel); 33 | stream.putRrsInt32(score); 34 | stream.putRrsInt32(donations); 35 | stream.putVarInt32(unknown_8); 36 | stream.putByte(currentRank); 37 | stream.putByte(previousRank); 38 | stream.putRrsInt32(clanChestCrowns); 39 | stream.putRrsInt32(unknown_12); 40 | stream.putRrsInt32(unknown_13); 41 | stream.putRrsInt32(unknown_14); 42 | stream.putByte(unknown_15); 43 | stream.putByte(unknown_16); 44 | stream.putBLong(homeID); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/components/Deck.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.components; 2 | 3 | import royaleserver.utils.DataStream; 4 | 5 | public class Deck { 6 | public Card cards[]; 7 | 8 | public void encode(DataStream stream) { 9 | if (cards.length != 8) { 10 | throw new RuntimeException("cards.length must be 8"); 11 | } 12 | 13 | for (Card card : cards) { 14 | card.encode(stream); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/components/GameCard.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.components; 2 | 3 | import royaleserver.utils.DataStream; 4 | 5 | public class GameCard { 6 | public int cardId; 7 | public int level; 8 | 9 | public void encode(DataStream stream) { 10 | stream.putRrsInt32(cardId); 11 | stream.putRrsInt32(level - 1); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/components/GameDeck.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.components; 2 | 3 | import royaleserver.utils.DataStream; 4 | 5 | public class GameDeck { 6 | public GameCard cards[]; 7 | 8 | public GameDeck() { 9 | cards = new GameCard[8]; 10 | for (int i = 0; i < 8; ++i) { 11 | cards[i] = new GameCard(); 12 | cards[i].cardId = 1 + i; 13 | cards[i].level = 1; 14 | } 15 | } 16 | 17 | public void encode(DataStream stream) { 18 | if (cards.length != 8) { 19 | throw new RuntimeException("cards.length must be 4"); 20 | } 21 | 22 | for (GameCard card : cards) { 23 | card.encode(stream); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/components/HomeChest.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.components; 2 | 3 | import royaleserver.logic.Chest; 4 | import royaleserver.utils.DataStream; 5 | 6 | public class HomeChest { 7 | public static final byte STATUS_STATIC = 0; 8 | public static final byte STATUS_OPENED = 1; 9 | public static final byte STATUS_OPENING = 8; 10 | 11 | public int offset; 12 | public boolean first; 13 | public int firstOffset; 14 | public int slot; 15 | public Chest chest; 16 | public byte status; 17 | public int ticksToOpen; // Remains ticks to open 18 | 19 | public void encode(DataStream stream) { 20 | stream.putRrsInt32(0); 21 | stream.putRrsInt32(offset); 22 | 23 | if (first) { 24 | stream.putRrsInt32(firstOffset); 25 | } 26 | 27 | stream.putSCID(chest.getScid()); 28 | 29 | stream.putByte(status); 30 | if (status == STATUS_OPENING) { 31 | stream.putRrsInt32(ticksToOpen); 32 | stream.putRrsInt32(chest.getOpenTicks()); 33 | 34 | stream.putRrsInt32((int)System.currentTimeMillis()); 35 | } 36 | 37 | stream.putRrsInt32(5772); // ?? chest id (у пользователя)?? 38 | 39 | stream.putRrsInt32(1); 40 | stream.putRrsInt32(slot); 41 | stream.putRrsInt32(0); 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/components/HomeResources.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.components; 2 | 3 | import royaleserver.utils.DataStream; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | public final class HomeResources { 9 | public static final int RESOURCE_GOLD = 1; 10 | public static final int RESOURCE_CHALLENGE_WINS = 2; // challenge wins (not max!) 11 | public static final int RESOURCE_CHEST_COINT = 3; 12 | public static final int RESOURCE_STAR_COUNT = 4; // ??? 13 | public static final int RESOURCE_FREE_GOLD = 5; // ??? 14 | public static final int RESOURCE_HIGHEST_TROPHIES = 6; 15 | public static final int RESOURCE_THREE_CROWNS_WIN = 7; 16 | public static final int RESOURCE_CARDS_FOUND = 8; 17 | public static final int RESOURCE_FAVOURITE_CARD = 9; // SCID? 18 | public static final int RESOURCE_CARDS_GIVEN = 10; 19 | public static final int RESOURCE_UNK_N11 = 11; 20 | public static final int RESOURCE_UNK_0 = 12; 21 | public static final int RESOURCE_REWARD_GOLD = 13; 22 | public static final int RESOURCE_REWARD_COUNT = 14; 23 | public static final int RESOURCE_UNK_1 = 15; // Wins? 24 | public static final int RESOURCE_CARD_RED_BADGE = 16; // Or SHOP_DAY_COUNT. WHAT? 25 | public static final int RESOURCE_CHALLENGE_CARDS_WON = 17; 26 | public static final int RESOURCE_UNK_2 = 18; 27 | public static final int RESOURCE_UNK_3 = 19; 28 | public static final int RESOURCE_MAX_CHALLENGE_WINS = 20; // Challenge max wins 29 | public static final int RESOURCE_CHALLENGE_CARDS_WON2 = 21; // Repeat? 30 | public static final int RESOURCE_TOURNAMENT_CARDS_WON = 22; 31 | public static final int RESOURCE_UNK_4 = 25; 32 | public static final int RESOURCE_UNK_5 = 26; 33 | public static final int RESOURCE_UNK_N27 = 27; 34 | public static final int RESOURCE_UNK_6 = 28; 35 | public static final int RESOURCE_GAME_MODE = 29; 36 | 37 | public Map resources; 38 | 39 | public HomeResources() { 40 | resources = new HashMap<>(); 41 | } 42 | 43 | public void encode(DataStream stream) { 44 | stream.putRrsInt32(resources.size()); 45 | for (Map.Entry entry : resources.entrySet()) { 46 | stream.putByte((byte)5); 47 | stream.putRrsInt32(entry.getKey()); 48 | stream.putRrsInt32(entry.getValue()); 49 | } 50 | 51 | resources.clear(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/components/PlayerClan.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.components; 2 | 3 | import royaleserver.logic.ClanBadge; 4 | import royaleserver.logic.ClanRole; 5 | import royaleserver.utils.DataStream; 6 | 7 | public final class PlayerClan { 8 | public long id; 9 | public String name; 10 | public ClanBadge badge; 11 | public ClanRole role; 12 | 13 | public void encode(DataStream stream) { 14 | stream.putRrsLong(id); 15 | stream.putString(name); 16 | stream.putRrsInt32(badge.getScid().getLow() + 1); 17 | stream.putRrsInt32(role.getIndex()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/AccountUnlockFailed.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.Messages; 4 | import royaleserver.network.protocol.server.ServerMessage; 5 | import royaleserver.utils.DataStream; 6 | 7 | public final class AccountUnlockFailed extends ServerMessage { 8 | public static final short ID = Messages.ACCOUNT_UNLOCK_FAILED; 9 | 10 | public AccountUnlockFailed() { 11 | super(ID); 12 | } 13 | 14 | @Override 15 | public ServerMessage create() { 16 | return new AccountUnlockFailed(); 17 | } 18 | 19 | @Override 20 | public void encode(DataStream stream) { 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/AccountUnlockOk.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.Messages; 4 | import royaleserver.network.protocol.server.ServerMessage; 5 | import royaleserver.utils.DataStream; 6 | 7 | public final class AccountUnlockOk extends ServerMessage { 8 | public static final short ID = Messages.ACCOUNT_UNLOCK_FAILED; 9 | 10 | public AccountUnlockOk() { 11 | super(ID); 12 | } 13 | 14 | @Override 15 | public ServerMessage create() { 16 | return new AccountUnlockOk(); 17 | } 18 | 19 | @Override 20 | public void encode(DataStream stream) { 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/ClanData.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.Messages; 4 | import royaleserver.network.protocol.server.ServerMessage; 5 | import royaleserver.network.protocol.server.components.ClanHeader; 6 | import royaleserver.network.protocol.server.components.ClanMember; 7 | import royaleserver.utils.DataStream; 8 | 9 | public final class ClanData extends ServerMessage { 10 | public static final short ID = Messages.CLAN_DATA; 11 | 12 | public ClanHeader header; 13 | public String description; 14 | public ClanMember[] members; 15 | public byte unknown_3; 16 | public byte unknown_4; 17 | public int unknown_5; 18 | public int unknown_6; 19 | public int unknown_7; 20 | public int unknown_8; 21 | public int unknown_9; 22 | public byte unknown_10; 23 | public byte unknown_11; 24 | 25 | public ClanData() { 26 | super(ID); 27 | } 28 | 29 | @Override 30 | public ServerMessage create() { 31 | return new ClanData(); 32 | } 33 | 34 | @Override 35 | public void encode(DataStream stream) { 36 | header.encode(stream); 37 | stream.putString(description); 38 | 39 | stream.putRrsInt32(members.length); 40 | for (int i = 0; i < members.length; ++i) { 41 | members[i].encode(stream); 42 | } 43 | 44 | stream.putByte(unknown_3); 45 | stream.putByte(unknown_4); 46 | stream.putRrsInt32(unknown_5); 47 | stream.putRrsInt32(unknown_6); 48 | stream.putBInt(unknown_7); 49 | stream.putBInt(unknown_8); 50 | stream.putRrsInt32(unknown_9); 51 | stream.putByte(unknown_10); 52 | stream.putByte(unknown_11); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/ClanEvent.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.logic.ClanRole; 4 | import royaleserver.logic.ExpLevel; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.network.protocol.server.ServerMessage; 7 | import royaleserver.utils.DataStream; 8 | 9 | public class ClanEvent extends ServerMessage { 10 | public static final short ID = Messages.CLAN_EVENT; 11 | 12 | public static final int EVENT_KICKED = 1; 13 | public static final int EVENT_LEFT = 2; 14 | public static final int EVENT_JOINED = 3; 15 | public static final int EVENT_PROMOTED = 5; 16 | 17 | public long entryId; 18 | public long senderAvatarId; 19 | public long senderAvatarId2; 20 | public String senderName; 21 | public ExpLevel senderLevel; 22 | public ClanRole senderRole; 23 | public int ageSeconds; 24 | public byte isRemoved; 25 | 26 | public int event; 27 | public long initiatorId; 28 | public String initiatorName; 29 | 30 | public ClanEvent() { 31 | super(ID); 32 | } 33 | 34 | @Override 35 | public ServerMessage create() { 36 | return new ClanEvent(); 37 | } 38 | 39 | @Override 40 | public void encode(DataStream stream) { 41 | stream.putRrsInt32(4); 42 | 43 | stream.putRrsLong(entryId); 44 | stream.putRrsLong(senderAvatarId); 45 | stream.putRrsLong(senderAvatarId2); 46 | stream.putString(senderName); 47 | stream.putRrsInt32(senderLevel.getIndex()); 48 | stream.putRrsInt32(senderRole.getIndex()); 49 | stream.putRrsInt32(ageSeconds); 50 | stream.putByte(isRemoved); 51 | 52 | stream.putRrsInt32(event); 53 | stream.putRrsLong(initiatorId); 54 | stream.putString(initiatorName); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/ClanJoinableResponse.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.Messages; 4 | import royaleserver.network.protocol.server.ServerMessage; 5 | import royaleserver.network.protocol.server.components.ClanHeader; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class ClanJoinableResponse extends ServerMessage { 9 | public static final short ID = Messages.CLAN_JOINABLE_RESPONSE; 10 | 11 | public ClanHeader[] clans; 12 | 13 | public ClanJoinableResponse() { 14 | super(ID); 15 | } 16 | 17 | @Override 18 | public ServerMessage create() { 19 | return new ClanJoinableResponse(); 20 | } 21 | 22 | @Override 23 | public void encode(DataStream stream) { 24 | stream.putRrsInt32(clans.length); 25 | 26 | for (int i = 0; i < clans.length; ++i) { 27 | clans[i].encode(stream); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/ClanMemberAdd.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.Messages; 4 | import royaleserver.network.protocol.server.ServerMessage; 5 | import royaleserver.network.protocol.server.components.ClanMember; 6 | import royaleserver.utils.DataStream; 7 | 8 | public class ClanMemberAdd extends ServerMessage { 9 | public static final short ID = Messages.CLAN_MEMBER_ADD; 10 | 11 | public ClanMember member; 12 | 13 | public ClanMemberAdd() { 14 | super(ID); 15 | } 16 | 17 | @Override 18 | public ServerMessage create() { 19 | return new ClanMemberAdd(); 20 | } 21 | 22 | @Override 23 | public void encode(DataStream stream) { 24 | member.encode(stream); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/ClanMemberRemove.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.Messages; 4 | import royaleserver.network.protocol.server.ServerMessage; 5 | import royaleserver.network.protocol.server.components.ClanMember; 6 | import royaleserver.utils.DataStream; 7 | 8 | public class ClanMemberRemove extends ServerMessage { 9 | public static final short ID = Messages.CLAN_MEMBER_REMOVE; 10 | 11 | public ClanMember member; 12 | 13 | public ClanMemberRemove() { 14 | super(ID); 15 | } 16 | 17 | @Override 18 | public ServerMessage create() { 19 | return new ClanMemberRemove(); 20 | } 21 | 22 | @Override 23 | public void encode(DataStream stream) { 24 | member.encode(stream); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/ClanOnlineUpdate.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.Messages; 4 | import royaleserver.network.protocol.server.ServerMessage; 5 | import royaleserver.utils.DataStream; 6 | 7 | public class ClanOnlineUpdate extends ServerMessage { 8 | public static final short ID = Messages.CLAN_ONLINE_UPDATE; 9 | 10 | public int membersOnline; 11 | public int unknown_1; 12 | 13 | public ClanOnlineUpdate() { 14 | super(ID); 15 | } 16 | 17 | @Override 18 | public ServerMessage create() { 19 | return new ClanOnlineUpdate(); 20 | } 21 | 22 | @Override 23 | public void encode(DataStream stream) { 24 | stream.putRrsInt32(membersOnline); 25 | stream.putRrsInt32(unknown_1); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/CommandResponse.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.server.ServerCommand; 4 | import royaleserver.network.protocol.server.ServerMessage; 5 | import royaleserver.network.protocol.Messages; 6 | import royaleserver.utils.DataStream; 7 | 8 | public final class CommandResponse extends ServerMessage { 9 | public static final short ID = Messages.SERVER_COMMAND; 10 | 11 | public ServerCommand command; 12 | public byte unknown_3; 13 | public byte unknown_4; 14 | 15 | public CommandResponse() { 16 | super(ID); 17 | } 18 | 19 | @Override 20 | public ServerMessage create() { 21 | return new CommandResponse(); 22 | } 23 | 24 | @Override 25 | public void encode(DataStream stream) { 26 | stream.putRrsInt32(command.id); 27 | command.encode(stream); 28 | 29 | stream.putByte((byte)127); 30 | stream.putByte((byte)127); 31 | stream.putByte(unknown_3); 32 | stream.putByte(unknown_4); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/Disconnected.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.server.ServerMessage; 4 | import royaleserver.network.protocol.Messages; 5 | import royaleserver.utils.DataStream; 6 | 7 | public final class Disconnected extends ServerMessage { 8 | public static final short ID = Messages.DISCONNECTED; 9 | 10 | public int unknown_0; 11 | 12 | public Disconnected() { 13 | super(ID); 14 | 15 | unknown_0 = 0; 16 | } 17 | 18 | @Override 19 | public ServerMessage create() { 20 | return new Disconnected(); 21 | } 22 | 23 | @Override 24 | public void encode(DataStream stream) { 25 | stream.putRrsInt32(unknown_0); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/HomeDataVisited.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.Messages; 4 | import royaleserver.network.protocol.server.ServerMessage; 5 | import royaleserver.network.protocol.server.components.Deck; 6 | import royaleserver.utils.DataStream; 7 | import royaleserver.utils.Hex; 8 | 9 | public final class HomeDataVisited extends HomeData { 10 | public static final short ID = Messages.HOME_DATA_VISITED; 11 | 12 | public int place; 13 | public Deck deck; 14 | 15 | public HomeDataVisited() { 16 | super(ID); 17 | } 18 | 19 | @Override 20 | public ServerMessage create() { 21 | return new HomeDataVisited(); 22 | } 23 | 24 | @Override 25 | public void encode(DataStream stream) { 26 | stream.putRrsInt32(250); 27 | stream.putRrsInt32(place); 28 | 29 | stream.putByte((byte)0xFF); // It seems that's always before deck 30 | deck.encode(stream); 31 | 32 | stream.putBLong(homeId); 33 | 34 | stream.putByte((byte)0); 35 | stream.putByte((byte)0); 36 | 37 | super.encode(stream); 38 | 39 | // Unknown 40 | stream.putRrsInt32(1); 41 | 42 | // ?Crowns earned => ladder? 43 | stream.putRrsInt32(0); 44 | 45 | // Tutorial Step (06 = setName , 08 = lastDone) 46 | stream.putRrsInt32(8); 47 | 48 | // Tournament? 49 | stream.putRrsInt32(0); 50 | 51 | // Unexplored data 52 | stream.put(Hex.toByteArray("0419bbb1bb0519bbb1bb0519bbb1bb0500000004587365740008ae3480080000000000001f000000000007120501ade8030502b0070503000504000505ade803050cbb0c050d00050e00050fad080510a5030511b2030512a7030513aa030516b70b051998dee2de09051a0d051c00051d8e88d544001e3c001a3c0192e7013c0292e7013c0392e7013c040a3c050a3c060a3c0785013c0885013c0985013c0a013c0b8e0c3c0c8e0c3c0d8e0c3c0e013c0f013c10013c11960b3c120b3c130b3c140b3c15b9013c16b9013c17b9013c180e3c190e3c1a0e3c1b92e7013c1c92e7013c1d92e701173c00013c01013c02013c03013c04013c05013c06013c07013c08013c09013c0a013c0e013c11013c12013c13013c15013c16013c17013c18013c19013c1a013c1b013c1c01090506b13505078a0305088501050988f3df19050a92e701050b1f05140b05158d1b051b0a88011a00001a01001a02001a03001a04001a05001a06001a07001a08001a09001a0a001a0b001a0c001a0d001a0e001a0f001a10001a11001a12001a13001a14001a15001a16001a17001a18001a19001a1a001a1b001a1c001a1d2a1a1e001a1f001a20001a21001a22001a23001a24001a25001a26001a27001a28001a29001a2aab021a2b001a2d001a2e001b00001b01001b02001b03001b04001b05001b06001b07001b08001b09001b0a001c00001c01001c02001c03001c04001c05001c06001c07001c08001c09001c0a001c0b001c0c001c0d001c100900a101a1018689020aa84109009fe0030000000c4241434b20494e2055535352920204b31f8c1b00920d970d019303170000")); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/LoginFailed.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.Messages; 4 | import royaleserver.network.protocol.server.ServerMessage; 5 | import royaleserver.utils.DataStream; 6 | 7 | public final class LoginFailed extends ServerMessage { 8 | public static final short ID = Messages.LOGIN_FAILED; 9 | 10 | public static int ERROR_CODE_REASON_MESSAGE = 3; 11 | public static int ERROR_CODE_NEW_ASSETS = 7; 12 | public static int ERROR_CODE_MAINTENANCE = 10; 13 | public static int ERROR_CODE_BANNED = 11; 14 | public static int ERROR_CODE_ACCOUNT_BLOCKED = 13; 15 | 16 | public int errorCode; 17 | public String resourceFingerprintData; 18 | public String redirectDomain; 19 | public String contentURL; 20 | public String updateURL; 21 | public String reason; 22 | public int secondsUntilMaintenanceEnd; 23 | public byte unknown_7; 24 | public String unknown_8; 25 | 26 | public LoginFailed() { 27 | super(ID); 28 | } 29 | 30 | @Override 31 | public ServerMessage create() { 32 | return new LoginFailed(); 33 | } 34 | 35 | @Override 36 | public void encode(DataStream stream) { 37 | stream.putRrsInt32(errorCode); 38 | stream.putString(resourceFingerprintData); 39 | stream.putString(redirectDomain); 40 | stream.putString(contentURL); 41 | stream.putString(updateURL); 42 | stream.putString(reason); 43 | stream.putRrsInt32(secondsUntilMaintenanceEnd); 44 | stream.putByte(unknown_7); 45 | stream.putString(unknown_8); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/LoginOk.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.server.ServerMessage; 4 | import royaleserver.network.protocol.Messages; 5 | import royaleserver.utils.DataStream; 6 | 7 | public final class LoginOk extends ServerMessage { 8 | public static final short ID = Messages.LOGIN_OK; 9 | 10 | public long userId; 11 | public long homeId; 12 | public String userToken; 13 | public String gameCenterId; 14 | public String facebookId; 15 | public int serverMajorVersion; 16 | public int serverBuild; 17 | public int contentVersion; 18 | public String environment; 19 | public int sessionCount; 20 | public int playTimeSeconds; 21 | public int daysSinceStartedPlaying; 22 | public String facebookAppId; 23 | public String serverTime; 24 | public String accountCreatedDate; 25 | public int unknown_16; 26 | public String googleServiceId; 27 | public String unknown_18; 28 | public String unknown_19; 29 | public String region; 30 | public String contentURL; 31 | public String eventAssetsURL; 32 | public byte unknown_23; 33 | 34 | public LoginOk() { 35 | super(ID); 36 | } 37 | 38 | @Override 39 | public ServerMessage create() { 40 | return new LoginOk(); 41 | } 42 | 43 | @Override 44 | public void encode(DataStream stream) { 45 | stream.putBLong(userId); 46 | stream.putBLong(homeId); 47 | stream.putString(userToken); 48 | stream.putString(gameCenterId); 49 | stream.putString(facebookId); 50 | stream.putRrsInt32(serverMajorVersion); 51 | stream.putRrsInt32(serverBuild); 52 | stream.putRrsInt32(serverBuild); 53 | stream.putRrsInt32(contentVersion); 54 | stream.putString(environment); 55 | stream.putRrsInt32(sessionCount); 56 | stream.putRrsInt32(playTimeSeconds); 57 | stream.putRrsInt32(daysSinceStartedPlaying); 58 | stream.putString(facebookAppId); 59 | stream.putString(serverTime); 60 | stream.putString(accountCreatedDate); 61 | stream.putRrsInt32(unknown_16); 62 | stream.putString(googleServiceId); 63 | stream.putString(unknown_18); 64 | stream.putString(unknown_19); 65 | stream.putString(region); 66 | stream.putString(contentURL); 67 | stream.putString(eventAssetsURL); 68 | stream.putByte(unknown_23); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/MatchmakeCancelOk.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.server.ServerMessage; 4 | import royaleserver.network.protocol.Messages; 5 | import royaleserver.utils.DataStream; 6 | import royaleserver.utils.Hex; 7 | 8 | public final class MatchmakeCancelOk extends ServerMessage { 9 | public static final short ID = Messages.MATCHMAKE_CANCEL_OK; 10 | 11 | public MatchmakeCancelOk() { 12 | super(ID); 13 | } 14 | 15 | @Override 16 | public ServerMessage create() { 17 | return new MatchmakeCancelOk(); 18 | } 19 | 20 | @Override 21 | public void encode(DataStream stream) { 22 | stream.putByte((byte)0x00); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/MatchmakeInfo.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.server.ServerMessage; 4 | import royaleserver.network.protocol.Messages; 5 | import royaleserver.utils.DataStream; 6 | import royaleserver.utils.Hex; 7 | 8 | public final class MatchmakeInfo extends ServerMessage { 9 | public static final short ID = Messages.MATCHMAKE_INFO; 10 | 11 | public MatchmakeInfo() { 12 | super(ID); 13 | } 14 | 15 | @Override 16 | public ServerMessage create() { 17 | return new MatchmakeInfo(); 18 | } 19 | 20 | @Override 21 | public void encode(DataStream stream) { 22 | stream.putBInt(0); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/NameCheckOk.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.Messages; 4 | import royaleserver.network.protocol.server.ServerMessage; 5 | import royaleserver.utils.DataStream; 6 | 7 | public final class NameCheckOk extends ServerMessage { 8 | public static final short ID = Messages.NAME_CHECK_OK; 9 | 10 | public String name; 11 | 12 | public NameCheckOk() { 13 | super(ID); 14 | } 15 | 16 | @Override 17 | public ServerMessage create() { 18 | return new NameCheckOk(); 19 | } 20 | 21 | @Override 22 | public void encode(DataStream stream) { 23 | stream.putString(name); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/Pong.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.server.ServerMessage; 4 | import royaleserver.network.protocol.Messages; 5 | import royaleserver.utils.DataStream; 6 | 7 | public final class Pong extends ServerMessage { 8 | public static final short ID = Messages.PONG; 9 | 10 | public Pong() { 11 | super(ID); 12 | } 13 | 14 | @Override 15 | public ServerMessage create() { 16 | return new Pong(); 17 | } 18 | 19 | @Override 20 | public void encode(DataStream stream) { 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/network/protocol/server/messages/ServerHello.java: -------------------------------------------------------------------------------- 1 | package royaleserver.network.protocol.server.messages; 2 | 3 | import royaleserver.network.protocol.server.ServerMessage; 4 | import royaleserver.network.protocol.Messages; 5 | import royaleserver.utils.DataStream; 6 | 7 | public final class ServerHello extends ServerMessage { 8 | public static final short ID = Messages.SERVER_HELLO; 9 | 10 | public byte[] sessionKey; 11 | 12 | public ServerHello() { 13 | super(ID); 14 | } 15 | 16 | @Override 17 | public ServerMessage create() { 18 | return new ServerHello(); 19 | } 20 | 21 | @Override 22 | public void encode(DataStream stream) { 23 | stream.putByteSet(sessionKey); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/utils/Bitset.java: -------------------------------------------------------------------------------- 1 | package royaleserver.utils; 2 | 3 | public final class Bitset { 4 | private byte value; 5 | 6 | public Bitset() { 7 | this((byte)0); 8 | } 9 | 10 | public Bitset(byte value) { 11 | this.value = value; 12 | } 13 | 14 | public byte get(int index) { 15 | return (byte)((value >> index) & 0x01); 16 | } 17 | 18 | public Bitset set(int index, boolean value) { 19 | if (value) { 20 | this.value |= 1 << index; 21 | } else { 22 | this.value &= ~(1 << index); 23 | } 24 | 25 | return this; 26 | } 27 | 28 | public byte getValue() { 29 | return value; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/utils/CSVConverter.java: -------------------------------------------------------------------------------- 1 | package royaleserver.utils; 2 | 3 | import org.tukaani.xz.LZMAInputStream; 4 | 5 | import java.io.ByteArrayInputStream; 6 | import java.io.ByteArrayOutputStream; 7 | import java.util.Arrays; 8 | 9 | public final class CSVConverter { 10 | private CSVConverter() {} 11 | 12 | public static String decodeCSV(byte[] buffer) { 13 | byte[] tempBuffer = new byte[buffer.length + 4]; 14 | System.arraycopy(buffer, 0, tempBuffer, 0, 9); 15 | Arrays.fill(tempBuffer, 9, 13, (byte)0x00); 16 | System.arraycopy(buffer, 9, tempBuffer, 9 + 4, buffer.length - 9); 17 | 18 | ByteArrayOutputStream os = null; 19 | try { 20 | LZMAInputStream is = new LZMAInputStream(new ByteArrayInputStream(tempBuffer)); 21 | os = new ByteArrayOutputStream(); 22 | 23 | tempBuffer = new byte[256]; 24 | int i; 25 | while ((i = is.read(tempBuffer)) > 0) { 26 | os.write(tempBuffer, 0, i); 27 | } 28 | } catch (Exception ignored) {} 29 | 30 | return os == null ? null : new String(os.toByteArray()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/utils/ChildLogger.java: -------------------------------------------------------------------------------- 1 | package royaleserver.utils; 2 | 3 | public class ChildLogger extends Logger { 4 | private final Logger parent; 5 | 6 | public ChildLogger(Logger parent, String name) { 7 | super(name); 8 | this.parent = parent; 9 | } 10 | 11 | @Override 12 | protected void send(LogLevel level, String name, String message, Object[] format) { 13 | parent.send(level, (parent.name().isEmpty() ? "" : (parent.name() + ".")) + name, message, format); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/utils/GsonUtils.java: -------------------------------------------------------------------------------- 1 | package royaleserver.utils; 2 | 3 | import com.google.gson.JsonElement; 4 | import com.google.gson.JsonObject; 5 | 6 | import java.util.Map; 7 | 8 | // https://stackoverflow.com/a/34092374 9 | public class GsonUtils { 10 | 11 | public static enum ConflictStrategy { 12 | 13 | THROW_EXCEPTION, PREFER_FIRST_OBJ, PREFER_SECOND_OBJ, PREFER_NON_NULL; 14 | } 15 | 16 | public static class JsonObjectExtensionConflictException extends Exception { 17 | 18 | public JsonObjectExtensionConflictException(String message) { 19 | super(message); 20 | } 21 | 22 | } 23 | 24 | public static void extendJsonObject(JsonObject destinationObject, ConflictStrategy conflictResolutionStrategy, JsonObject ... objs) 25 | throws JsonObjectExtensionConflictException { 26 | for (JsonObject obj : objs) { 27 | extendJsonObject(destinationObject, obj, conflictResolutionStrategy); 28 | } 29 | } 30 | 31 | private static void extendJsonObject(JsonObject leftObj, JsonObject rightObj, ConflictStrategy conflictStrategy) 32 | throws JsonObjectExtensionConflictException { 33 | for (Map.Entry rightEntry : rightObj.entrySet()) { 34 | String rightKey = rightEntry.getKey(); 35 | JsonElement rightVal = rightEntry.getValue(); 36 | if (leftObj.has(rightKey)) { 37 | //conflict 38 | JsonElement leftVal = leftObj.get(rightKey); 39 | if (leftVal.isJsonArray() && rightVal.isJsonArray()) { 40 | /*JsonArray leftArr = leftVal.getAsJsonArray(); 41 | JsonArray rightArr = rightVal.getAsJsonArray(); 42 | //concat the arrays -- there cannot be a conflict in an array, it's just a collection of stuff 43 | for (int i = 0; i < rightArr.size(); i++) { 44 | leftArr.add(rightArr.get(i)); 45 | }*/ 46 | handleMergeConflict(rightKey, leftObj, leftVal, rightVal, conflictStrategy); 47 | } else if (leftVal.isJsonObject() && rightVal.isJsonObject()) { 48 | //recursive merging 49 | extendJsonObject(leftVal.getAsJsonObject(), rightVal.getAsJsonObject(), conflictStrategy); 50 | } else {//not both arrays or objects, normal merge with conflict resolution 51 | handleMergeConflict(rightKey, leftObj, leftVal, rightVal, conflictStrategy); 52 | } 53 | } else {//no conflict, add to the object 54 | leftObj.add(rightKey, rightVal); 55 | } 56 | } 57 | } 58 | 59 | private static void handleMergeConflict(String key, JsonObject leftObj, JsonElement leftVal, JsonElement rightVal, ConflictStrategy conflictStrategy) 60 | throws JsonObjectExtensionConflictException { 61 | { 62 | switch (conflictStrategy) { 63 | case PREFER_FIRST_OBJ: 64 | break;//do nothing, the right val gets thrown out 65 | case PREFER_SECOND_OBJ: 66 | leftObj.add(key, rightVal);//right side auto-wins, replace left val with its val 67 | break; 68 | case PREFER_NON_NULL: 69 | //check if right side is not null, and left side is null, in which case we use the right val 70 | if (leftVal.isJsonNull() && !rightVal.isJsonNull()) { 71 | leftObj.add(key, rightVal); 72 | }//else do nothing since either the left value is non-null or the right value is null 73 | break; 74 | case THROW_EXCEPTION: 75 | throw new JsonObjectExtensionConflictException("Key " + key + " exists in both objects and the conflict resolution strategy is " + conflictStrategy); 76 | default: 77 | throw new UnsupportedOperationException("The conflict strategy " + conflictStrategy + " is unknown and cannot be processed"); 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/utils/Hex.java: -------------------------------------------------------------------------------- 1 | package royaleserver.utils; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | public class Hex { 6 | public static final int DUMP_WIDTH = 16; 7 | public static final char[] HEX_SET = "0123456789ABCDEF".toCharArray(); 8 | private static final byte[] PRINTABLE = new byte[] {(byte)0, (byte)0, (byte)0, (byte)0, (byte)255, (byte)255, (byte)255, (byte)255, (byte)255, (byte)255, (byte)255, (byte)127, (byte)255, (byte)255, (byte)255, (byte)127, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0}; 9 | private static final Pattern REMOVE_NOT_HEX_PATTERN = Pattern.compile("[^0-9a-fA-F]"); 10 | 11 | private Hex() {} 12 | 13 | private static boolean isPrintable(char ch) { 14 | int index = (int)ch; 15 | return index <= 255 && ((PRINTABLE[index / 8] >> (index % 8)) & 0x01) == 1; 16 | } 17 | 18 | public static String dump(final byte[] buffer) { 19 | return dump(buffer, 0, buffer.length); 20 | } 21 | 22 | public static String dump(final byte[] buffer, final int offset, final int count) { 23 | final StringBuilder builder = new StringBuilder(); 24 | 25 | final int parts = (int)Math.ceil(((float)count) / DUMP_WIDTH); 26 | final int leftPad = String.valueOf((parts * DUMP_WIDTH) + 1).length(); 27 | int position = offset; 28 | 29 | for (int i = 0; i < parts; ++i) { 30 | builder.append((new String(new char[leftPad - String.valueOf(position).length()])).replace('\0', ' ')); 31 | builder.append(position); 32 | builder.append(": "); 33 | 34 | final int from = position; 35 | final int to = Math.min(position + DUMP_WIDTH, offset + count); 36 | position += DUMP_WIDTH; 37 | 38 | for (int j = from; j < to; ++j) { 39 | builder.append(HEX_SET[(buffer[j] >> 4) & 0xF]); 40 | builder.append(HEX_SET[buffer[j] & 0xF]); 41 | builder.append(" "); 42 | } 43 | 44 | for (int j = 0; j < DUMP_WIDTH - (to - from); ++j) { 45 | builder.append(" "); 46 | } 47 | 48 | builder.append(" "); 49 | 50 | for (int j = from; j < to; ++j) { 51 | char ch = (char)buffer[j]; 52 | 53 | if (isPrintable(ch)) { 54 | builder.append(ch); 55 | } else { 56 | builder.append("."); 57 | } 58 | } 59 | 60 | builder.append("\n"); 61 | } 62 | 63 | return builder.toString(); 64 | } 65 | 66 | public static String toHexString(byte[] buffer) { 67 | return toHexString(buffer, 0, buffer.length); 68 | } 69 | 70 | public static String toHexString(byte[] buffer, int offset, int count) { 71 | StringBuilder sb = new StringBuilder((count - offset) * 2); 72 | for (int i = offset; i < offset + count; ++i) { 73 | sb.append(HEX_SET[(buffer[i] >> 4) & 0xF]); 74 | sb.append(HEX_SET[buffer[i] & 0xF]); 75 | } 76 | return sb.toString(); 77 | } 78 | 79 | public static byte[] toByteArray(String s) { 80 | s = REMOVE_NOT_HEX_PATTERN.matcher(s).replaceAll(""); 81 | 82 | int len = s.length(); 83 | byte[] data = new byte[len / 2]; 84 | 85 | for (int i = 0; i < len; i += 2) { 86 | data[i / 2] = (byte)((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16)); 87 | } 88 | 89 | return data; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/utils/IO.java: -------------------------------------------------------------------------------- 1 | package royaleserver.utils; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.OutputStream; 7 | 8 | public final class IO { 9 | private IO() {} 10 | 11 | public static byte[] getByteArray(InputStream is) { 12 | return getByteArray(is, true); 13 | } 14 | 15 | public static byte[] getByteArray(InputStream is, boolean close) { 16 | try { 17 | ByteArrayOutputStream os = new ByteArrayOutputStream(); 18 | 19 | byte[] buffer = new byte[1024]; 20 | int i; 21 | 22 | while ((i = is.read(buffer)) != -1) { 23 | os.write(buffer, 0, i); 24 | } 25 | 26 | buffer = os.toByteArray(); 27 | os.close(); 28 | 29 | if (close) { 30 | try { 31 | is.close(); 32 | } catch (IOException ignored) {} 33 | } 34 | 35 | return buffer; 36 | } catch (IOException ignored) {} 37 | 38 | return null; 39 | } 40 | 41 | public static void copy(InputStream is, OutputStream os) { 42 | copy(is, os, true); 43 | } 44 | 45 | public static void copy(InputStream is, OutputStream os, boolean close) { 46 | copy(is, os, close, close); 47 | } 48 | 49 | public static void copy(InputStream is, OutputStream os, boolean closeIs, boolean closeOs) { 50 | byte[] temp = new byte[1024]; 51 | int i; 52 | 53 | try { 54 | while ((i = is.read(temp)) > 0) { 55 | os.write(temp, 0, i); 56 | } 57 | } catch (IOException e) { 58 | e.printStackTrace(); 59 | } 60 | 61 | if (closeIs) { 62 | try { 63 | is.close(); 64 | } catch (IOException e) { 65 | e.printStackTrace(); 66 | } 67 | } 68 | 69 | if (closeOs) { 70 | try { 71 | os.close(); 72 | } catch (IOException e) { 73 | e.printStackTrace(); 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/utils/LogLevel.java: -------------------------------------------------------------------------------- 1 | package royaleserver.utils; 2 | 3 | public final class LogLevel { 4 | public static final int WEIGHT_DEBUG = 1; 5 | public static final int WEIGHT_INFO = 2; 6 | public static final int WEIGHT_WARN = 3; 7 | public static final int WEIGHT_ERROR = 4; 8 | public static final int WEIGHT_FATAL = 5; 9 | 10 | public static final LogLevel DEBUG = new LogLevel(WEIGHT_DEBUG, "DEBUG"); 11 | public static final LogLevel INFO = new LogLevel(WEIGHT_INFO, "INFO"); 12 | public static final LogLevel WARN = new LogLevel(WEIGHT_WARN, "WARN"); 13 | public static final LogLevel ERROR = new LogLevel(WEIGHT_ERROR, "ERROR"); 14 | public static final LogLevel FATAL = new LogLevel(WEIGHT_FATAL, "FATAL"); 15 | 16 | private final int levelWeight; 17 | private final String levelName; 18 | 19 | private LogLevel(int weight, String name) { 20 | levelWeight = weight; 21 | levelName = name; 22 | } 23 | 24 | public String name() { 25 | return levelName; 26 | } 27 | 28 | public int weight() { 29 | return levelWeight; 30 | } 31 | 32 | @Override 33 | public boolean equals(Object o) { 34 | return this == o; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return levelName; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/utils/LogManager.java: -------------------------------------------------------------------------------- 1 | package royaleserver.utils; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | 7 | public class LogManager { 8 | private LogManager() {} 9 | 10 | private static final File DEFAULT_LOG_FILE = new File("server.log"); 11 | private static MainLogger mainLogger = null; 12 | 13 | public static Logger getLogger(Class clazz) { 14 | return new ChildLogger(getMainLogger(), clazz.getSimpleName()); 15 | } 16 | 17 | private static MainLogger getMainLogger() { 18 | initMainLogger(); 19 | 20 | return mainLogger; 21 | } 22 | 23 | public static void initMainLogger() { 24 | initMainLogger(DEFAULT_LOG_FILE); 25 | } 26 | 27 | public static void initMainLogger(File file) { 28 | if (mainLogger == null) { 29 | mainLogger = new MainLogger(false); 30 | mainLogger.addHandler(System.out); 31 | 32 | try { 33 | if (!file.exists()) { 34 | file.createNewFile(); 35 | } 36 | 37 | mainLogger.addHandler(new FileOutputStream(file)); 38 | } catch (IOException e) { 39 | e.printStackTrace(); 40 | } 41 | 42 | mainLogger.start(); 43 | } 44 | } 45 | 46 | public static void shutdown() { 47 | if (mainLogger != null) { 48 | mainLogger.stop(); 49 | mainLogger = null; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/utils/Logger.java: -------------------------------------------------------------------------------- 1 | package royaleserver.utils; 2 | 3 | public abstract class Logger { 4 | private final String loggerName; 5 | 6 | public Logger(String name) { 7 | this.loggerName = name; 8 | } 9 | 10 | public String name() { 11 | return loggerName; 12 | } 13 | 14 | public Logger debug(String message, Object... format) { 15 | return log(LogLevel.DEBUG, message, format); 16 | } 17 | 18 | public Logger info(String message, Object... format) { 19 | return log(LogLevel.INFO, message, format); 20 | } 21 | 22 | public Logger warn(String message, Object... format) { 23 | return log(LogLevel.WARN, message, format); 24 | } 25 | 26 | public Logger error(String message, Object... format) { 27 | return log(LogLevel.ERROR, message, format); 28 | } 29 | 30 | public Logger fatal(String message, Object... format) { 31 | return log(LogLevel.FATAL, message, format); 32 | } 33 | 34 | public Logger log(LogLevel level, String message, Object... format) { 35 | send(level, loggerName, message, format); 36 | return this; 37 | } 38 | 39 | protected abstract void send(LogLevel level, String name, String message, Object[] format); 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/utils/MainLogger.java: -------------------------------------------------------------------------------- 1 | package royaleserver.utils; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.OutputStream; 6 | import java.io.PrintStream; 7 | import java.text.DateFormat; 8 | import java.text.SimpleDateFormat; 9 | import java.util.ArrayList; 10 | import java.util.Date; 11 | import java.util.List; 12 | import java.util.Queue; 13 | import java.util.concurrent.ConcurrentLinkedQueue; 14 | 15 | public final class MainLogger extends Logger { 16 | private static final DateFormat DATE_FORMAT = new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]"); 17 | private Queue logQueue = new ConcurrentLinkedQueue<>(); 18 | private List handlers = new ArrayList<>(); 19 | 20 | private boolean running = false; 21 | private LoggerThread thread = new LoggerThread(); 22 | 23 | public MainLogger() { 24 | this(true); 25 | } 26 | 27 | public MainLogger(boolean start) { 28 | super(""); 29 | if (start) { 30 | this.start(); 31 | } 32 | } 33 | 34 | public void addHandler(OutputStream stream) { 35 | handlers.add(stream); 36 | } 37 | 38 | @Override 39 | protected void send(LogLevel level, String name, String message, Object[] format) { 40 | StringBuilder sb = new StringBuilder(1024); 41 | 42 | Throwable throwable = null; 43 | if ((format.length != 0) && (format[0] instanceof Throwable)) { 44 | throwable = (Throwable)format[0]; 45 | for (int i = 1; i != format.length; ++i) { 46 | format[i - 1] = format[i]; 47 | } 48 | 49 | format[format.length - 1] = null; 50 | } 51 | 52 | sb.append(DATE_FORMAT.format(new Date())); 53 | sb.append(" ["); 54 | sb.append(level.name()); 55 | sb.append("/"); 56 | 57 | String threadName = Thread.currentThread().getName(); 58 | if (threadName.equals("main")) { 59 | sb.append("Main thread"); 60 | } else { 61 | sb.append("Thread "); 62 | sb.append(threadName); 63 | } 64 | 65 | sb.append("] "); 66 | 67 | if (name.equals("")) { 68 | sb.append("Main"); 69 | } else { 70 | sb.append(name); 71 | } 72 | 73 | sb.append(": "); 74 | 75 | if (message == null) { 76 | message = "null"; 77 | } 78 | 79 | sb.append(String.format(message, format)); 80 | sb.append('\n'); 81 | 82 | if (throwable != null) { 83 | ByteArrayOutputStream os = new ByteArrayOutputStream(); 84 | PrintStream stream = new PrintStream(os); 85 | throwable.printStackTrace(stream); 86 | sb.append(new String(os.toByteArray())); 87 | sb.append('\n'); 88 | } 89 | 90 | logQueue.add(sb.toString()); 91 | } 92 | 93 | public void start() { 94 | if (!running) { 95 | running = true; 96 | thread.start(); 97 | } 98 | } 99 | 100 | public void stop() { 101 | if (running) { 102 | running = false; 103 | 104 | try { 105 | thread.join(); 106 | } catch (InterruptedException ignored) {} 107 | 108 | thread = null; 109 | for (OutputStream handler : handlers) { 110 | try { 111 | handler.close(); 112 | } catch (IOException e) { 113 | e.printStackTrace(); 114 | } 115 | } 116 | } 117 | } 118 | 119 | private class LoggerThread extends Thread { 120 | @Override 121 | public void run() { 122 | String line; 123 | 124 | while (running) { 125 | try { 126 | Thread.sleep(20); 127 | } catch (InterruptedException ignored) {} 128 | 129 | while ((line = logQueue.poll()) != null) { 130 | for (OutputStream handler : handlers) { 131 | try { 132 | handler.write(line.getBytes()); 133 | } catch (IOException ignored) {} 134 | } 135 | } 136 | } 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/utils/Pair.java: -------------------------------------------------------------------------------- 1 | package royaleserver.utils; 2 | 3 | public final class Pair { 4 | private A first; 5 | private B second; 6 | 7 | public Pair(A first, B second) { 8 | super(); 9 | this.first = first; 10 | this.second = second; 11 | } 12 | 13 | public final A first() { 14 | return first; 15 | } 16 | 17 | public final B second() { 18 | return second; 19 | } 20 | 21 | public int hashCode() { 22 | int hashFirst = first != null ? first.hashCode() : 0; 23 | int hashSecond = second != null ? second.hashCode() : 0; 24 | 25 | return (hashFirst + hashSecond) * hashSecond + hashFirst; 26 | } 27 | 28 | @Override 29 | public boolean equals(Object o) { 30 | if (this == o) { 31 | return true; 32 | } 33 | if (!(o instanceof Pair)) { 34 | return false; 35 | } 36 | 37 | Pair pair = (Pair)o; 38 | 39 | return first != null ? first.equals(pair.first) : pair.first == null; 40 | } 41 | 42 | public final String toString() { 43 | return "(" + first + ", " + second + ")"; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/utils/SCID.java: -------------------------------------------------------------------------------- 1 | package royaleserver.utils; 2 | 3 | import org.hibernate.HibernateException; 4 | import org.hibernate.engine.spi.SharedSessionContractImplementor; 5 | import org.hibernate.usertype.UserType; 6 | 7 | import java.io.Serializable; 8 | import java.sql.PreparedStatement; 9 | import java.sql.ResultSet; 10 | import java.sql.SQLException; 11 | import java.sql.Types; 12 | 13 | public final class SCID implements UserType, Serializable { 14 | private int high, low; 15 | private long value; 16 | 17 | public SCID() { 18 | this(0, 0); 19 | } 20 | 21 | public SCID(int high, int low) { 22 | this.high = high; 23 | this.low = low; 24 | 25 | value = high * 1000000 + low; 26 | } 27 | 28 | public SCID(long value) { 29 | this((int)(value / 1000000), (int)(value % 1000000)); 30 | } 31 | 32 | public int getHigh() { 33 | return high; 34 | } 35 | 36 | public int getLow() { 37 | return low; 38 | } 39 | 40 | public long getValue() { 41 | return value; 42 | } 43 | 44 | // Java 45 | 46 | @Override 47 | public int hashCode() { 48 | return (int)getValue(); 49 | } 50 | 51 | @Override 52 | public boolean equals(Object o) { 53 | if (o instanceof SCID) { 54 | return getValue() == ((SCID)o).getValue(); 55 | } 56 | 57 | return super.equals(o); 58 | } 59 | 60 | @Override 61 | protected Object clone() throws CloneNotSupportedException { 62 | return new SCID(high, low); 63 | } 64 | 65 | @Override 66 | public String toString() { 67 | return (new StringBuilder()) 68 | .append("SCID(high = ").append(high) 69 | .append(", low = ").append(low) 70 | .append(", value = ").append(getValue()) 71 | .append(")").toString(); 72 | } 73 | 74 | 75 | // Hibernate 76 | 77 | @Override 78 | public int[] sqlTypes() { 79 | return new int[] { Types.BIGINT }; 80 | } 81 | 82 | @Override 83 | public Class returnedClass() { 84 | return SCID.class; 85 | } 86 | 87 | @Override 88 | public boolean equals(Object x, Object y) throws HibernateException { 89 | if (x == null || y == null) { 90 | return x == y; 91 | } 92 | 93 | return x.equals(y); 94 | } 95 | 96 | @Override 97 | public int hashCode(Object x) throws HibernateException { 98 | return x.hashCode(); 99 | } 100 | 101 | @Override 102 | public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException { 103 | final String value = rs.getString(names[0]); 104 | if (value == null) { 105 | return null; 106 | } 107 | 108 | return new SCID(Long.valueOf(value)); 109 | } 110 | 111 | @Override 112 | public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException { 113 | if (value == null) { 114 | st.setNull(index, Types.BIGINT); 115 | return; 116 | } 117 | 118 | st.setLong(index, ((SCID)value).getValue()); 119 | } 120 | 121 | @Override 122 | public Object deepCopy(Object value) throws HibernateException { 123 | return value; 124 | } 125 | 126 | @Override 127 | public boolean isMutable() { 128 | return false; 129 | } 130 | 131 | @Override 132 | public Serializable disassemble(Object value) throws HibernateException { 133 | return (Serializable)value; 134 | } 135 | 136 | @Override 137 | public Object assemble(Serializable cached, Object owner) throws HibernateException { 138 | return cached; 139 | } 140 | 141 | @Override 142 | public Object replace(Object original, Object target, Object owner) throws HibernateException { 143 | return original; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/utils/StringUtils.java: -------------------------------------------------------------------------------- 1 | package royaleserver.utils; 2 | 3 | import java.io.InputStream; 4 | import java.nio.charset.Charset; 5 | import java.util.Random; 6 | 7 | public final class StringUtils { 8 | private StringUtils() {} 9 | 10 | private static final Charset charset = Charset.forName("UTF-8"); 11 | 12 | private static final char[] symbols; 13 | private static final Random random = new Random(); 14 | private static char[] buffer = new char[64]; 15 | 16 | static { 17 | StringBuilder tmp = new StringBuilder(); 18 | for (char ch = '0'; ch <= '9'; ++ch) { 19 | tmp.append(ch); 20 | } 21 | 22 | for (char ch = 'a'; ch <= 'z'; ++ch) { 23 | tmp.append(ch); 24 | } 25 | 26 | for (char ch = 'A'; ch <= 'Z'; ++ch) { 27 | tmp.append(ch); 28 | } 29 | 30 | symbols = tmp.toString().toCharArray(); 31 | } 32 | 33 | /** 34 | * Generates a string using 0-9A-Za-z characters with length between minLength and maxLength. 35 | * @param minLength Minimal length of string 36 | * @param maxLength Maximal length of string 37 | * @return Generated string 38 | */ 39 | public static synchronized String randomString(int minLength, int maxLength) { 40 | return randomString(minLength + random.nextInt(maxLength - minLength + 1)); 41 | } 42 | 43 | /** 44 | * Generates a string using 0-9A-Za-z characters for given length. 45 | * @param length Length of string 46 | * @return Generated string 47 | */ 48 | public static synchronized String randomString(int length) { 49 | if (buffer.length < length) { 50 | int bufferLength = buffer.length; 51 | while (bufferLength < length) { 52 | bufferLength <<= 1; 53 | } 54 | 55 | buffer = new char[bufferLength]; 56 | } 57 | 58 | for (int i = 0; i < length; ++i) { 59 | buffer[i] = symbols[random.nextInt(symbols.length)]; 60 | } 61 | 62 | return new String(buffer, 0, length); 63 | } 64 | 65 | public static String from(InputStream is) { 66 | return from(is, true); 67 | } 68 | 69 | public static String from(InputStream is, boolean close) { 70 | byte[] buffer = IO.getByteArray(is, close); 71 | if (buffer == null) { 72 | return null; 73 | } 74 | 75 | return from(buffer); 76 | } 77 | 78 | public static String from(byte[] buffer) { 79 | return new String(buffer, charset); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/royaleserver/utils/Tag.java: -------------------------------------------------------------------------------- 1 | package royaleserver.utils; 2 | 3 | import java.io.Serializable; 4 | 5 | public final class Tag implements Comparable, Serializable { 6 | private static final String TAG_CHARACTERS = "0289PYLQGRJCUV"; 7 | private final long id; 8 | private transient String string = null; 9 | 10 | public Tag(long id) { 11 | this.id = id; 12 | } 13 | 14 | public Tag(String tag) { 15 | if (tag.startsWith("#")) { 16 | tag = tag.substring(1); 17 | } 18 | 19 | long parsedId = 0; 20 | 21 | for (char c : tag.toCharArray()) { 22 | int index = TAG_CHARACTERS.indexOf(c); 23 | parsedId *= TAG_CHARACTERS.length(); 24 | parsedId += index; 25 | } 26 | 27 | final long high = parsedId % 256; 28 | final long low = (parsedId - high) >>> 8; 29 | 30 | id = (high << 32) | low; 31 | } 32 | 33 | public long id() { 34 | return id; 35 | } 36 | 37 | public String string() { 38 | if (string != null) { 39 | return string; 40 | } 41 | 42 | final long high = (id >> 32) & 0xFFFFFFFF; 43 | final long low = id & 0xFFFFFFFF; 44 | 45 | long parsedId = (low << 8) + high; 46 | final StringBuilder sb = new StringBuilder(); 47 | 48 | while (parsedId != 0L) { 49 | int index = (int)(parsedId % TAG_CHARACTERS.length()); 50 | sb.append(TAG_CHARACTERS.charAt(index)); 51 | parsedId /= TAG_CHARACTERS.length(); 52 | } 53 | 54 | return string = sb.toString(); 55 | } 56 | 57 | @Override 58 | public boolean equals(Object o) { 59 | if (this == o) { 60 | return true; 61 | } 62 | if (!(o instanceof Tag)) { 63 | return false; 64 | } 65 | 66 | Tag tag = (Tag)o; 67 | 68 | return id == tag.id; 69 | } 70 | 71 | @Override 72 | public int hashCode() { 73 | return (int)(id ^ (id >>> 32)); 74 | } 75 | 76 | @Override 77 | public String toString() { 78 | return string; 79 | } 80 | 81 | @Override 82 | public int compareTo(Tag tag) { 83 | return Long.compare(id, tag.id); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/resources/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_version": 6, 3 | 4 | "assets": [ 5 | { 6 | "disabled": true, 7 | "provider": "apk", 8 | "file": "ClashRoyale.apk" 9 | }, { 10 | "disabled": true, 11 | "provider": "zip", 12 | "file": "ClashRoyale.zip", 13 | "root": "assets" 14 | }, { 15 | "disabled": true, 16 | "provider": "folder", 17 | "path": "assets" 18 | } 19 | ], 20 | 21 | "content": { 22 | "url": "http://7166046b142482e67b30-2a63f4436c967aa7d355061bd0d924a1.r65.cf1.rackcdn.com" 23 | }, 24 | 25 | "server": { 26 | "require_login_code": false, 27 | "port": 9339 28 | }, 29 | 30 | "database": { 31 | "provider": "mysql", 32 | "show_sql": false, 33 | 34 | "mysql": { 35 | "host": "localhost", 36 | "port": 3306, 37 | 38 | "user": "root", 39 | "password": "", 40 | 41 | "database": "clashroyale" 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/main/resources/hibernate.cfg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | update 7 | false 8 | 9 | 1 10 | 1 11 | 300 12 | 50 13 | 0 14 | 15 | false 16 | 17 | thread 18 | true 19 | 20 | --------------------------------------------------------------------------------