Skip to content

Commit 09db6df

Browse files
authored
Merge pull request #476 from liquiddevelopmentnet/min-xp
Change minimum xp for daily removal to 1
2 parents bc80839 + 8af2ac3 commit 09db6df

File tree

5 files changed

+157
-7
lines changed

5 files changed

+157
-7
lines changed

src/main/java/net/discordjug/javabot/data/config/guild/HelpConfig.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,17 @@ public class HelpConfig extends GuildConfigItem {
116116
private double thankExperience = 3;
117117

118118
/**
119-
* The amount that should be subtracted from every Help Account each day.
119+
* The minimum total amount of XP that should be subtracted from every Help Account each day.
120+
*/
121+
private int minDailyExperienceSubtraction = 1;
122+
123+
/**
124+
* The maximum total amount of XP that should be subtracted from every Help Account each day.
125+
*/
126+
private int maxDailyExperienceSubtraction = 50;
127+
128+
/**
129+
* The percentage of XP that should be subtracted from every Help Account each day.
120130
*/
121131
private double dailyExperienceSubtraction = 5;
122132

src/main/java/net/discordjug/javabot/data/h2db/DbHelper.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,13 @@ private static boolean shouldInitSchema(String jdbcUrl) {
9999
return shouldInitSchema;
100100
}
101101

102-
private static void initializeSchema(HikariDataSource dataSource) throws IOException, SQLException {
102+
/**
103+
* Initializes the schema of the database by running all SQL statements from the schema.sql script.
104+
* @param dataSource the {@link DataSource} to connect to the DB
105+
* @throws IOException if an error happened while loading the schema.sql
106+
* @throws SQLException if any SQL error happened
107+
*/
108+
public static void initializeSchema(DataSource dataSource) throws IOException, SQLException {
103109
try (InputStream is = DbHelper.class.getClassLoader().getResourceAsStream("database/schema.sql")) {
104110
if (is == null) throw new IOException("Could not load schema.sql.");
105111
List<String> queries = Arrays.stream(new String(is.readAllBytes()).split(";"))

src/main/java/net/discordjug/javabot/systems/help/HelpExperienceJob.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import lombok.RequiredArgsConstructor;
44
import net.discordjug.javabot.data.config.BotConfig;
5+
import net.discordjug.javabot.data.config.guild.HelpConfig;
56
import net.discordjug.javabot.data.h2db.DbHelper;
67
import net.discordjug.javabot.systems.help.dao.HelpAccountRepository;
78
import net.discordjug.javabot.util.ExceptionLogger;
@@ -31,9 +32,12 @@ public class HelpExperienceJob {
3132
public void execute() {
3233
asyncPool.execute(() -> {
3334
try {
35+
// just get the config for the first guild the bot is in, as it's not designed to work in multiple guilds anyway
36+
HelpConfig helpConfig = botConfig.get(jda.getGuilds().get(0)).getHelpConfig();
3437
helpAccountRepository.removeExperienceFromAllAccounts(
35-
// just get the config for the first guild the bot is in, as it's not designed to work in multiple guilds anyway
36-
botConfig.get(jda.getGuilds().get(0)).getHelpConfig().getDailyExperienceSubtraction(), 5, 50);
38+
helpConfig.getDailyExperienceSubtraction(),
39+
helpConfig.getMinDailyExperienceSubtraction(),
40+
helpConfig.getMaxDailyExperienceSubtraction());
3741
} catch (DataAccessException e) {
3842
ExceptionLogger.capture(e, DbHelper.class.getSimpleName());
3943
}

src/main/java/net/discordjug/javabot/systems/help/dao/HelpAccountRepository.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import lombok.RequiredArgsConstructor;
44
import lombok.extern.slf4j.Slf4j;
5-
import net.discordjug.javabot.data.config.BotConfig;
65
import net.discordjug.javabot.systems.help.model.HelpAccount;
76

87
import org.jetbrains.annotations.NotNull;
@@ -26,7 +25,6 @@
2625
@Repository
2726
public class HelpAccountRepository {
2827
private final JdbcTemplate jdbcTemplate;
29-
private final BotConfig botConfig;
3028

3129
/**
3230
* Inserts a new {@link HelpAccount}.
@@ -105,7 +103,7 @@ public int getTotalAccounts() throws DataAccessException {
105103
* @throws DataAccessException If an error occurs.
106104
*/
107105
public void removeExperienceFromAllAccounts(double change, int min, int max) throws DataAccessException {
108-
long rows = jdbcTemplate.execute("UPDATE help_account SET experience = GREATEST(experience - LEAST(GREATEST(experience * (? / 100), ?), ?), 0)",new CallableStatementCallback<Long>() {
106+
long rows = jdbcTemplate.execute("UPDATE help_account SET experience = GREATEST(experience - LEAST(GREATEST((experience * ?) / 100, ?), ?), 0)",new CallableStatementCallback<Long>() {
109107

110108
@Override
111109
public Long doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package net.discordjug.javabot.systems.help;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertTrue;
6+
7+
import java.io.IOException;
8+
import java.sql.SQLException;
9+
10+
import org.junit.jupiter.api.AfterEach;
11+
import org.junit.jupiter.api.BeforeEach;
12+
import org.junit.jupiter.api.Test;
13+
import org.springframework.boot.jdbc.DataSourceBuilder;
14+
import org.springframework.jdbc.core.JdbcTemplate;
15+
16+
import com.zaxxer.hikari.HikariDataSource;
17+
18+
import net.discordjug.javabot.data.h2db.DbHelper;
19+
import net.discordjug.javabot.systems.help.dao.HelpAccountRepository;
20+
import net.discordjug.javabot.systems.help.model.HelpAccount;
21+
22+
/**
23+
* Tests functionality of automated experience subtraction.
24+
*/
25+
public class HelpExperienceSubtractionTest {
26+
27+
private HikariDataSource dataSource;
28+
private HelpAccountRepository repo;
29+
30+
@BeforeEach
31+
void setUp() throws IOException, SQLException {
32+
dataSource = DataSourceBuilder.create()
33+
.type(HikariDataSource.class)
34+
.url("jdbc:h2:mem:test")
35+
.username("test")
36+
.password("")
37+
.build();
38+
39+
DbHelper.initializeSchema(dataSource);
40+
41+
JdbcTemplate template = new JdbcTemplate(dataSource);
42+
repo = new HelpAccountRepository(template);
43+
}
44+
45+
@AfterEach
46+
void cleanUp() {
47+
dataSource.close();
48+
}
49+
50+
/**
51+
* If a user has less XP than the minimum experience subtraction, the user should lose all XP.
52+
*/
53+
@Test
54+
void testUserHasLessThanMinimum() {
55+
repo.insert(new HelpAccount(1, 1));
56+
repo.removeExperienceFromAllAccounts(50, 2, 10);
57+
assertEquals(0, repo.getByUserId(1).get().getExperience());
58+
}
59+
60+
/**
61+
* If the XP to subtract is less than the minimum, the minimum XP should be subtracted.
62+
*/
63+
@Test
64+
void testSubtractMinimum() {
65+
repo.insert(new HelpAccount(1, 6));//6XP
66+
//would remove 50% i.e. 3XP
67+
//the minimum is 4XP hence it should subtract 4XP
68+
repo.removeExperienceFromAllAccounts(50, 4, 10);
69+
assertEquals(2, repo.getByUserId(1).get().getExperience());
70+
}
71+
72+
@Test
73+
void testSubtractMaximum() {
74+
repo.insert(new HelpAccount(1, 100));
75+
//tries to subtract 50% which is 50XP
76+
//but maximum is 10XP hence it should subtract 10XP
77+
repo.removeExperienceFromAllAccounts(50, 1, 10);
78+
assertEquals(90, repo.getByUserId(1).get().getExperience());
79+
}
80+
81+
@Test
82+
void testFraction() {
83+
repo.insert(new HelpAccount(1, 100));
84+
//subtract 10% i.e. 10XP
85+
//should be inside [1,50] hence neither minimum nor maximum is active
86+
repo.removeExperienceFromAllAccounts(10, 1, 50);
87+
assertEquals(90, repo.getByUserId(1).get().getExperience());
88+
//subtract 10% i.e. 9XP
89+
//should be inside [1,50] hence neither minimum nor maximum is active
90+
repo.removeExperienceFromAllAccounts(10, 1, 50);
91+
assertEquals(81, repo.getByUserId(1).get().getExperience());
92+
}
93+
94+
@Test
95+
void testXPHalfLife() {
96+
int startXP = 1_000;
97+
int half = startXP/2;
98+
repo.insert(new HelpAccount(1, startXP));
99+
for (int i = 0; i < 55; i++) {
100+
repo.removeExperienceFromAllAccounts(1.25, 0, 1_000);
101+
double actualXP = repo.getByUserId(1).get().getExperience();
102+
assertTrue(actualXP > half, "In iteration "+i+", XP have decayed by more than 50%, user has "+actualXP+"XP after iteration");
103+
}
104+
repo.removeExperienceFromAllAccounts(1.25, 0, 1_000);
105+
double actualXP = repo.getByUserId(1).get().getExperience();
106+
assertFalse(actualXP > half, "After all iterations, XP have not decayed by more than 50%, user has "+actualXP+"XP at the end");
107+
}
108+
109+
@Test
110+
void testMultipleUsers() {
111+
repo.insert(new HelpAccount(79, 79));//below min
112+
repo.insert(new HelpAccount(80, 80));//exactly min
113+
repo.insert(new HelpAccount(100, 100));//within bounds
114+
repo.insert(new HelpAccount(2_000, 2_000));//within bounds
115+
repo.insert(new HelpAccount(3_999, 3_999));//close to upper bound
116+
repo.insert(new HelpAccount(4_000, 4_000));//exactly upper bound
117+
repo.insert(new HelpAccount(4_001, 4_001));//exceeds upper bound
118+
repo.insert(new HelpAccount(10_000, 10_000));//significantly exceeds upper bound
119+
120+
repo.removeExperienceFromAllAccounts(1.25, 1, 50);
121+
122+
double delta = 0.0001;//required precision
123+
assertEquals(78, repo.getByUserId(79).get().getExperience(), delta);
124+
assertEquals(79, repo.getByUserId(80).get().getExperience(), delta);
125+
assertEquals(98.75, repo.getByUserId(100).get().getExperience(), delta);
126+
assertEquals(1975, repo.getByUserId(2_000).get().getExperience(), delta);
127+
assertEquals(3949.0125, repo.getByUserId(3_999).get().getExperience(), delta);
128+
assertEquals(3950, repo.getByUserId(4_000).get().getExperience(), delta);
129+
assertEquals(3951, repo.getByUserId(4_001).get().getExperience(), delta);
130+
assertEquals(9_950, repo.getByUserId(10_000).get().getExperience(), delta);
131+
}
132+
}

0 commit comments

Comments
 (0)