Лаунчер на Java ( полномасштабный )

Добро пожаловать!

Зарегистрировавшись у нас, вы сможете обсуждать, делиться и отправлять личные сообщения другим участникам нашего сообщества.

Зарегистрироваться!
  • Если Вы желаете помогать развитию проекта, готовы заполнять раздел(-ы) и подсказывать другим пользователям на портале, есть возможность попасть в команду редакторов. Для этого следует обратиться в техническую поддержку
Пользователь
Регистрация
11 Май 2025
Сообщения
10

Структура проекта ( Maven )​

src/
├── main/
│ ├── java/com/crmp/launcher/
│ │ ├── core/
│ │ │ ├── AuthManager.java # Аутентификация
│ │ │ ├── UpdateEngine.java # Система обновлений
│ │ │ ├── SecurityModule.java # Античит и шифрование
│ │ │ └── ServerBrowser.java # Список серверов
│ │ ├── gui/
│ │ │ ├── MainWindow.java # Основное окно
│ │ │ ├── LoginController.java # Форма входа
│ │ │ └── Animations.java # Анимации JavaFX
│ │ └── LauncherMain.java # Точка входа
│ └── resources/ # Шрифы, стили, иконки
└── test/ # Юнит-тест

Код основных модулей, шифрование трафика​

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Base64;

public class SecurityModule {
private static final String ALGORITHM = "AES";
private static final byte[] KEY = "MySuperSecretKey".getBytes();

public static String encrypt(String data) throws Exception {
Key key = new SecretKeySpec(KEY, ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypted = cipher.doFinal(data.getBytes());
return Base64.getEncoder().encodeToString(encrypted);
}

public static String decrypt(String encryptedData) throws Exception {
Key key = new SecretKeySpec(KEY, ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decoded = Base64.getDecoder().decode(encryptedData);
byte[] decrypted = cipher.doFinal(decoded);
return new String(decrypted);
}
}

Система обновлений​

import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.util.List;
import java.util.concurrent.CompletableFuture;

public class UpdateEngine {
private static final String MANIFEST_URL = "https://api.crmp.mobi/launcher/manifest";

public CompletableFuture<Boolean> checkUpdates() {
return CompletableFuture.supplyAsync(() -> {
try (CloseableHttpClient client = HttpClients.createDefault()) {
HttpGet request = new HttpGet(MANIFEST_URL);
String manifestJson = client.execute(request, response ->
new BufferedReader(new InputStreamReader(response.getEntity().getContent()))
.lines().collect(Collectors.joining("\n")));

List<FileMetadata> remoteFiles = parseManifest(manifestJson);
return remoteFiles.stream().anyMatch(remote ->
!Files.exists(Paths.get(remote.path)) ||
!checksumMatch(remote.path, remote.hash));
} catch (Exception e) {
throw new RuntimeException("Update check failed", e);
}
});
}

private boolean checksumMatch(String path, String expectedHash) {
try (InputStream is = Files.newInputStream(Paths.get(path))) {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] buffer = new byte[8192];
int read;
while ((read = is.read(buffer)) != -1) {
md.update(buffer, 0, read);
}
byte[] hash = md.digest();
return bytesToHex(hash).equals(expectedHash);
} catch (Exception e) {
return false;
}
}
}

Античит-Модуль​

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;

public class AntiCheat {
private static final List<String> BANNED_SIGNATURES = Arrays.asList(
"4D5A900003000000", // Сигнатура .exe
"CEFAEDFE0C000000" // Сигнатура Mach-O
);

public static boolean scanGameFiles() {
try {
Files.walk(Paths.get("game_files"))
.filter(Files::isRegularFile)
.forEach(path -> {
byte[] data = Files.readAllBytes(path);
String hex = bytesToHex(data);
if (BANNED_SIGNATURES.stream().anyMatch(hex::contains)) {
throw new RuntimeException("Обнаружен запрещенный файл: " + path);
}
});
return true;
} catch (Exception e) {
return false;
}
}
}

GUI на JAVAFX​

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class MainWindow extends Application {
@Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
ProgressBar progressBar = new ProgressBar();
root.getChildren().add(progressBar);

Scene scene = new Scene(root, 800, 600);
scene.getStylesheets().add("styles.css");

primaryStage.setTitle("CRMP Mobile Launcher");
primaryStage.setScene(scene);
primaryStage.show();

// Запуск проверки обновлений
UpdateEngine updateEngine = new UpdateEngine();
updateEngine.checkUpdates().thenAccept(hasUpdates -> {
if (hasUpdates) {
showUpdateScreen();
} else {
showLoginScreen();
}
});
}

private void showUpdateScreen() { /* ... */ }
private void showLoginScreen() { /* ... */ }
}

Запуск лаунчера​

mvn clean javafx:run

ТРЕБОВАНИЕ​

Java 17+ ( с модулями JPMS )

2. Зависимость от Maven
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>17</version>
</dependency>
</dependencies>
 
Сверху