Skip to content

Instantly share code, notes, and snippets.

@NotArchon
Created April 26, 2023 00:43
Show Gist options
  • Select an option

  • Save NotArchon/c8d3b26defcac4eda5128758a0a4b1c9 to your computer and use it in GitHub Desktop.

Select an option

Save NotArchon/c8d3b26defcac4eda5128758a0a4b1c9 to your computer and use it in GitHub Desktop.
package com.neox.web.model.game.requests;
import com.mongodb.MongoException;
import com.mongodb.bulk.BulkWriteResult;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.*;
import com.neox.web.Neox;
import com.neox.web.model.game.GameRequest;
import com.neox.web.pojo.HiscoresStatDoc;
import io.archon.misc.utils.ThreadUtils;
import io.archon.webserver.network.HttpAsyncRequest;
import io.archon.webserver.network.messages.StatusMessage;
import io.netty5.handler.codec.http.HttpResponseStatus;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import java.util.*;
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class HiscoresUpdate implements GameRequest {
private static final int MIN_LEVEL_REQ = 30;
String userId;
String gameMode;
String xpMode;
Map<Integer, Stat> stats;
@Override
public void handle(HttpAsyncRequest httpReq) {
if(userId == null || gameMode == null || xpMode == null || stats == null) { // should never happen
httpReq.write(new StatusMessage(HttpResponseStatus.BAD_REQUEST));
return;
}
long ms = System.currentTimeMillis();
Stat overall = new Stat();
stats.forEach((id, stat) -> {
overall.lvl += stat.lvl;
overall.xp += stat.xp;
});
stats.put(-1, overall);
MongoCollection<HiscoresStatDoc> collection = Neox.getNode().getMongoDatabase()
.getCollection("hiscores_stats", HiscoresStatDoc.class); // not sure if we should cache this ?
Map<Integer, HiscoresStatDoc> existing = new HashMap<>();
collection.find(Filters.and(
Filters.eq("user_id", userId),
Filters.eq("game_mode", gameMode),
Filters.eq("xp_mode", xpMode)
)).forEach(d -> existing.put(d.skillId(), d));
List<WriteModel<HiscoresStatDoc>> updates = new ArrayList<>();
stats.forEach((skillId, stat) -> {
HiscoresStatDoc e = existing.get(skillId);
if(stat.lvl < MIN_LEVEL_REQ) {
if(e != null) // should not exist, delete
updates.add(new DeleteOneModel<>(Filters.eq("_id", e._id())));
return;
}
if(e == null) { // insert required
updates.add(new InsertOneModel<>(HiscoresStatDoc.builder()
.userId(userId)
.gameMode(gameMode)
.xpMode(xpMode)
.skillId(skillId)
.skillLvl(stat.lvl)
.skillXp(stat.xp)
.lastUpdate(ms)
.build()
));
} else if(stat.xp != e.skillXp()) { // update required
updates.add(new UpdateOneModel<>(
Filters.eq("_id", e._id()),
Updates.combine(
Updates.set("skill_level", stat.lvl),
Updates.set("skill_xp", stat.xp),
Updates.set("last_update", ms)
)
));
}
});
int tries = 0;
while(tries++ < 5) {
try {
collection.bulkWrite(updates);
break;
} catch(MongoException e) {
Neox.getNode().logError(e); // todo remove this just testing live
ThreadUtils.sleep(5000L);
}
}
}
private static final class Stat {
int lvl;
int xp;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment