1
0
mirror of https://github.com/Eyre-S/sekai-scores.git synced 2024-11-24 20:17:40 +08:00

add a CLI program, which can read config, simple parse and echo a basic score

- CLI add config read, from $HOME/.config/sekai-scores/sekai-scores.properties.
  - now it can read a pjsekai user id, and the sekai-scores database config
- add a command `add`
  - it now can parse 9 params from args, or let user input them in cli, to build a basic score
  - it can echo the score, which looks just like the result score screen in game
- now the sekai-cli build script supports 'application' implementation, and supports UTF-8 and uses spotbugs-annotations.
This commit is contained in:
A.C.Sukazyo Eyre 2022-11-24 20:42:03 +08:00
parent 079da346b0
commit e6cbab2d3c
Signed by: Eyre_S
GPG Key ID: C17CE40291207874
7 changed files with 247 additions and 3 deletions

View File

@ -1,16 +1,19 @@
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets
plugins {
id 'java'
id 'application'
}
group 'cc.sukazyo'
version projVersion
repositories {
mavenCentral()
}
dependencies {
compileOnly "com.github.spotbugs:spotbugs-annotations:${lib_spotbugs_v}"
implementation rootProject
testImplementation "org.junit.jupiter:junit-jupiter-api:${lib_junit_v}"
@ -18,6 +21,35 @@ dependencies {
}
final JavaVersion proj_java = JavaVersion.VERSION_17
final Charset proj_source_encoding = StandardCharsets.UTF_8
group 'cc.sukazyo'
version moduleVersion
application {
mainClass = "${group}.sekai_cli.ClientMain"
}
test {
useJUnitPlatform()
}
java {
sourceCompatibility proj_java
targetCompatibility proj_java
withSourcesJar()
}
tasks.withType(JavaCompile) {
options.encoding = proj_source_encoding.name()
}
tasks.withType(Javadoc) {
options.encoding = proj_source_encoding.name()
options.docEncoding = proj_source_encoding.name()
options.charSet = proj_source_encoding.name()
}

View File

@ -0,0 +1,4 @@
## Project Configurations
# Proj Metadata
moduleVersion = 0.5

View File

@ -0,0 +1,28 @@
package cc.sukazyo.sekai_cli;
import cc.sukazyo.sekai_cli.client.AddScore;
import java.util.Arrays;
public class ClientMain {
public static final Config config = Config.loadUserConfig();
public static void main (String[] args) {
if (args.length > 0) {
if (args[0].equals("add")) {
AddScore.main(Arrays.copyOfRange(args, 1, args.length));
$done();
}
}
System.out.println("Unknown function call.\n please check your program param.");
}
private static void $done () {
System.exit(0);
}
}

View File

@ -0,0 +1,74 @@
package cc.sukazyo.sekai_cli;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Properties;
import static cc.sukazyo.sekai_cli.Log._debug;
public class Config {
private static final String CONFIG_ROOT_NAME = "sekai-scores";
private static final String CONFIG_FILE = CONFIG_ROOT_NAME + ".properties";
public final long sekai_id;
@Nonnull public final String db_host;
@Nonnull public final String db_name;
@Nonnull public final String db_auth_user;
@Nonnull public final String db_auth_pwd;
@Nullable public final String db_prefix;
private Config (Properties props) {
// user config field
this.sekai_id = Long.parseLong(props.getProperty("user.sekai-id"));
_debug("config field user.sekai-id set: " + this.sekai_id);
this.db_host = getNonnull(props, "db.server");
_debug("config field db.server set: " + this.db_host);
this.db_name = getNonnull(props, "db.database");
_debug("config field db.database set: " + this.db_name);
this.db_auth_user = getNonnull(props, "db.auth.user");
_debug("config field db.auth.user set: " + this.db_auth_user);
this.db_auth_pwd = getNonnull(props, "db.auth.password");
_debug("config field db.auth.password set.");
this.db_prefix = props.getProperty("db.table-prefix");
_debug(this.db_prefix == null ? "config field db.prefix unset." : "config field db.table-prefix set: " + this.db_prefix);
}
@Nonnull
private static String getNonnull (Properties props, String key) {
final String v = props.getProperty(key);
if (v == null) throw new NullPointerException("null at key " + key);
return v;
}
static Config loadUserConfig() {
try {
final Properties props = new Properties();
final File propFile = Paths.get(getAppConfigPath(getSysUserConfigRoot()).toString(), CONFIG_FILE).toFile();
props.load(new FileInputStream(propFile));
_debug("loaded config file: " + propFile.getAbsolutePath());
return new Config(props);
} catch (IOException e) {
throw new RuntimeException("error while load user config", e);
}
}
private static Path getAppConfigPath(Path configRoot) {
return Paths.get(configRoot.toString(), CONFIG_ROOT_NAME);
}
private static Path getSysUserConfigRoot () {
final Path userhome = Paths.get(System.getProperty("user.home"), ".config");
_debug("read config from user home : " + userhome.toAbsolutePath());
return userhome;
}
}

View File

@ -0,0 +1,16 @@
package cc.sukazyo.sekai_cli;
public class Log {
private static final boolean IS_DEBUG = true;
public static void _debug (String m) {
if (!isDebug()) return;
m = "[DEBUG]" + m;
m = m.replaceAll("\\n", "'''''''");
System.out.println(m);
}
private static boolean isDebug () { return IS_DEBUG; }
}

View File

@ -0,0 +1,56 @@
package cc.sukazyo.sekai_cli.client;
import cc.sukazyo.sekai_scores.ScoreBase;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.InputMismatchException;
import java.util.Scanner;
import static cc.sukazyo.sekai_cli.Log._debug;
public class AddScore {
public static void main (String[] args) {
try {
final int[] scores = new int[9];
if (args.length == 0) {
System.out.println("Input your score,");
System.out.println(" score formatting: perfect ... miss late fast flick combo");
System.out.print("> ");
Scanner input = new Scanner(System.in);
for (int i = 0; i < 9; i++) {
scores[i] = input.nextInt();
}
} else {
for (int i = 0; i < 9; i++) {
scores[i] = Integer.parseInt(args[i]);
}
}
for (int i : scores) {
if (i < 0 || i > 9999) throw new InputMismatchException(String.format("input %d out of range of [0, 9999]", i));
}
ScoreBase scoreBase = new ScoreBase(
scores[0], scores[1], scores[2], scores[3], scores[4],
scores[6], scores[5], scores[7], scores[8]
);
System.out.println(PrintScore.printTableScoreBase(scoreBase));
} catch (ArrayIndexOutOfBoundsException | NumberFormatException e) {
System.out.println("unsupported yet.");
final StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
_debug(sw.toString());
} catch (InputMismatchException e) {
System.out.println("unavailable input: " + e.getMessage());
}
}
}

View File

@ -0,0 +1,34 @@
package cc.sukazyo.sekai_cli.client;
import cc.sukazyo.sekai_scores.ScoreBase;
public class PrintScore {
public static final String MESSAGE_AP = "ALL PERFECT!";
public static final String MESSAGE_FC = "FULL COMBO!";
public static String getMessageQuote(String message) {
return "\\ " + message + " /";
}
public static String printTableScoreBase (ScoreBase score) {
return String.format("""
COMBO %16s
PERFECT %4d
GREAT %4d LATE FAST
%-4d GOOD %4d [%-4d %4d]
BAD %4d FLICK %4d
MISS %4d
""",
score.noteCount() == score.combo() ? getMessageQuote((score.noteCount()==score.perfect()?MESSAGE_AP : MESSAGE_FC)) : "",
score.perfect(),
score.great(),
score.combo(), score.good(), score.slow(), score.fast(),
score.bad(), score.flick(),
score.miss()
);
}
}