Skip to content

Commit

Permalink
Merge branch 'WiIIiam278:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
MSCMDD authored Feb 13, 2024
2 parents 6625ba8 + 2c860ec commit b19e9f2
Show file tree
Hide file tree
Showing 40 changed files with 1,031 additions and 376 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Requires Java 17+ and a Minecraft 1.17.1+ Spigot-based server. A MySQL database
3. Navigate to the HuskTowns config file on each server (`~/plugins/HuskTowns/config.yml`)
4. Configure the plugin to your liking. If you are running HuskTowns across multiple servers, enable `cross_server` mode and fill in your MySQL credentials, remembering to change the database type to `MYSQL` as well.
5. You can also modify the level requirements in `~/levels.yml`, the default town rule settings in `~/rules.yml` and the town roles in `~/roles.yml`
6. Start every server again and HuskTowns should have completed installation!
6. Start every server again and HuskTowns should have completed installation!

## Development
To build HuskTowns, simply run the following in the root of the repository:
Expand Down
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ allprojects {
}

dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.1'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.1'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.1'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.2'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.2'
}

test {
Expand Down
2 changes: 1 addition & 1 deletion bukkit/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ dependencies {
compileOnly 'me.clip:placeholderapi:2.11.5'
compileOnly 'net.luckperms:api:5.4'

testImplementation 'com.github.seeseemelk:MockBukkit-v1.17:1.12.0'
testImplementation 'com.github.seeseemelk:MockBukkit-v1.17:1.13.0'
testImplementation 'de.themoep:minedown-adventure:1.7.2-SNAPSHOT'
testImplementation 'net.kyori:adventure-platform-bukkit:4.3.2'
testImplementation 'org.apache.commons:commons-text:1.11.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
package net.william278.husktowns;

import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
import lombok.AccessLevel;
import lombok.Getter;
Expand Down Expand Up @@ -94,7 +92,7 @@ public class BukkitHuskTowns extends JavaPlugin implements HuskTowns, BukkitTask
private final Map<UUID, Deque<Invite>> invites = Maps.newConcurrentMap();
private final Map<UUID, Preferences> userPreferences = Maps.newConcurrentMap();
private final Map<UUID, Visualizer> visualizers = Maps.newConcurrentMap();
private final Multimap<String, User> globalUserList = Multimaps.newListMultimap(Maps.newConcurrentMap(), ArrayList::new);
private final Map<String, List<User>> globalUserList = Maps.newConcurrentMap();
private final Validator validator = new Validator(this);
@Setter
private boolean loaded = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import be.seeseemelk.mockbukkit.ServerMock;
import com.google.common.collect.ImmutableList;
import net.william278.husktowns.audit.Action;
import net.william278.husktowns.audit.Log;
import net.william278.husktowns.claim.*;
import net.william278.husktowns.map.MapSquare;
import net.william278.husktowns.town.Town;
Expand Down Expand Up @@ -334,7 +335,7 @@ private static Stream<Arguments> getTownAndMayorParameters() {
@Order(5)
@Nested
@DisplayName("Town Schema Update Tests")
public class TownSchemaUpdateTests {
public class TownSchemaTests {

@Order(1)
@DisplayName("Test Town Schema Update")
Expand All @@ -351,6 +352,24 @@ public void testTownSchemaUpdate() {
);
}

@Order(2)
@DisplayName("Test Deserializing Town Log with Duplicate Keys")
@Test
public void testTownLogSerialization() {
final String logJson = """
{
"actions": {
"2024-02-04T15:09:34.661609Z": { "action": "CREATE_TOWN" },
"2024-02-04T15:09:34.661609Z": { "action": "CREATE_TOWN" }
}
}""";
final Log log = plugin.getGson().fromJson(logJson, Log.class);
Assertions.assertNotNull(log, "Failed to deserialize log with duplicate keys");

final Map<OffsetDateTime, Action> actions = log.getActions();
Assertions.assertEquals(1, actions.size(), "Duplicate keys were not removed on load");
}

}

@NotNull
Expand Down
1 change: 0 additions & 1 deletion common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ dependencies {
api 'net.william278:DesertWell:2.0.4'
api 'net.william278.cloplib:cloplib-common:1.0.1'
api 'com.google.code.gson:gson:2.10.1'
api 'com.fatboyindustrial.gson-javatime-serialisers:gson-javatime-serialisers:1.1.2'
api 'com.github.Exlll.ConfigLib:configlib-yaml:v4.4.0'
api('com.zaxxer:HikariCP:5.1.0') {
exclude module: 'slf4j-api'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
import java.util.logging.Level;
import java.util.stream.Collectors;

public interface HuskTowns extends Task.Supplier, ConfigProvider, EventDispatcher, GlobalUserList,
public interface HuskTowns extends Task.Supplier, ConfigProvider, EventDispatcher, UserListProvider,
AdvancementProvider, DataPruner, GsonProvider, OperationHandler, UserListener {

int SPIGOT_RESOURCE_ID = 92672;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import net.william278.husktowns.claim.*;
import net.william278.husktowns.map.ClaimMap;
import net.william278.husktowns.town.Member;
import net.william278.husktowns.town.Privilege;
import net.william278.husktowns.town.Town;
import net.william278.husktowns.user.OnlineUser;
import net.william278.husktowns.user.Preferences;
Expand Down Expand Up @@ -262,6 +263,18 @@ public Optional<TownClaim> getClaimAt(@NotNull Chunk chunk, @NotNull World world
return plugin.getClaimAt(chunk, world);
}

/**
* Get whether a claim exists at a {@link Chunk} in a {@link World}
*
* @param chunk The {@link Chunk} to check
* @param world The {@link World} the {@link Chunk} is in
* @return Whether a claim exists at the chunk in the world
* @since 3.0
*/
public boolean isClaimAt(@NotNull Chunk chunk, @NotNull World world) {
return plugin.getClaimAt(chunk, world).isPresent();
}

/**
* Get a {@link TownClaim} at a {@link Position}, if it exists.
*
Expand All @@ -273,6 +286,17 @@ public Optional<TownClaim> getClaimAt(@NotNull Position position) {
return plugin.getClaimAt(position);
}

/**
* Get whether a claim exists at a {@link Position}
*
* @param position The {@link Position} to check
* @return Whether a claim exists at the position
* @since 3.0
*/
public boolean isClaimAt(@NotNull Position position) {
return plugin.getClaimAt(position).isPresent();
}

/**
* Create a claim for a town
*
Expand Down Expand Up @@ -601,7 +625,7 @@ public Component getClaimMapComponent(@NotNull Position position) {
}

/**
* Get whether an {@link Operation} is allowed
* Get whether an {@link Operation} should be allowed to occur.
*
* @param operation The {@link Operation} to check against
* @return Whether the {@link Operation} would be allowed
Expand All @@ -613,6 +637,46 @@ public boolean isOperationAllowed(@NotNull Operation operation) {
return !plugin.cancelOperation(operation);
}


/**
* Get whether an {@link Operation}, consisting of an {@link OnlineUser}, {@link OperationType} and
* {@link Position}, should be allowed to occur.
*
* @param user the user
* @param type the operation type
* @param position the position of the operation
* @return {@code true} if the operation is allowed, else {@code false}
*/
public boolean isOperationAllowed(@NotNull OnlineUser user, @NotNull OperationType type,
@NotNull Position position) {
return isOperationAllowed(Operation.of(user, type, position));
}

/**
* Get whether an {@link Operation}, consisting of a {@link Position} and {@link OperationType}, should be allowed
* to occur.
*
* @param position the position of the operation
* @param type the operation type
* @return {@code true} if the operation is allowed, else {@code false}
* @since 1.0
*/
public boolean isOperationAllowed(@NotNull Position position, @NotNull OperationType type) {
return isOperationAllowed(Operation.of(type, position));
}

/**
* Returns whether a {@link User} can exercise a {@link Privilege}.
*
* @param privilege the privilege
* @param user the user
* @return {@code true} if the user can exercise the privilege in the claim, else {@code false}
* @since 3.0
*/
public boolean isPrivilegeAllowed(@NotNull Privilege privilege, @NotNull User user) {
return getUserTown(user).map(m -> m.hasPrivilege(plugin, privilege)).orElse(false);
}

/**
* Get a {@link Town} by its ID.
*
Expand Down
18 changes: 6 additions & 12 deletions common/src/main/java/net/william278/husktowns/audit/Action.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
package net.william278.husktowns.audit;

import com.google.gson.annotations.Expose;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import net.william278.husktowns.user.User;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand All @@ -30,26 +32,18 @@
/**
* Represents a {@link Log logged} action that was performed on a {@link net.william278.husktowns.town.Town}
*/
@AllArgsConstructor
@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE)
public class Action {

@Expose
private Type action;
@Expose
@Nullable
private User user;
@Expose
@Nullable
private String details;
@Expose
private Type action;

private Action(@NotNull Type action, @Nullable User user, @Nullable String details) {
this.action = action;
this.user = user;
this.details = details;
}

@SuppressWarnings("unused")
private Action() {
}

/**
* Return a new {@code Action} for a given {@link Type} and {@link User}
Expand Down
49 changes: 22 additions & 27 deletions common/src/main/java/net/william278/husktowns/audit/Log.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,27 @@

import com.google.common.collect.Maps;
import com.google.gson.annotations.Expose;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import net.william278.husktowns.user.User;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable;

import java.time.OffsetDateTime;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
* Represents the audit log of actions taken in a {@link net.william278.husktowns.town.Town}
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Log {

@Expose
private Map<String, Action> actions;

private Log(@NotNull Map<OffsetDateTime, Action> actions) {
this.actions = new TreeMap<>();
actions.forEach((key, value) -> this.actions.put(key.toString(), value));
}
// Format used for storing map timestamps
private static final DateTimeFormatter FORMAT = DateTimeFormatter.ISO_OFFSET_DATE_TIME;

@SuppressWarnings("unused")
private Log() {
}
@Expose
private Map<String, Action> actions = Maps.newLinkedHashMap();

/**
* Create a new Log instance for a newly created town
Expand All @@ -56,7 +53,7 @@ private Log() {
*/
@NotNull
public static Log newTownLog(@NotNull User creator) {
final Log log = new Log(new TreeMap<>());
final Log log = new Log();
log.log(Action.of(creator, Action.Type.CREATE_TOWN));
return log;
}
Expand All @@ -68,7 +65,7 @@ public static Log newTownLog(@NotNull User creator) {
*/
@NotNull
public static Log empty() {
return new Log(new TreeMap<>());
return new Log();
}

/**
Expand All @@ -82,8 +79,8 @@ public static Log empty() {
*/
@NotNull
public static Log migratedLog(@NotNull OffsetDateTime foundedTime) {
final Log log = new Log(Maps.newTreeMap());
log.actions.put(foundedTime.toString(), Action.of(Action.Type.CREATE_TOWN));
final Log log = new Log();
log.actions.put(foundedTime.format(FORMAT), Action.of(Action.Type.CREATE_TOWN));
log.log(Action.of(Action.Type.TOWN_DATA_MIGRATED));
return log;
}
Expand All @@ -95,7 +92,7 @@ public static Log migratedLog(@NotNull OffsetDateTime foundedTime) {
* @apiNote The action will be logged as having occurred just now
*/
public void log(@NotNull Action action) {
this.actions.putIfAbsent(OffsetDateTime.now().toString(), action);
this.actions.putIfAbsent(OffsetDateTime.now().format(FORMAT), action);
}

/**
Expand All @@ -104,12 +101,11 @@ public void log(@NotNull Action action) {
* @return the map of actions to when they occurred
*/
@NotNull
@Unmodifiable
public Map<OffsetDateTime, Action> getActions() {
return actions.entrySet().stream().collect(
TreeMap::new,
(m, e) -> m.put(OffsetDateTime.parse(e.getKey()), e.getValue()),
Map::putAll
);
final Map<OffsetDateTime, Action> parsed = Maps.newLinkedHashMap();
actions.forEach((key, value) -> parsed.put(OffsetDateTime.parse(key, FORMAT), value));
return parsed;
}

/**
Expand All @@ -121,9 +117,8 @@ public Map<OffsetDateTime, Action> getActions() {
public OffsetDateTime getFoundedTime() {
return getActions().entrySet().stream()
.filter(entry -> entry.getValue().getType() == Action.Type.CREATE_TOWN)
.findFirst()
.map(Map.Entry::getKey)
.orElse(OffsetDateTime.now());
.findFirst().orElse(OffsetDateTime.now());
}

/**
Expand All @@ -134,8 +129,8 @@ public OffsetDateTime getFoundedTime() {
public Optional<OffsetDateTime> getLastWarTime() {
return getActions().entrySet().stream()
.filter(entry -> entry.getValue().getType() == Action.Type.START_WAR)
.findFirst()
.map(Map.Entry::getKey);
.map(Map.Entry::getKey)
.max(OffsetDateTime::compareTo);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Claim {

@Expose
Expand All @@ -44,10 +47,6 @@ private Claim(@NotNull Chunk chunk, @NotNull Type type, @Nullable Map<UUID, Bool
this.plotMembers = type == Type.PLOT ? plotMembers : null;
}

@SuppressWarnings("unused")
private Claim() {
}

@NotNull
public static Claim at(@NotNull Chunk chunk) {
return new Claim(chunk, Type.CLAIM, null);
Expand Down
Loading

0 comments on commit b19e9f2

Please sign in to comment.