Skip to content

Commit

Permalink
Add revision for vote comments and optimize code
Browse files Browse the repository at this point in the history
  • Loading branch information
ustc-zzzz committed Sep 29, 2024
1 parent bb7d5de commit 5be9c84
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 171 deletions.
36 changes: 18 additions & 18 deletions src/main/java/org/teacon/voteme/item/VoterItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,25 +70,25 @@ private VoterItem(Properties properties) {

@Override
public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<Component> tooltip, TooltipFlag tooltipFlag) {
UUID artifactID = stack.get(ArtifactID.INSTANCE);
Optional<VoteArtifactNames> artifactNames = VoteArtifactNames.effective();
if (artifactNames.isPresent() && artifactID != null && !artifactNames.get().getName(artifactID).isEmpty()) {
MutableComponent artifactText = artifactNames.get().toText(artifactID).withStyle(ChatFormatting.GREEN);
tooltip.add(Component.translatable("gui.voteme.voter.current_artifact_hint", artifactText).withStyle(ChatFormatting.GRAY));
if (!VoteCategoryHandler.getIds().isEmpty()) {
tooltip.add(Component.empty());
}
for (ResourceLocation categoryID : VoteCategoryHandler.getIds()) {
Optional<VoteCategory> categoryOptional = VoteCategoryHandler.getCategory(categoryID);
if (categoryOptional.isPresent()) {
Component categoryName = categoryOptional.get().name;
MutableComponent categoryText = Component.empty().append(categoryName).withStyle(ChatFormatting.YELLOW);
tooltip.add(Component.translatable("gui.voteme.counter.category_hint", categoryText).withStyle(ChatFormatting.GRAY));
}
UUID artifactID = stack.get(ArtifactID.INSTANCE);
Optional<VoteArtifactNames> artifactNames = VoteArtifactNames.effective();
if (artifactNames.isPresent() && artifactID != null && !artifactNames.get().getName(artifactID).isEmpty()) {
MutableComponent artifactText = artifactNames.get().toText(artifactID).withStyle(ChatFormatting.GREEN);
tooltip.add(Component.translatable("gui.voteme.voter.current_artifact_hint", artifactText).withStyle(ChatFormatting.GRAY));
if (!VoteCategoryHandler.getIds().isEmpty()) {
tooltip.add(Component.empty());
}
for (ResourceLocation categoryID : VoteCategoryHandler.getIds()) {
Optional<VoteCategory> categoryOptional = VoteCategoryHandler.getCategory(categoryID);
if (categoryOptional.isPresent()) {
Component categoryName = categoryOptional.get().name;
MutableComponent categoryText = Component.empty().append(categoryName).withStyle(ChatFormatting.YELLOW);
tooltip.add(Component.translatable("gui.voteme.counter.category_hint", categoryText).withStyle(ChatFormatting.GRAY));
}
} else {
tooltip.add(Component.translatable("gui.voteme.voter.empty_artifact_hint").withStyle(ChatFormatting.GRAY));
}
} else {
tooltip.add(Component.translatable("gui.voteme.voter.empty_artifact_hint").withStyle(ChatFormatting.GRAY));
}
}

@Override
Expand Down Expand Up @@ -136,7 +136,7 @@ public Component getName(ItemStack stack) {

public ItemStack copyFrom(int voterSize, ItemStack stack) {
ItemStack result = new ItemStack(this, voterSize);
result.copyFrom(stack, ArtifactID.INSTANCE);
result.set(ArtifactID.INSTANCE, stack.get(ArtifactID.INSTANCE));
return result;
}
}
3 changes: 1 addition & 2 deletions src/main/java/org/teacon/voteme/screen/VoterScreen.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.teacon.voteme.network.ShowVoterPacket;
import org.teacon.voteme.network.SubmitCommentPacket;
import org.teacon.voteme.network.SubmitVotePacket;
import org.teacon.voteme.network.VoteMePacketManager;

import javax.annotation.ParametersAreNonnullByDefault;
import java.util.*;
Expand Down Expand Up @@ -294,7 +293,7 @@ public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, doubl
}

@Override
public void onClick(double mouseX, double mouseY) {
public void onClick(double mouseX, double mouseY, int button) {
double dx = mouseX - this.getX(), dy = mouseY - this.getY();
if (dx >= 192 && dy >= this.slideCenter + this.halfSliderHeight) {
this.changeSlideCenter(this.slideCenter + 1);
Expand Down
25 changes: 11 additions & 14 deletions src/main/java/org/teacon/voteme/sync/AnnouncementSerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,30 +37,32 @@ public final class AnnouncementSerializer {
private static final String KEY_DISABLED = "Disabled";
private static final String KEY_LEVEL = "Level";
private static final String KEY_LEVEL_COUNTS = "LevelCounts";
private static final String KEY_REVISION = "Revision";
private static final String KEY_VOTER = "VoterUUID";
private static final String KEY_VOTE_ROLE = "VoteRole";
private static final String KEY_VOTE_ROLES = "VoteRoles";
private static final String KEY_VOTE_TIME = "VoteTime";

public static Optional<CompoundTag> serialize(Announcement announcement) {
try {
CompoundTag nbt = new CompoundTag();
if (announcement instanceof Artifact artifact) {
CompoundTag nbt = new CompoundTag();
switch (announcement) {
case Artifact artifact -> {
nbt.putString(KEY_ANNOUNCEMENT, ARTIFACT);
nbt.putUUID(KEY_ARTIFACT, artifact.key().artifactID());
nbt.putString(KEY_ARTIFACT_NAME, artifact.name());
artifact.alias().ifPresent(alias -> nbt.putString(KEY_ALIAS, alias));
return Optional.of(nbt);
}
if (announcement instanceof Comments comments) {
case Comments comments -> {
nbt.putString(KEY_ANNOUNCEMENT, COMMENTS);
nbt.putUUID(KEY_ARTIFACT, comments.key().artifactID());
nbt.putUUID(KEY_VOTER, comments.key().voterID());
nbt.putInt(KEY_REVISION, comments.key().revision());
nbt.put(KEY_COMMENTS, Util.make(new ListTag(), tag -> comments
.comments().forEach(c -> tag.add(StringTag.valueOf(c)))));
return Optional.of(nbt);
}
if (announcement instanceof Vote vote) {
case Vote vote -> {
nbt.putString(KEY_ANNOUNCEMENT, VOTE);
nbt.putUUID(KEY_ARTIFACT, vote.key().artifactID());
nbt.putString(KEY_CATEGORY, vote.key().categoryID().toString());
Expand All @@ -71,26 +73,21 @@ public static Optional<CompoundTag> serialize(Announcement announcement) {
nbt.putLong(KEY_VOTE_TIME, vote.time().toEpochMilli());
return Optional.of(nbt);
}
if (announcement instanceof VoteDisabled voteDisabled) {
case VoteDisabled voteDisabled -> {
nbt.putString(KEY_ANNOUNCEMENT, VOTE_DISABLED);
nbt.putUUID(KEY_ARTIFACT, voteDisabled.key().artifactID());
nbt.putString(KEY_CATEGORY, voteDisabled.key().categoryID().toString());
voteDisabled.disabled().ifPresent(disabled -> nbt.putBoolean(KEY_DISABLED, disabled));
return Optional.of(nbt);
}
if (announcement instanceof VoteStats voteStats) {
case VoteStats voteStats -> {
nbt.putString(KEY_ANNOUNCEMENT, VOTE_STATS);
nbt.putUUID(KEY_ARTIFACT, voteStats.key().artifactID());
nbt.putString(KEY_CATEGORY, voteStats.key().categoryID().toString());
nbt.putString(KEY_VOTE_ROLE, voteStats.key().roleID().toString());
// noinspection UnstableApiUsage
nbt.putIntArray(KEY_LEVEL_COUNTS, voteStats.counts().toArray());
return Optional.of(nbt);
}
throw new IllegalArgumentException("unsupported announcement type: " + announcement.getClass());
} catch (IllegalArgumentException e) {
VoteMe.LOGGER.warn("Failed to serialize " + announcement + " to nbt", e);
return Optional.empty();
}
}

Expand All @@ -104,7 +101,8 @@ yield new Artifact(key, nbt.getString(KEY_ARTIFACT_NAME), nbt.contains(KEY_ALIAS
Tag.TAG_STRING) ? Optional.of(nbt.getString(KEY_ALIAS)) : Optional.empty());
}
case COMMENTS -> {
CommentsKey key = new CommentsKey(nbt.getUUID(KEY_ARTIFACT), nbt.getUUID(KEY_VOTER));
CommentsKey key = new CommentsKey(
nbt.getUUID(KEY_ARTIFACT), nbt.getUUID(KEY_VOTER), nbt.getInt(KEY_REVISION));
yield new Comments(key, nbt.getList(KEY_COMMENTS, Tag.TAG_STRING)
.stream().map(Tag::getAsString).collect(toImmutableList()));
}
Expand All @@ -125,7 +123,6 @@ yield new VoteDisabled(key, nbt.contains(KEY_DISABLED,
case VOTE_STATS -> {
VoteStatsKey key = new VoteStatsKey(nbt.getUUID(KEY_ARTIFACT), ResourceLocation.parse(nbt
.getString(KEY_CATEGORY)), ResourceLocation.parse(nbt.getString(KEY_VOTE_ROLE)));
// noinspection UnstableApiUsage
yield new VoteStats(key, copyOf(nbt.getIntArray(KEY_LEVEL_COUNTS)));
}
default -> throw new IllegalArgumentException("unsupported announce key: " + announceKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public void publish(Collection<? extends Announcement> announcements) {
@Override
public Collection<? extends Announcement> dequeue() {
Preconditions.checkArgument(this.server.isSameThread(), "server thread");
// noinspection SizeReplaceableByIsEmpty
if (this.queued.size() > 0) {
VoteMe.LOGGER.info("Retrieving {} announcement locally.", this.queued.size());
Collection<? extends Announcement> result = this.queued;
Expand Down
62 changes: 19 additions & 43 deletions src/main/java/org/teacon/voteme/sync/RedisSynchronizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.CompletableFuture.allOf;
import static java.util.concurrent.CompletableFuture.failedStage;
import static org.teacon.voteme.sync.AnnouncementSerializer.*;

@MethodsReturnNonnullByDefault
Expand Down Expand Up @@ -76,11 +75,11 @@ private void tickVoteUpdates() {
}
List<Vote> watchedVotes = new ArrayList<>();
accumulator.buildAffectedVotes(watchedVotes);
// noinspection SizeReplaceableByIsEmpty
if (watchedVotes.size() > 0) {
String[] watchedKeys = watchedVotes.stream().map(v -> toRedisKey(v.key())).toArray(String[]::new);
VoteMe.LOGGER.info("Watch {} key(s) for updating vote related data in redis.", watchedKeys.length);
List<Vote> affectedVotes = new ArrayList<>();
// noinspection UnstableApiUsage
Map<VoteStatsKey, ImmutableIntArray> affectedStatsMap = new HashMap<>();
RedisAsyncCommands<String, String> async = this.connection.async();
AtomicBoolean succeed = new AtomicBoolean();
Expand Down Expand Up @@ -117,15 +116,11 @@ private void tickVoteUpdates() {
futures.add(async.hset(key, builder.build()).toCompletableFuture());
}
// submit affected stats
// noinspection UnstableApiUsage
for (Map.Entry<VoteStatsKey, ImmutableIntArray> entry : affectedStatsMap.entrySet()) {
String key = toRedisKey(entry.getKey());
// noinspection UnstableApiUsage
ImmutableIntArray counts = entry.getValue();
// noinspection UnstableApiUsage
int bound = counts.length();
for (int i = 0; i < bound; ++i) {
// noinspection UnstableApiUsage
futures.add(async.hincrby(key, "level:" + i, counts.get(i)).toCompletableFuture());
}
}
Expand All @@ -138,7 +133,6 @@ private void tickVoteUpdates() {
for (Vote affectedVote : affectedVotes) {
async.publish(SYNC, serialize(affectedVote).orElseThrow().toString());
}
// noinspection UnstableApiUsage
for (Map.Entry<VoteStatsKey, ImmutableIntArray> entry : affectedStatsMap.entrySet()) {
VoteStats voteStats = new VoteStats(entry.getKey(), entry.getValue());
async.publish(SYNC, serialize(voteStats).orElseThrow().toString());
Expand All @@ -154,22 +148,13 @@ private void tickVoteUpdates() {
}

private static String toRedisKey(AnnounceKey<?> announceKey) {
if (announceKey instanceof ArtifactKey key) {
return ARTIFACT + ":" + key.artifactID();
}
if (announceKey instanceof CommentsKey key) {
return COMMENTS + ":" + key.artifactID() + ":" + key.voterID();
}
if (announceKey instanceof VoteKey key) {
return VOTE + ":" + key.artifactID() + ":" + key.categoryID() + ":" + key.voterID();
}
if (announceKey instanceof VoteDisabledKey key) {
return VOTE_DISABLED + ":" + key.artifactID() + ":" + key.categoryID();
}
if (announceKey instanceof VoteStatsKey key) {
return VOTE_STATS + ":" + key.artifactID() + ":" + key.categoryID() + ":" + key.roleID();
}
throw new IllegalArgumentException("unsupported announce key");
return switch (announceKey) {
case ArtifactKey key -> ARTIFACT + ":" + key.artifactID();
case CommentsKey key -> COMMENTS + ":" + key.artifactID() + ":" + key.voterID() + ":";
case VoteKey key -> VOTE + ":" + key.artifactID() + ":" + key.categoryID() + ":" + key.voterID();
case VoteDisabledKey key -> VOTE_DISABLED + ":" + key.artifactID() + ":" + key.categoryID();
case VoteStatsKey key -> VOTE_STATS + ":" + key.artifactID() + ":" + key.categoryID() + ":" + key.roleID();
};
}

private static AnnounceKey<?> fromRedisKey(String redisKey) {
Expand All @@ -183,10 +168,11 @@ private static AnnounceKey<?> fromRedisKey(String redisKey) {
}
case COMMENTS -> {
String[] parts = redisKeyParts[2].split(":");
checkArgument(parts.length == 2, "invalid message");
checkArgument(parts.length == 2 || parts.length == 3, "invalid message");
UUID artifactID = UUID.fromString(parts[0]);
UUID voterID = UUID.fromString(parts[1]);
return new CommentsKey(artifactID, voterID);
int revision = parts.length > 2 ? Integer.parseInt(parts[2]) : 0;
return new CommentsKey(artifactID, voterID, revision);
}
case VOTE -> {
String[] parts = redisKeyParts[2].split(":");
Expand Down Expand Up @@ -217,9 +203,8 @@ private static AnnounceKey<?> fromRedisKey(String redisKey) {

private static <T extends Announcement> CompletableFuture<T> dispatch(AnnounceKey<T> announceKey,
RedisAsyncCommands<String, String> async) {
CompletionStage<T> stage = failedStage(new IllegalArgumentException("unsupported announce key"));
if (announceKey instanceof ArtifactKey key) {
stage = async.hgetall(toRedisKey(key)).thenApplyAsync(map -> {
CompletionStage<T> stage = switch (announceKey) {
case ArtifactKey key -> async.hgetall(toRedisKey(key)).thenApplyAsync(map -> {
String name = map.getOrDefault("name", "");
Optional<String> optional = Optional.empty();
if (map.containsKey("alias")) {
Expand All @@ -230,19 +215,14 @@ private static <T extends Announcement> CompletableFuture<T> dispatch(AnnounceKe
}
return announceKey.cast(new Artifact(key, name, optional));
});
}
if (announceKey instanceof CommentsKey key) {
stage = async.lrange(toRedisKey(key), 0, Integer.MAX_VALUE).thenApplyAsync(list -> {
case CommentsKey key -> async.lrange(toRedisKey(key), 0, Integer.MAX_VALUE).thenApplyAsync(list -> {
ImmutableList<String> comments = ImmutableList.copyOf(list).reverse();
return announceKey.cast(new Comments(key, comments));
});
}
if (announceKey instanceof VoteKey key) {
stage = async.hgetall(toRedisKey(key)).thenApplyAsync(map -> {
case VoteKey key -> async.hgetall(toRedisKey(key)).thenApplyAsync(map -> {
int level = Integer.parseInt(map.getOrDefault("level", "0"));
checkArgument(level >= 0 && level <= 5, "level out of range from 1 to 5");
int expectedSize = Math.max(0, map.size() - 2);
// noinspection UnstableApiUsage
ImmutableSet.Builder<ResourceLocation> roles = ImmutableSet.builderWithExpectedSize(expectedSize);
for (int i = 0; map.containsKey("role:" + i); ++i) {
ResourceLocation role = ResourceLocation.parse(map.get("role:" + i));
Expand All @@ -251,9 +231,7 @@ private static <T extends Announcement> CompletableFuture<T> dispatch(AnnounceKe
Instant time = Instant.parse(checkNotNull(map.getOrDefault("time", Instant.EPOCH.toString())));
return announceKey.cast(new Vote(key, level, roles.build(), time));
});
}
if (announceKey instanceof VoteDisabledKey key) {
stage = async.get(toRedisKey(key)).thenApplyAsync(string -> {
case VoteDisabledKey key -> async.get(toRedisKey(key)).thenApplyAsync(string -> {
Optional<Boolean> disabled = switch (String.valueOf(string)) {
case "null" -> Optional.empty();
case "true" -> Optional.of(Boolean.TRUE);
Expand All @@ -262,20 +240,17 @@ private static <T extends Announcement> CompletableFuture<T> dispatch(AnnounceKe
};
return announceKey.cast(new VoteDisabled(key, disabled));
});
}
if (announceKey instanceof VoteStatsKey key) {
stage = async.hgetall(toRedisKey(key)).thenApplyAsync(map -> {
case VoteStatsKey key -> async.hgetall(toRedisKey(key)).thenApplyAsync(map -> {
int count0 = Integer.parseInt(map.getOrDefault("level:0", "0"));
int count1 = Integer.parseInt(map.getOrDefault("level:1", "0"));
int count2 = Integer.parseInt(map.getOrDefault("level:2", "0"));
int count3 = Integer.parseInt(map.getOrDefault("level:3", "0"));
int count4 = Integer.parseInt(map.getOrDefault("level:4", "0"));
int count5 = Integer.parseInt(map.getOrDefault("level:5", "0"));
// noinspection UnstableApiUsage
ImmutableIntArray counts = ImmutableIntArray.of(count0, count1, count2, count3, count4, count5);
return announceKey.cast(new VoteStats(key, counts));
});
}
};
return stage.toCompletableFuture();
}

Expand Down Expand Up @@ -358,6 +333,7 @@ public Collection<? extends Announcement> dequeue() {
this.scan(ScanCursor.of("0"), new ScanArgs().match(VOTE_DISABLED + ":*").limit(BATCH_MAXIMUM));
this.scan(ScanCursor.of("0"), new ScanArgs().match(VOTE_STATS + ":*").limit(BATCH_MAXIMUM));
}
// noinspection SizeReplaceableByIsEmpty
if (this.receivedAnnouncements.size() > 0) {
VoteMe.LOGGER.info("Retrieving {} announcement(s) from redis.", this.receivedAnnouncements.size());
Collection<? extends Announcement> result = this.receivedAnnouncements;
Expand Down
Loading

0 comments on commit 5be9c84

Please sign in to comment.