Added builder, DataTracker and KeyValue #16
@ -10,14 +10,16 @@ on:
|
||||
pull_request_target:
|
||||
branches: [ master, dev ]
|
||||
|
||||
env:
|
||||
REPO_USERNAME: Altarik
|
||||
REPO_PASSWORD: ${{ secrets.REPO_PASSWORD }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
java: [ '17' ]
|
||||
# and run on both Linux and Windows
|
||||
os: [ubuntu-latest, windows-2022]
|
||||
os: [ ubuntu-latest ]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
@ -31,17 +33,19 @@ jobs:
|
||||
distribution: 'oracle'
|
||||
- name: make gradle wrapper executable
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
run: chmod +x ./gradlew
|
||||
run: |
|
||||
chmod +x ./gradlew
|
||||
touch local.properties
|
||||
echo $REPO_USERNAME
|
||||
- name: build
|
||||
run: ./gradlew build --no-daemon
|
||||
- name: test
|
||||
run: ./gradlew test --no-daemon
|
||||
run: ./gradlew build --no-daemon --max-workers 1
|
||||
#- name: test
|
||||
# run: ./gradlew test --no-daemon
|
||||
deploy:
|
||||
runs-on: ${{ ubuntu-latest }}
|
||||
if: gitea.ref == 'refs/heads/master'
|
||||
needs: build
|
||||
steps:
|
||||
- name: deploy
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Artifacts
|
||||
path: build/libs/
|
||||
run: ./gradlew publish
|
||||
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -3,9 +3,11 @@ build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
local.properties
|
||||
|
||||
*/run
|
||||
*/logs
|
||||
run/*
|
||||
**/run
|
||||
**/logs
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
|
@ -0,0 +1,8 @@
|
||||
package fr.altarik.toolbox.core.builder;
|
||||
|
||||
public class EmptyCollectionException extends NullPointerException {
|
||||
|
||||
public EmptyCollectionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package fr.altarik.toolbox.core.builder;
|
||||
|
||||
public interface IBuilder<T> {
|
||||
|
||||
/**
|
||||
* Build the builders parameters into T object
|
||||
* @return The created objects thanks to given parameters
|
||||
* @throws Exception if any error occur during creation of the built object
|
||||
*/
|
||||
T build() throws Exception;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package fr.altarik.toolbox.core.builder;
|
||||
|
||||
/**
|
||||
* Builder parameter, for more flexibility
|
||||
* @param <T> the parameter type
|
||||
* @see OptionalParamBuilder
|
||||
* @see RequiredParamBuilder
|
||||
* @see RequiredCollectionParameterBuilder
|
||||
*/
|
||||
public interface IParamBuilder<T> {
|
||||
|
||||
/**
|
||||
* Get the given object, may return {@link NullPointerException} depending on the policy of implemented class
|
||||
* @return the parameter given by {@link IParamBuilder#set(Object)}
|
||||
* @throws NullPointerException may throw this error depending on the policy of implemented class
|
||||
*/
|
||||
T get() throws NullPointerException;
|
||||
|
||||
/**
|
||||
* Change/insert the value of the parameter
|
||||
* @param parameter the given parameter
|
||||
*/
|
||||
void set(T parameter);
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package fr.altarik.toolbox.core.builder;
|
||||
|
||||
/**
|
||||
* Doesn't throw a {@link NullPointerException} when using {@link IParamBuilder#get()} in any case
|
||||
* @param <T> the returned type
|
||||
* @see IParamBuilder
|
||||
*/
|
||||
public class OptionalParamBuilder<T> implements IParamBuilder<T> {
|
||||
|
||||
private T parameter;
|
||||
|
||||
public OptionalParamBuilder(T param) {
|
||||
this.parameter = param;
|
||||
}
|
||||
@Override
|
||||
public T get() throws NullPointerException {
|
||||
return parameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(T parameter) {
|
||||
this.parameter = parameter;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package fr.altarik.toolbox.core.builder;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Mostly same as {@link RequiredParamBuilder} but for list
|
||||
* @param <E> The type contained in the collection
|
||||
* @param <T> The returned type
|
||||
*/
|
||||
public class RequiredCollectionParameterBuilder<E, T extends Collection<E>> implements IParamBuilder<T> {
|
||||
|
||||
private final T collection;
|
||||
private final boolean canBeEmpty;
|
||||
|
||||
public RequiredCollectionParameterBuilder(@NotNull T collection, boolean canBeEmpty) {
|
||||
this.collection = Objects.requireNonNull(collection);
|
||||
this.canBeEmpty = canBeEmpty;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the list, if not empty</p>
|
||||
* <p>If empty, return the collection if {@code canBeEmpty} if true, otherwise throw a {@link NullPointerException}</p>
|
||||
* @return the collection
|
||||
* @throws NullPointerException if collection is empty and {@code canBeEmpty} is false
|
||||
*/
|
||||
@Override
|
||||
public T get() throws NullPointerException {
|
||||
if(canBeEmpty) {
|
||||
return collection;
|
||||
} else if(!collection.isEmpty()) {
|
||||
return collection;
|
||||
} else {
|
||||
throw new EmptyCollectionException("Collection cannot be empty");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(T parameter) {
|
||||
throw new UnsupportedOperationException("Use `add` in place of `set` for RequiredCollectionParameterBuilder");
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an element to the collection
|
||||
* @param element element to add to the list
|
||||
*/
|
||||
public void add(E element) {
|
||||
collection.add(element);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package fr.altarik.toolbox.core.builder;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Throw a {@link NullPointerException} when using {@link IParamBuilder#get()} if the parameter doesn't have been initialized
|
||||
* @param <T> the returned type
|
||||
*/
|
||||
public class RequiredParamBuilder<T> implements IParamBuilder<T> {
|
||||
|
||||
private T parameter;
|
||||
|
||||
public RequiredParamBuilder(T parameter) {
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
public RequiredParamBuilder() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
return Objects.requireNonNull(parameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(T parameter) {
|
||||
this.parameter = parameter;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package fr.altarik.toolbox.core.data;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class DataTracker {
|
||||
|
||||
private final Map<TrackedData, String> trackedData;
|
||||
|
||||
public DataTracker() {
|
||||
this.trackedData = new HashMap<>();
|
||||
}
|
||||
|
||||
public void startTracking(TrackedData data) {
|
||||
trackedData.put(data, data.defaultValue());
|
||||
}
|
||||
|
||||
public String getOrDefault(TrackedData data) {
|
||||
return Objects.requireNonNull(trackedData.get(data));
|
||||
}
|
||||
|
||||
public void set(TrackedData data, String value) {
|
||||
String v = trackedData.get(data);
|
||||
if(v != null) {
|
||||
trackedData.putIfAbsent(data, value);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Data " + data.name() + " is not tracked, please initialize it with DataTracker#startTracking(TrackedData, String) first");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void saveToDb() {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package fr.altarik.toolbox.core.data;
|
||||
|
||||
public record TrackedData(String name, String defaultValue) {
|
||||
|
||||
}
|
BIN
Core/src/main/resources/assets/core/icon.png
Normal file
BIN
Core/src/main/resources/assets/core/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
29
Core/src/main/resources/fabric.mod.json
Normal file
29
Core/src/main/resources/fabric.mod.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "toolbox-core",
|
||||
"version": "${version}",
|
||||
"name": "Core",
|
||||
"description": "",
|
||||
"authors": [
|
||||
"Altarik"
|
||||
],
|
||||
"contributors": [
|
||||
"Legot Quentin<legotquentin@gmail.com>"
|
||||
],
|
||||
"contact": {
|
||||
"homepage": "https://altarik.fr"
|
||||
},
|
||||
"license": "Altarik @ All-Rights-Reserved ",
|
||||
"icon": "assets/core/icon.png",
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"main": []
|
||||
},
|
||||
"mixins": [],
|
||||
"depends": {
|
||||
"fabricloader": "^0.14.12",
|
||||
"fabric-api": "*",
|
||||
"minecraft": "1.19.3",
|
||||
"java": ">=17"
|
||||
}
|
||||
}
|
38
Core/src/test/java/BuilderImpl.java
Normal file
38
Core/src/test/java/BuilderImpl.java
Normal file
@ -0,0 +1,38 @@
|
||||
import fr.altarik.toolbox.core.builder.IBuilder;
|
||||
import fr.altarik.toolbox.core.builder.RequiredCollectionParameterBuilder;
|
||||
import fr.altarik.toolbox.core.builder.RequiredParamBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BuilderImpl implements IBuilder<BuilderResult> {
|
||||
|
||||
private final RequiredCollectionParameterBuilder<String, List<String>> collection;
|
||||
private final RequiredParamBuilder<Integer> numberOfSentences;
|
||||
|
||||
private BuilderImpl(boolean canBeEmpty) {
|
||||
this.collection = new RequiredCollectionParameterBuilder<>(new ArrayList<>(), canBeEmpty);
|
||||
this.numberOfSentences = new RequiredParamBuilder<>();
|
||||
}
|
||||
|
||||
public BuilderImpl addSentence(String sentence) {
|
||||
collection.add(sentence);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BuilderImpl numberOfSentence(int i) {
|
||||
this.numberOfSentences.set(i);
|
||||
return this;
|
||||
}
|
||||
|
||||
public static BuilderImpl builder(boolean canBeEmpty) {
|
||||
return new BuilderImpl(canBeEmpty);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public BuilderResult build() throws Exception {
|
||||
return new BuilderResult(collection.get(), numberOfSentences.get());
|
||||
}
|
||||
}
|
5
Core/src/test/java/BuilderResult.java
Normal file
5
Core/src/test/java/BuilderResult.java
Normal file
@ -0,0 +1,5 @@
|
||||
import java.util.List;
|
||||
|
||||
public record BuilderResult(List<String> sentences, int numberOfSentences) {
|
||||
|
||||
}
|
32
Core/src/test/java/BuilderTest.java
Normal file
32
Core/src/test/java/BuilderTest.java
Normal file
@ -0,0 +1,32 @@
|
||||
import fr.altarik.toolbox.core.builder.EmptyCollectionException;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class BuilderTest {
|
||||
|
||||
|
||||
@Test
|
||||
void builderTest() throws Exception {
|
||||
BuilderImpl builder = BuilderImpl.builder(true);
|
||||
builder.addSentence("First sentence");
|
||||
builder.addSentence("Second sentence");
|
||||
builder.numberOfSentence(2);
|
||||
BuilderResult res = builder.build();
|
||||
Assertions.assertEquals(Arrays.asList("First sentence", "Second sentence"), res.sentences());
|
||||
Assertions.assertEquals(res.numberOfSentences(), 2);
|
||||
|
||||
BuilderImpl builder1 = BuilderImpl.builder(false);
|
||||
builder1.numberOfSentence(3);
|
||||
Assertions.assertThrowsExactly(EmptyCollectionException.class, builder1::build);
|
||||
|
||||
BuilderImpl builder2 = BuilderImpl.builder(true);
|
||||
builder2.numberOfSentence(3);
|
||||
Assertions.assertDoesNotThrow(builder2::build);
|
||||
|
||||
BuilderImpl builder3 = BuilderImpl.builder(true);
|
||||
Assertions.assertThrowsExactly(NullPointerException.class, builder3::build);
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,9 @@
|
||||
dependencies {
|
||||
implementation 'org.postgresql:postgresql:42.5.0'
|
||||
implementation 'org.postgresql:postgresql:42.6.0'
|
||||
testImplementation 'com.google.code.gson:gson:2.10'
|
||||
implementation project(':Core')
|
||||
}
|
||||
|
||||
test {
|
||||
exclude 'fr/altarik/toolbox/database/**' // exclude for runner
|
||||
}
|
@ -25,16 +25,18 @@ public abstract class AbstractSqlConnection implements SqlConnection {
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeConnection() {
|
||||
try {
|
||||
if(!connection.isClosed()) {
|
||||
connection.close();
|
||||
connection = null;
|
||||
}
|
||||
} catch(SQLException ignored) {
|
||||
// no op
|
||||
}
|
||||
close();
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
if(!connection.isClosed()) {
|
||||
connection.close();
|
||||
connection = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,28 @@
|
||||
package fr.altarik.toolbox.database;
|
||||
|
||||
import fr.altarik.toolbox.database.keyValue.KeyValueBuilder;
|
||||
import fr.altarik.toolbox.database.keyValue.KeyValueTable;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class Connections {
|
||||
|
||||
/**
|
||||
* Create a new Connection object for a postgresql database server
|
||||
* @return
|
||||
* @return postgresql connection
|
||||
*/
|
||||
public static SqlConnection newPostgresConnection(ConnectionConfig config) throws SQLException {
|
||||
return new PostgresConnection(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new (key, value) table if not exist and use it through {@link KeyValueTable} interface
|
||||
* @param connection Postgresql connection
|
||||
* @param tableName name of the table to use
|
||||
* @return interface to control the table
|
||||
* @throws SQLException if connection is lost
|
||||
*/
|
||||
public static KeyValueTable newKeyValueTable(SqlConnection connection, String tableName) throws SQLException {
|
||||
return KeyValueBuilder.builder().setConnection(connection).setTableName(tableName).build();
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import java.sql.SQLException;
|
||||
|
||||
public class PostgresConnection extends AbstractSqlConnection {
|
||||
|
||||
PostgresConnection(ConnectionConfig config) throws SQLException {
|
||||
public PostgresConnection(ConnectionConfig config) throws SQLException {
|
||||
super(config);
|
||||
}
|
||||
|
||||
|
@ -3,14 +3,30 @@ package fr.altarik.toolbox.database;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public interface SqlConnection {
|
||||
public interface SqlConnection extends AutoCloseable {
|
||||
|
||||
/**
|
||||
* Start the connection to sql database
|
||||
* @throws SQLException if unable to connect to database
|
||||
*/
|
||||
void connect() throws SQLException;
|
||||
|
||||
/**
|
||||
* Get the sql connection
|
||||
* @return the connection session
|
||||
*/
|
||||
Connection getConnection();
|
||||
|
||||
/**
|
||||
* Reconnect you to database if it has closed or lost.
|
||||
* @throws SQLException if unable to reconnect you
|
||||
*/
|
||||
void checkConnection() throws SQLException;
|
||||
|
||||
/**
|
||||
* @deprecated replaced with {@link AutoCloseable#close()}
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
void closeConnection();
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
package fr.altarik.toolbox.database.keyValue;
|
||||
|
||||
import fr.altarik.toolbox.core.builder.IBuilder;
|
||||
import fr.altarik.toolbox.core.builder.RequiredParamBuilder;
|
||||
import fr.altarik.toolbox.database.SqlConnection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
||||
public class KeyValueBuilder implements IBuilder<KeyValuePostgresql> {
|
||||
|
||||
private final RequiredParamBuilder<String> tableName;
|
||||
private final RequiredParamBuilder<SqlConnection> connection;
|
||||
|
||||
private KeyValueBuilder() {
|
||||
this.tableName = new RequiredParamBuilder<>();
|
||||
this.connection = new RequiredParamBuilder<>();
|
||||
}
|
||||
|
||||
public static KeyValueBuilder builder() {
|
||||
return new KeyValueBuilder();
|
||||
}
|
||||
|
||||
public KeyValueBuilder setConnection(@NotNull SqlConnection connection) {
|
||||
this.connection.set(connection);
|
||||
return this;
|
||||
}
|
||||
|
||||
public KeyValueBuilder setTableName(@NotNull String tableName) {
|
||||
this.tableName.set(tableName);
|
||||
return this;
|
||||
}
|
||||
|
||||
public KeyValuePostgresql build() throws SQLException {
|
||||
return new KeyValuePostgresql(connection.get(), tableName.get());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package fr.altarik.toolbox.database.keyValue;
|
||||
|
||||
import fr.altarik.toolbox.database.SqlConnection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
public class KeyValuePostgresql implements KeyValueTable {
|
||||
|
||||
private final SqlConnection connection;
|
||||
private final String tableName;
|
||||
|
||||
public KeyValuePostgresql(@NotNull SqlConnection connection, @NotNull String tableName) throws SQLException {
|
||||
this.connection = connection;
|
||||
this.tableName = tableName;
|
||||
connection.checkConnection();
|
||||
createTable(tableName);
|
||||
}
|
||||
|
||||
private void createTable(String tableName) throws SQLException {
|
||||
try(Statement statement = connection.getConnection().createStatement()) {
|
||||
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + tableName + "(key VARCHAR(50) NOT NULL, value TEXT NOT NULL, PRIMARY KEY(key));");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getValue(String key) throws SQLException {
|
||||
connection.checkConnection();
|
||||
try(PreparedStatement preparedStatement = connection.getConnection().prepareStatement("SELECT value FROM " + tableName + " WHERE key=?;")) {
|
||||
preparedStatement.setString(1, key);
|
||||
ResultSet resultSet = preparedStatement.executeQuery();
|
||||
if(resultSet.next())
|
||||
return resultSet.getString(1);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertValue(String key, String value) throws SQLException {
|
||||
connection.checkConnection();
|
||||
try(PreparedStatement preparedStatement = connection.getConnection().prepareStatement("INSERT INTO " + tableName + "(key, value) VALUES (?, ?);")){
|
||||
preparedStatement.setString(1, key);
|
||||
preparedStatement.setString(2, value);
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateValue(String key, String value) throws SQLException {
|
||||
connection.checkConnection();
|
||||
try(PreparedStatement preparedStatement = connection.getConnection().prepareStatement("UPDATE " + tableName + " SET value=? WHERE key=?;")) {
|
||||
preparedStatement.setString(1, value);
|
||||
preparedStatement.setString(2, key);
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRow(String key) throws SQLException {
|
||||
connection.checkConnection();
|
||||
try(PreparedStatement preparedStatement = connection.getConnection().prepareStatement("DELETE FROM " + tableName + " WHERE key=?")) {
|
||||
preparedStatement.setString(1, key);
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void truncateTable() throws SQLException {
|
||||
connection.checkConnection();
|
||||
try(PreparedStatement preparedStatement = connection.getConnection().prepareStatement("TRUNCATE TABLE " + tableName)) {
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package fr.altarik.toolbox.database.keyValue;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* <p>Implement of a key value table, abstract the actual representation of the table and its manipulation between this interface</p>
|
||||
* @see KeyValuePostgresql
|
||||
*/
|
||||
public interface KeyValueTable {
|
||||
|
||||
/**
|
||||
* <p>Return the first value associated with the unique key.</p>
|
||||
*
|
||||
* @param key String key of associated to the value
|
||||
* @return value associated with the key
|
||||
* @throws SQLException if connection is lost
|
||||
*/
|
||||
@Nullable String getValue(String key) throws SQLException;
|
||||
|
||||
/**
|
||||
* <p>Insert a new value in the table, associated with key</p>
|
||||
*
|
||||
* @param key String key which will be associated with the value, is unique
|
||||
* @param value String value which will be stored in the database
|
||||
* @throws SQLException if connection is lost or if {@code key} is not unique (already exist in database)
|
||||
*/
|
||||
void insertValue(String key, String value) throws SQLException;
|
||||
|
||||
/**
|
||||
* <p>Update value column of the row associated with the key by {@code value}</p>
|
||||
* <p>If {@code key} doesn't exist in table, will update no row without warning</p>
|
||||
* @param key String key which will is associated with the value, is unique
|
||||
* @param value new value
|
||||
* @throws SQLException if connection is lost
|
||||
*/
|
||||
void updateValue(String key, String value) throws SQLException;
|
||||
|
||||
/**
|
||||
* <p>Delete row with having {@code key} as unique key</p>
|
||||
* <p>If key doesn't exist in database, will delete no row without warning</p>
|
||||
* @param key the key of the row to delete
|
||||
* @throws SQLException if connection is lost
|
||||
*/
|
||||
void deleteRow(String key) throws SQLException;
|
||||
|
||||
/**
|
||||
* Will delete every data inside the table
|
||||
* @throws SQLException if connection is lost
|
||||
*/
|
||||
void truncateTable() throws SQLException;
|
||||
|
||||
}
|
BIN
Database/src/main/resources/assets/database/icon.png
Normal file
BIN
Database/src/main/resources/assets/database/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
29
Database/src/main/resources/fabric.mod.json
Normal file
29
Database/src/main/resources/fabric.mod.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "toolbox-database",
|
||||
"version": "${version}",
|
||||
"name": "Database",
|
||||
"description": "",
|
||||
"authors": [
|
||||
"Altarik"
|
||||
],
|
||||
"contributors": [
|
||||
"Legot Quentin<legotquentin@gmail.com>"
|
||||
],
|
||||
"contact": {
|
||||
"homepage": "https://altarik.fr"
|
||||
},
|
||||
"license": "Altarik @ All-Rights-Reserved ",
|
||||
"icon": "assets/database/icon.png",
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"main": []
|
||||
},
|
||||
"mixins": [],
|
||||
"depends": {
|
||||
"fabricloader": "^0.14.12",
|
||||
"fabric-api": "*",
|
||||
"minecraft": "1.19.3",
|
||||
"java": ">=17"
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ class ConnectionTest {
|
||||
try(PreparedStatement statement = connection.getConnection().prepareStatement("CREATE TABLE IF NOT EXISTS toolbox(id SERIAL, PRIMARY KEY (id));")) {
|
||||
statement.executeUpdate();
|
||||
}
|
||||
connection.close();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,68 @@
|
||||
package fr.altarik.toolbox.database.keyValue;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import fr.altarik.toolbox.database.ConnectionConfig;
|
||||
import fr.altarik.toolbox.database.Connections;
|
||||
import fr.altarik.toolbox.database.SqlConnection;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class KeyValueTest {
|
||||
|
||||
@Test
|
||||
void tableTest() {
|
||||
System.out.println("Hello");
|
||||
assertDoesNotThrow(() -> {InputStream configInput = getResource("config.yml");
|
||||
String configStr = new BufferedReader(new InputStreamReader(Objects.requireNonNull(configInput)))
|
||||
.lines().collect(Collectors.joining("\n"));
|
||||
Gson gson = new Gson();
|
||||
ConnectionConfig config = gson.fromJson(configStr, ConnectionConfig.class);
|
||||
try(SqlConnection connection = Connections.newPostgresConnection(config)) {
|
||||
KeyValueTable keyValueTable = Connections.newKeyValueTable(connection, "toolbox_keyvalue");
|
||||
keyValueTable.truncateTable();
|
||||
keyValueTable.insertValue("location", "here");
|
||||
keyValueTable.insertValue("experience", "5");
|
||||
assertEquals("here", keyValueTable.getValue("location"));
|
||||
assertEquals("5", keyValueTable.getValue("experience"));
|
||||
keyValueTable.updateValue("location", "Elsewhere");
|
||||
assertEquals("Elsewhere", keyValueTable.getValue("location"));
|
||||
assertEquals("5", keyValueTable.getValue("experience"));
|
||||
keyValueTable.updateValue("experience", "10");
|
||||
assertEquals("Elsewhere", keyValueTable.getValue("location"));
|
||||
assertEquals("10", keyValueTable.getValue("experience"));
|
||||
keyValueTable.deleteRow("experience");
|
||||
assertEquals("Elsewhere", keyValueTable.getValue("location"));
|
||||
assertNull(keyValueTable.getValue("experience"));
|
||||
keyValueTable.truncateTable();
|
||||
assertNull(keyValueTable.getValue("location"));
|
||||
assertNull(keyValueTable.getValue("experience"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: 08/06/2023 Move to Core module in a toolkit class
|
||||
private InputStream getResource(String resourcePath) {
|
||||
try {
|
||||
URL url = this.getClass().getClassLoader().getResource(resourcePath);
|
||||
if(url == null)
|
||||
return null;
|
||||
|
||||
URLConnection connection = url.openConnection();
|
||||
connection.setUseCaches(false);
|
||||
return connection.getInputStream();
|
||||
} catch (IOException e){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -3,5 +3,5 @@
|
||||
"port": 5432,
|
||||
"database": "postgres",
|
||||
"username": "postgres",
|
||||
"password": "root"
|
||||
"password": "Vaubadon1"
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
plugins {
|
||||
id 'fabric-loom'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand "version": project.version
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
||||
// this fixes some edge cases with special characters not displaying correctly
|
||||
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
||||
// If Javadoc is generated, this must be specified in that task too.
|
||||
it.options.encoding = "UTF-8"
|
||||
|
||||
// The Minecraft launcher currently installs Java 8 for users, so your mod probably wants to target Java 8 too
|
||||
// JDK 9 introduced a new way of specifying this that will make sure no newer classes or methods are used.
|
||||
// We'll use that if it's available, but otherwise we'll use the older option.
|
||||
def targetVersion = 17
|
||||
if (JavaVersion.current().isJava9Compatible()) {
|
||||
it.options.release = targetVersion
|
||||
}
|
||||
}
|
@ -1,4 +1,113 @@
|
||||
package fr.altarik.toolbox.pagination;
|
||||
|
||||
import fr.altarik.toolbox.pagination.api.PageIndexOutOfBoundException;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.ClickEvent;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Formatting;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class PaginatedContent {
|
||||
|
||||
private final List<Page> pages;
|
||||
private final Text header;
|
||||
|
||||
public PaginatedContent(String header, String content) {
|
||||
this.header = buildHeader(header);
|
||||
pages = new ArrayList<>();
|
||||
List<String> secondSplit = new ArrayList<>();
|
||||
for(String elem : Stream.of(content.split("\n")).collect(Collectors.toCollection(ArrayList::new))) {
|
||||
if(elem.length() > 50) {
|
||||
secondSplit.add(elem.substring(0, 50));
|
||||
secondSplit.add(elem.substring(51, elem.length() - 1));
|
||||
} else {
|
||||
secondSplit.add(elem);
|
||||
}
|
||||
}
|
||||
List<Text> currentPage = new ArrayList<>();
|
||||
for(String elem : secondSplit) {
|
||||
if(!elem.isEmpty()) {
|
||||
currentPage.add(Text.literal(elem));
|
||||
}
|
||||
if(currentPage.size() == 8 || elem.isEmpty()) {
|
||||
pages.add(new Page(currentPage));
|
||||
currentPage = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
pages.add(new Page(currentPage));
|
||||
}
|
||||
|
||||
public PaginatedContent(@Nullable Text header, List<Text> content) {
|
||||
this.header = buildHeader(header);
|
||||
this.pages = new ArrayList<>();
|
||||
List<Text> currentPage = new ArrayList<>();
|
||||
for(Text elem : content) {
|
||||
if(elem != null)
|
||||
currentPage.add(elem);
|
||||
if(currentPage.size() == 8 || elem == null) {
|
||||
pages.add(new Page(currentPage));
|
||||
currentPage = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
pages.add(new Page(currentPage));
|
||||
}
|
||||
|
||||
private Text buildHeader(@Nullable String header) {
|
||||
int numberOfEq = (50 - (header != null ? header.length() : 0)) / 2;
|
||||
return Text.literal("=".repeat(numberOfEq) + " " + header + " " + "=".repeat(numberOfEq));
|
||||
}
|
||||
|
||||
private Text buildHeader(@Nullable Text header) {
|
||||
int numberOfEq = (50 - (header != null ? header.getString().length() : 0)) / 2;
|
||||
return Text.literal("=".repeat(numberOfEq) + " ").append(header).append(" " + "=".repeat(numberOfEq));
|
||||
}
|
||||
|
||||
public void display(ServerPlayerEntity playerEntity, int page) throws PageIndexOutOfBoundException {
|
||||
if(page >= this.pages.size()) {
|
||||
throw new PageIndexOutOfBoundException("api.pagination.page_higher_than_expected", this.pages.size(), (page + 1));
|
||||
} else if(page < 0) {
|
||||
throw new PageIndexOutOfBoundException("api.pagination.page_lower_than_0");
|
||||
} else {
|
||||
playerEntity.sendMessage(header);
|
||||
for(Text s : pages.get(page).lines) {
|
||||
playerEntity.sendMessage(s);
|
||||
}
|
||||
|
||||
playerEntity.sendMessage(buildFooter(page));
|
||||
}
|
||||
}
|
||||
|
||||
private Text buildFooter(int page) {
|
||||
String strPage = String.valueOf(page + 1);
|
||||
int numberOfEq = (46 - strPage.length()) / 2;
|
||||
MutableText left = Text.literal(" <").styled(
|
||||
style -> style
|
||||
.withColor(Formatting.YELLOW)
|
||||
.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/table page " + (page - 1)))
|
||||
);
|
||||
MutableText middle = Text.literal(" " + strPage + " ").styled(style -> style.withColor(Formatting.RESET));
|
||||
MutableText right = Text.literal("> ").styled(
|
||||
style -> style
|
||||
.withColor(Formatting.YELLOW)
|
||||
.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/table page " + (page + 1)))
|
||||
);
|
||||
return Text.literal("=".repeat(numberOfEq))
|
||||
.append(left)
|
||||
.append(middle)
|
||||
.append(right)
|
||||
.append(
|
||||
Text.literal("=".repeat(numberOfEq))
|
||||
.styled(style -> style.withColor(Formatting.RESET))
|
||||
);
|
||||
}
|
||||
|
||||
private record Page(List<Text> lines) {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,13 +19,14 @@ public class Pagination implements ModInitializer {
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> new CommandsRegister().register(dispatcher, environment.dedicated));
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> new CommandsRegister(this).register(dispatcher));
|
||||
}
|
||||
|
||||
public @NotNull PaginationApi getApi() {
|
||||
return api;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static @NotNull Pagination getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package fr.altarik.toolbox.pagination.api;
|
||||
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
public class PageIndexOutOfBoundException extends Exception {
|
||||
|
||||
private final Text text;
|
||||
|
||||
public PageIndexOutOfBoundException(String s) {
|
||||
this.text = Text.translatable(s);
|
||||
}
|
||||
|
||||
public PageIndexOutOfBoundException(String s, int size, int currentPage) {
|
||||
this.text = Text.translatable(s, size, currentPage);
|
||||
}
|
||||
|
||||
public Text getText() {
|
||||
return text;
|
||||
}
|
||||
}
|
@ -1,12 +1,16 @@
|
||||
package fr.altarik.toolbox.pagination.api;
|
||||
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface PaginationApi {
|
||||
|
||||
/**
|
||||
* <p>Create a pagination table for player, content is separated into multiple pages.<br>
|
||||
* You can separate yourself content by adding *\n\n* between two pages.</p>
|
||||
* You can separate yourself content between two pages by adding *\n\n*.</p>
|
||||
* <p>Content have a time-to-live of 15 minutes (18,000 ticks)</p>
|
||||
* @param playerEntity The player who will be able to interact and see the paginated message
|
||||
* @param content Content you want to paginate
|
||||
@ -14,12 +18,48 @@ public interface PaginationApi {
|
||||
* <p>Special values are:
|
||||
* <ul><li><b>null</b> if you doesn't want to add a header</li>
|
||||
* <li><b>empty String</b> if you want just the header to be filled only with "="</li></ul>
|
||||
* @param display true if you want the message to be displayed now, false otherwise if you want to display the
|
||||
* message yourself
|
||||
* @throws IllegalArgumentException if one of its conditions is met: <ol>
|
||||
* <li><b>header</b> length is more than 50 characters</li>
|
||||
* <li><b>content</b> is empty</li>
|
||||
* <li><b>content</b> is empty/blank</li>
|
||||
* <li><b>playerEntity</b> or <b>content</b> are null</li>
|
||||
* </ol>
|
||||
*/
|
||||
void createTable(ServerPlayerEntity playerEntity, String content, String header);
|
||||
void createTable(ServerPlayerEntity playerEntity, String content, String header, boolean display);
|
||||
|
||||
/**
|
||||
* <p>Create a pagination table for player the same way than
|
||||
* {@link PaginationApi#createTable(ServerPlayerEntity, String, String, boolean)},
|
||||
* content is separated into multiple pages.<br />
|
||||
* You can separate yourself content between 2 pages by adding a null instance of Text in content list.</p>
|
||||
* <p>Content have a time-to-live of 15 minutes (18,000 ticks)</p>
|
||||
* @param playerEntity The player who will be able to interact and see the paginated message
|
||||
* @param content Content you want to paginate
|
||||
* @param header header/title you want to add to every page, empty space is filled with "=".
|
||||
* <p>Special values are:</p>
|
||||
* <ul><li><b>null</b> if you doesn't want to add a header</li>
|
||||
* <li><b>Empty text</b>if you want just the header to be filled only with "="</li></ul>
|
||||
* @param display true if you want the message to be displayed now, false otherwise if you want to display the
|
||||
* message yourself
|
||||
* @throws IllegalArgumentException if one of its conditions is met: <ol>
|
||||
* <li><b>header</b> length is more than 50 characters</li>
|
||||
* <li><b>content</b> is empty/blank</li>
|
||||
* <li><b>playerEntity</b> or <b>content</b> are null</li>
|
||||
* </ol>
|
||||
* @see Text#empty()
|
||||
*/
|
||||
void createTable(ServerPlayerEntity playerEntity, List<Text> content, @Nullable Text header, boolean display);
|
||||
|
||||
|
||||
/**
|
||||
* Display the given page for the given player
|
||||
* @param player display the content of this player
|
||||
* @param page display this page
|
||||
* @throws IllegalArgumentException if page is invalid
|
||||
* @throws NullPointerException if player is null or paginated content for the player doesn't exist (or have expired)
|
||||
* @see fr.altarik.toolbox.pagination.PaginatedContent#display(ServerPlayerEntity, int)
|
||||
*/
|
||||
void display(ServerPlayerEntity player, int page) throws PageIndexOutOfBoundException;
|
||||
|
||||
}
|
||||
|
@ -1,18 +1,85 @@
|
||||
package fr.altarik.toolbox.pagination.api;
|
||||
|
||||
import fr.altarik.toolbox.pagination.PaginatedContent;
|
||||
import fr.altarik.toolbox.pagination.precondition.ContentCondition;
|
||||
import fr.altarik.toolbox.pagination.precondition.HeaderCondition;
|
||||
import fr.altarik.toolbox.pagination.precondition.NullPlayerCondition;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Pair;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class PaginationApiImpl implements PaginationApi {
|
||||
/**
|
||||
* Integer represent relative tts of the paginated content, decreased by 1 every seconds
|
||||
*/
|
||||
public final Map<ServerPlayerEntity, Pair<Integer, PaginatedContent>> paginatedContent = new HashMap<>();
|
||||
private final Predicate<ServerPlayerEntity> playerCondition = new NullPlayerCondition().negate();
|
||||
private final Predicate<String> headerCondition = new HeaderCondition().negate();
|
||||
private final Predicate<String> contentCondition = new ContentCondition().negate();
|
||||
|
||||
Map<ServerPlayerEntity, Pair<Integer, PaginatedContent>> paginatedContent = new HashMap<>();
|
||||
public PaginationApiImpl() {
|
||||
ServerTickEvents.START_SERVER_TICK.register(this::serverTick);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTable(ServerPlayerEntity playerEntity, String content, String header) {
|
||||
// TODO: 01/03/2023
|
||||
public void createTable(ServerPlayerEntity playerEntity, String content, String header, boolean display) {
|
||||
if(playerCondition.test(playerEntity) || headerCondition.test(header) || contentCondition.test(content)) {
|
||||
throw new IllegalArgumentException("Preconditions aren't satisfied");
|
||||
}
|
||||
PaginatedContent paginatedContent1 = new PaginatedContent(header, content);
|
||||
storeAndDisplay(playerEntity, paginatedContent1, display);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTable(ServerPlayerEntity playerEntity, List<Text> content, @Nullable Text header, boolean display) {
|
||||
if(playerCondition.test(playerEntity)) {
|
||||
throw new IllegalArgumentException("Preconditions aren't satisfied");
|
||||
}
|
||||
PaginatedContent paginatedContent1 = new PaginatedContent(header, content);
|
||||
storeAndDisplay(playerEntity, paginatedContent1, display);
|
||||
}
|
||||
|
||||
private void storeAndDisplay(ServerPlayerEntity playerEntity, PaginatedContent paginatedContent1, boolean display) {
|
||||
paginatedContent.put(playerEntity, new Pair<>(18000, paginatedContent1));
|
||||
if(display) {
|
||||
try {
|
||||
paginatedContent1.display(playerEntity, 0);
|
||||
} catch (PageIndexOutOfBoundException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void display(ServerPlayerEntity player, int page) throws PageIndexOutOfBoundException {
|
||||
if(player == null)
|
||||
throw new NullPointerException("Player is null");
|
||||
Pair<Integer, PaginatedContent> pair = paginatedContent.get(player);
|
||||
if(pair == null)
|
||||
throw new NullPointerException("No paginated page for player " + player.getCustomName());
|
||||
pair.getRight().display(player, page);
|
||||
}
|
||||
|
||||
private void serverTick(MinecraftServer server) {
|
||||
List<ServerPlayerEntity> toRemove = new ArrayList<>();
|
||||
for(Map.Entry<ServerPlayerEntity, Pair<Integer, PaginatedContent>> content : paginatedContent.entrySet()) {
|
||||
if(content.getValue().getLeft() == 0) {
|
||||
toRemove.add(content.getKey());
|
||||
} else {
|
||||
content.getValue().setLeft(content.getValue().getLeft() - 1);
|
||||
}
|
||||
}
|
||||
for(ServerPlayerEntity player : toRemove) {
|
||||
paginatedContent.remove(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,19 +2,101 @@ package fr.altarik.toolbox.pagination.command;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
||||
import fr.altarik.toolbox.pagination.Pagination;
|
||||
import fr.altarik.toolbox.pagination.api.PageIndexOutOfBoundException;
|
||||
import fr.altarik.toolbox.pagination.api.PaginationApi;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static net.minecraft.server.command.CommandManager.argument;
|
||||
import static net.minecraft.server.command.CommandManager.literal;
|
||||
|
||||
public class CommandsRegister {
|
||||
|
||||
public void register(CommandDispatcher<ServerCommandSource> dispatcher, boolean dedicated) {
|
||||
private final PaginationApi api;
|
||||
|
||||
public CommandsRegister(Pagination instance) {
|
||||
this.api = instance.getApi();
|
||||
}
|
||||
|
||||
public void register(CommandDispatcher<ServerCommandSource> dispatcher) {
|
||||
dispatcher.register(literal("table")
|
||||
.then(literal("page")
|
||||
.then(argument("page", IntegerArgumentType.integer()))
|
||||
.then(argument("page", IntegerArgumentType.integer())
|
||||
.executes(this::selectPageCommand)
|
||||
)
|
||||
).then(literal("test")
|
||||
.requires(source -> source.isExecutedByPlayer() && source.hasPermissionLevel(3))
|
||||
.executes(this::testPageCommand)
|
||||
).then(literal("testText")
|
||||
.requires(source -> source.isExecutedByPlayer() && source.hasPermissionLevel(3))
|
||||
.executes(this::testPageTextCommand)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply a debug command
|
||||
*/
|
||||
private int testPageCommand(CommandContext<ServerCommandSource> context) {
|
||||
api.createTable(context.getSource().getPlayer(), """
|
||||
first line, string version
|
||||
Second line
|
||||
|
||||
second page
|
||||
dqdq
|
||||
dqdqd
|
||||
qdqdq
|
||||
dqdq
|
||||
dqdq
|
||||
dqdq
|
||||
dqdqd
|
||||
third page
|
||||
dqdqd
|
||||
dqdqd
|
||||
d""", "My header", true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int testPageTextCommand(CommandContext<ServerCommandSource> context) {
|
||||
List<Text> content = new ArrayList<>();
|
||||
content.add(Text.literal("first line, text version"));
|
||||
content.add(Text.literal("Second line"));
|
||||
content.add(null);
|
||||
content.add(Text.literal("second page"));
|
||||
content.add(Text.literal("dqdq"));
|
||||
content.add(Text.literal("dqdqd"));
|
||||
content.add(Text.literal("dqdqd"));
|
||||
content.add(Text.literal("dqdq"));
|
||||
content.add(Text.literal("dqdq"));
|
||||
content.add(Text.literal("dqdq"));
|
||||
content.add(Text.literal("dqdqd"));
|
||||
content.add(Text.literal("third page"));
|
||||
content.add(Text.literal("dqdqd"));
|
||||
content.add(Text.literal("dqdqd"));
|
||||
api.createTable(context.getSource().getPlayer(), content, Text.literal("My Text Header"), true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int selectPageCommand(CommandContext<ServerCommandSource> context) throws CommandSyntaxException {
|
||||
try {
|
||||
int page = IntegerArgumentType.getInteger(context, "page");
|
||||
api.display(context.getSource().getPlayerOrThrow(), page);
|
||||
} catch(PageIndexOutOfBoundException e) {
|
||||
throw new CommandSyntaxException(new SimpleCommandExceptionType(e.getText()), e.getText());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private enum TestType {
|
||||
String,
|
||||
Text;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
package fr.altarik.toolbox.pagination.precondition;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* This predicate returns true if the String is not null or
|
||||
* if its content is not blank (empty or only contains whitespaces)
|
||||
*/
|
||||
public class ContentCondition implements Predicate<String> {
|
||||
@Override
|
||||
public boolean test(String s) {
|
||||
return s != null && !s.isBlank();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package fr.altarik.toolbox.pagination.precondition;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* This predicate returns true if its length doesn't exceed 50 characters.
|
||||
*/
|
||||
public class HeaderCondition implements Predicate<String> {
|
||||
@Override
|
||||
public boolean test(String header) {
|
||||
return header.length() <= 50;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package fr.altarik.toolbox.pagination.precondition;
|
||||
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* This predicate returns true if the player isn't null, false otherwise
|
||||
*/
|
||||
public class NullPlayerCondition implements Predicate<ServerPlayerEntity> {
|
||||
@Override
|
||||
public boolean test(ServerPlayerEntity player) {
|
||||
return player != null;
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"api.pagination.page_lower_than_0": "argument page is lower than 0",
|
||||
"api.pagination.page_higher_than_expected": "There's %d paginated pages but you wanted page n°%d"
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "pagination",
|
||||
"id": "toolbox-pagination",
|
||||
"version": "${version}",
|
||||
"name": "Task",
|
||||
"name": "Pagination",
|
||||
"description": "A mod to use to paginate long result to player in chat",
|
||||
"authors": [
|
||||
"Altarik"
|
||||
|
@ -1,36 +0,0 @@
|
||||
plugins {
|
||||
id 'fabric-loom'
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand "version": project.version
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
||||
// this fixes some edge cases with special characters not displaying correctly
|
||||
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
||||
// If Javadoc is generated, this must be specified in that task too.
|
||||
it.options.encoding = "UTF-8"
|
||||
|
||||
// The Minecraft launcher currently installs Java 8 for users, so your mod probably wants to target Java 8 too
|
||||
// JDK 9 introduced a new way of specifying this that will make sure no newer classes or methods are used.
|
||||
// We'll use that if it's available, but otherwise we'll use the older option.
|
||||
def targetVersion = 17
|
||||
if (JavaVersion.current().isJava9Compatible()) {
|
||||
it.options.release = targetVersion
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "task",
|
||||
"id": "toolbox-task",
|
||||
"version": "${version}",
|
||||
"name": "Task",
|
||||
"description": "A mod to use as a dependency for others to schedule tasks",
|
||||
|
52
build.gradle
52
build.gradle
@ -1,11 +1,13 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'fabric-loom' version '1.1-SNAPSHOT' apply false
|
||||
id 'fabric-loom' version '1.2-SNAPSHOT' apply false
|
||||
}
|
||||
|
||||
Properties local = new Properties()
|
||||
local.load(new FileInputStream(rootProject.file("local.properties")))
|
||||
|
||||
allprojects {
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'fabric-loom'
|
||||
|
||||
group = project.maven_group
|
||||
version = project.maven_version
|
||||
@ -34,25 +36,50 @@ allprojects {
|
||||
mavenJava(MavenPublication) {
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
name 'altarik'
|
||||
url 'https://repo.altarik.fr/'.concat(project.version.endsWith('SNAPSHOT') ? 'snapshots/' : 'releases/')
|
||||
credentials {
|
||||
username = project.repo_username
|
||||
password = project.repo_password
|
||||
username = System.getProperty("REPO_USERNAME", local.getProperty("repo_username"))
|
||||
password = System.getProperty("REPO_PASSWORD", local.getProperty("repo_password"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subprojects {
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand "version": project.version
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
||||
// this fixes some edge cases with special characters not displaying correctly
|
||||
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
||||
// If Javadoc is generated, this must be specified in that task too.
|
||||
it.options.encoding = "UTF-8"
|
||||
|
||||
// The Minecraft launcher currently installs Java 8 for users, so your mod probably wants to target Java 8 too
|
||||
// JDK 9 introduced a new way of specifying this that will make sure no newer classes or methods are used.
|
||||
// We'll use that if it's available, but otherwise we'll use the older option.
|
||||
def targetVersion = 17
|
||||
if (JavaVersion.current().isJava9Compatible()) {
|
||||
it.options.release = targetVersion
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api:${project.junit_version}"
|
||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${project.junit_version}"
|
||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||
}
|
||||
|
||||
java {
|
||||
@ -66,11 +93,16 @@ subprojects {
|
||||
|
||||
}
|
||||
|
||||
jar {
|
||||
dependencies {
|
||||
include subprojects.collect { project -> project }
|
||||
implementation subprojects.collect { project -> project }
|
||||
}
|
||||
|
||||
/*jar {
|
||||
dependsOn subprojects.jar
|
||||
subprojects.each { project ->
|
||||
from(project.jar) {
|
||||
into("META-INF/jars/")
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
@ -1,4 +1,4 @@
|
||||
org.gradle.jvmargs=-Xmx4G
|
||||
org.gradle.jvmargs=-Xmx2G
|
||||
|
||||
|
||||
junit_version=5.9.0
|
||||
@ -8,6 +8,5 @@ loader_version=0.14.14
|
||||
fabric_version=0.75.1+1.19.3
|
||||
|
||||
maven_group=fr.altarik.toolbox
|
||||
maven_version=4.0.0-SNAPSHOT
|
||||
maven_version=4.1.0-SNAPSHOT
|
||||
repo_username=Altarik
|
||||
repo_password=password
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@ -10,4 +10,7 @@ pluginManagement {
|
||||
}
|
||||
|
||||
rootProject.name = 'Toolbox'
|
||||
include(':Tasks', ':Database', /* ':Pagination' */)
|
||||
include(':Tasks')
|
||||
include(':Database')
|
||||
include(':Pagination')
|
||||
include(':Core')
|
||||
|
BIN
src/main/resources/assets/toolbox/icon.png
Normal file
BIN
src/main/resources/assets/toolbox/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
@ -14,13 +14,17 @@
|
||||
"homepage": "https://altarik.fr"
|
||||
},
|
||||
"license": "Altarik @ All-Rights-Reserved ",
|
||||
"icon": "assets/quests/icon.png",
|
||||
"icon": "assets/toolbox/icon.png",
|
||||
"environment": "*",
|
||||
"depends": {
|
||||
"fabricloader": "^0.14.12",
|
||||
"fabric-api": "*",
|
||||
"minecraft": "1.19.3",
|
||||
"java": ">=17"
|
||||
"java": ">=17",
|
||||
"toolbox-core": "${version}",
|
||||
"toolbox-database": "${version}",
|
||||
"toolbox-pagination": "${version}",
|
||||
"toolbox-task": "${version}"
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user