mirror of
https://github.com/Melledy/Nebula.git
synced 2025-12-13 04:45:02 +01:00
Implement gacha history
This commit is contained in:
@@ -1,28 +1,19 @@
|
||||
package emu.nebula.game.gacha;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Id;
|
||||
import dev.morphia.annotations.Indexed;
|
||||
|
||||
import emu.nebula.data.resources.GachaDef;
|
||||
import emu.nebula.data.resources.GachaDef.GachaPackage;
|
||||
import emu.nebula.data.resources.GachaPkgDef;
|
||||
import emu.nebula.database.GameDatabaseObject;
|
||||
import emu.nebula.game.player.Player;
|
||||
import emu.nebula.proto.GachaInformation.GachaInfo;
|
||||
import emu.nebula.util.Utils;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Entity(value = "banner_info", useDiscriminator = false)
|
||||
public class GachaBannerInfo implements GameDatabaseObject {
|
||||
@Id
|
||||
private ObjectId id;
|
||||
|
||||
@Indexed
|
||||
private int playerUid;
|
||||
private int bannerId;
|
||||
@Entity(useDiscriminator = false)
|
||||
public class GachaBannerInfo {
|
||||
private int id;
|
||||
|
||||
private int total;
|
||||
private int missTimesA;
|
||||
@@ -35,9 +26,8 @@ public class GachaBannerInfo implements GameDatabaseObject {
|
||||
|
||||
}
|
||||
|
||||
public GachaBannerInfo(Player player, GachaDef data) {
|
||||
this.playerUid = player.getUid();
|
||||
this.bannerId = data.getId();
|
||||
public GachaBannerInfo(GachaDef data) {
|
||||
this.id = data.getId();
|
||||
}
|
||||
|
||||
public void setUsedGuarantee(boolean value) {
|
||||
@@ -108,7 +98,7 @@ public class GachaBannerInfo implements GameDatabaseObject {
|
||||
|
||||
public GachaInfo toProto() {
|
||||
var proto = GachaInfo.newInstance()
|
||||
.setId(this.getBannerId())
|
||||
.setId(this.getId())
|
||||
.setGachaTotalTimes(this.getTotal())
|
||||
.setTotalTimes(this.getTotal())
|
||||
.setAupMissTimes(this.getMissTimesA())
|
||||
|
||||
40
src/main/java/emu/nebula/game/gacha/GachaHistoryLog.java
Normal file
40
src/main/java/emu/nebula/game/gacha/GachaHistoryLog.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package emu.nebula.game.gacha;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.proto.GachaHistoriesOuterClass.GachaHistory;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Entity(value = "banner_info", useDiscriminator = false)
|
||||
public class GachaHistoryLog {
|
||||
private int type;
|
||||
private long time;
|
||||
private IntList ids;
|
||||
|
||||
@Deprecated // Morphia only
|
||||
public GachaHistoryLog() {
|
||||
|
||||
}
|
||||
|
||||
public GachaHistoryLog(int type, IntList results) {
|
||||
this.type = type;
|
||||
this.time = Nebula.getCurrentTime();
|
||||
this.ids = results;
|
||||
}
|
||||
|
||||
// Proto
|
||||
|
||||
public GachaHistory toProto() {
|
||||
var proto = GachaHistory.newInstance()
|
||||
.setGid(this.getType())
|
||||
.setTime(this.getTime());
|
||||
|
||||
for (int id : this.getIds()) {
|
||||
proto.addIds(id);
|
||||
}
|
||||
|
||||
return proto;
|
||||
}
|
||||
}
|
||||
@@ -1,57 +1,72 @@
|
||||
package emu.nebula.game.gacha;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Id;
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.data.resources.GachaDef;
|
||||
import emu.nebula.database.GameDatabaseObject;
|
||||
import emu.nebula.game.player.Player;
|
||||
import emu.nebula.game.player.PlayerChangeInfo;
|
||||
import emu.nebula.game.player.PlayerManager;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import lombok.Getter;
|
||||
|
||||
public class GachaManager extends PlayerManager {
|
||||
private final Int2ObjectMap<GachaBannerInfo> bannerInfos;
|
||||
private boolean loaded;
|
||||
@Getter
|
||||
@Entity(value = "gacha", useDiscriminator = false)
|
||||
public class GachaManager extends PlayerManager implements GameDatabaseObject {
|
||||
@Id
|
||||
private int uid;
|
||||
|
||||
public GachaManager(Player player) {
|
||||
super(player);
|
||||
this.bannerInfos = new Int2ObjectOpenHashMap<>();
|
||||
private Map<Integer, GachaBannerInfo> banners;
|
||||
private Map<Integer, List<GachaHistoryLog>> histories;
|
||||
|
||||
@Deprecated // Morphia only
|
||||
public GachaManager() {
|
||||
|
||||
}
|
||||
|
||||
public synchronized GachaBannerInfo getBannerInfoById(int id) {
|
||||
if (!this.loaded) {
|
||||
this.loadFromDatabase();
|
||||
}
|
||||
public GachaManager(Player player) {
|
||||
this();
|
||||
this.setPlayer(player);
|
||||
this.uid = player.getUid();
|
||||
|
||||
return this.bannerInfos.get(id);
|
||||
this.banners = new HashMap<>();
|
||||
this.histories = new HashMap<>();
|
||||
|
||||
this.save();
|
||||
}
|
||||
|
||||
public synchronized Collection<GachaBannerInfo> getBannerInfos() {
|
||||
if (!this.loaded) {
|
||||
this.loadFromDatabase();
|
||||
}
|
||||
|
||||
return this.bannerInfos.values();
|
||||
return this.banners.values();
|
||||
}
|
||||
|
||||
public synchronized GachaBannerInfo getBannerInfo(GachaDef gachaData) {
|
||||
if (!this.loaded) {
|
||||
this.loadFromDatabase();
|
||||
}
|
||||
|
||||
return this.bannerInfos.computeIfAbsent(
|
||||
return this.banners.computeIfAbsent(
|
||||
gachaData.getId(),
|
||||
i -> new GachaBannerInfo(this.getPlayer(), gachaData)
|
||||
i -> new GachaBannerInfo(gachaData)
|
||||
);
|
||||
}
|
||||
|
||||
public void saveBanner(GachaBannerInfo info) {
|
||||
Nebula.getGameDatabase().update(
|
||||
this,
|
||||
this.getPlayerUid(),
|
||||
"banners." + info.getId(),
|
||||
info
|
||||
);
|
||||
}
|
||||
|
||||
public PlayerChangeInfo recvGuarantee(int id) {
|
||||
// Get banner info
|
||||
var banner = this.getBannerInfoById(id);
|
||||
if (banner == null) {
|
||||
var info = this.banners.get(id);
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -62,32 +77,62 @@ public class GachaManager extends PlayerManager {
|
||||
}
|
||||
|
||||
// Check if we have enough pulls for a guarantee
|
||||
if (!data.canGuarantee() || banner.getTotal() < data.getGuaranteeTimes()) {
|
||||
if (!data.canGuarantee() || info.getTotal() < data.getGuaranteeTimes()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Make sure we havent used our guarantee yet
|
||||
if (banner.isUsedGuarantee()) {
|
||||
if (info.isUsedGuarantee()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Set guarantee
|
||||
banner.setUsedGuarantee(true);
|
||||
banner.save();
|
||||
info.setUsedGuarantee(true);
|
||||
|
||||
// Update to database
|
||||
this.saveBanner(info);
|
||||
|
||||
// Give player the guaranteed item
|
||||
return getPlayer().getInventory().addItem(data.getGuaranteeTid(), data.getGuaranteeQty());
|
||||
}
|
||||
|
||||
// Database
|
||||
// Histories
|
||||
|
||||
private void loadFromDatabase() {
|
||||
var db = Nebula.getGameDatabase();
|
||||
public void addGachaHistory(GachaHistoryLog log) {
|
||||
// Get history
|
||||
var list = this.histories.computeIfAbsent(
|
||||
log.getType(),
|
||||
i -> new ArrayList<>()
|
||||
);
|
||||
|
||||
db.getObjects(GachaBannerInfo.class, "playerUid", getPlayerUid()).forEach(bannerInfo -> {
|
||||
this.bannerInfos.put(bannerInfo.getBannerId(), bannerInfo);
|
||||
});
|
||||
// Add to history
|
||||
list.add(log);
|
||||
|
||||
this.loaded = true;
|
||||
// Limit history
|
||||
boolean resize = false;
|
||||
|
||||
while (list.size() > 50) {
|
||||
list.remove(0);
|
||||
resize = true;
|
||||
}
|
||||
|
||||
// Update to database
|
||||
if (resize) {
|
||||
// Replace history logs
|
||||
Nebula.getGameDatabase().update(
|
||||
this,
|
||||
this.getPlayerUid(),
|
||||
"histories." + log.getType(),
|
||||
list
|
||||
);
|
||||
} else {
|
||||
// Add to history list
|
||||
Nebula.getGameDatabase().addToSet(
|
||||
this,
|
||||
this.getPlayerUid(),
|
||||
"histories." + log.getType(),
|
||||
log
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@ public class GachaModule extends GameContextModule {
|
||||
int amount = mode == 2 ? 10 : 1;
|
||||
|
||||
// Get banner data
|
||||
var banner = GameData.getGachaDataTable().get(bannerId);
|
||||
if (banner == null) {
|
||||
var data = GameData.getGachaDataTable().get(bannerId);
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var bannerStorage = banner.getStorageData();
|
||||
var bannerStorage = data.getStorageData();
|
||||
if (bannerStorage == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -57,13 +57,13 @@ public class GachaModule extends GameContextModule {
|
||||
player.getInventory().removeItem(bannerStorage.getDefaultId(), Math.min(costReq, costQty), change);
|
||||
|
||||
// Get gacha banner info
|
||||
var info = player.getGachaManager().getBannerInfo(banner);
|
||||
var info = player.getGachaManager().getBannerInfo(data);
|
||||
|
||||
// Do gacha
|
||||
var results = new IntArrayList();
|
||||
|
||||
for (int i = 0; i < amount; i++) {
|
||||
int id = info.doPull(banner);
|
||||
int id = info.doPull(data);
|
||||
if (id <= 0) continue;
|
||||
|
||||
results.add(id);
|
||||
@@ -158,7 +158,11 @@ public class GachaModule extends GameContextModule {
|
||||
change.add(transform);
|
||||
|
||||
// Save banner info to database
|
||||
info.save();
|
||||
player.getGachaManager().saveBanner(info);
|
||||
|
||||
// Add history
|
||||
var log = new GachaHistoryLog(data.getGachaType(), results);
|
||||
player.getGachaManager().addGachaHistory(log);
|
||||
|
||||
// Complete
|
||||
return new GachaResult(info, change, results);
|
||||
|
||||
@@ -81,7 +81,6 @@ public class Player implements GameDatabaseObject {
|
||||
// Managers
|
||||
private final transient CharacterStorage characters;
|
||||
private final transient FriendList friendList;
|
||||
private final transient GachaManager gachaManager;
|
||||
private final transient BattlePassManager battlePassManager;
|
||||
private final transient StarTowerManager starTowerManager;
|
||||
private final transient InstanceManager instanceManager;
|
||||
@@ -93,6 +92,7 @@ public class Player implements GameDatabaseObject {
|
||||
private transient Inventory inventory;
|
||||
private transient FormationManager formations;
|
||||
private transient Mailbox mailbox;
|
||||
private transient GachaManager gachaManager;
|
||||
private transient PlayerProgress progress;
|
||||
private transient StoryManager storyManager;
|
||||
private transient QuestManager questManager;
|
||||
@@ -107,7 +107,6 @@ public class Player implements GameDatabaseObject {
|
||||
// Init player managers
|
||||
this.characters = new CharacterStorage(this);
|
||||
this.friendList = new FriendList(this);
|
||||
this.gachaManager = new GachaManager(this);
|
||||
this.battlePassManager = new BattlePassManager(this);
|
||||
this.starTowerManager = new StarTowerManager(this);
|
||||
this.instanceManager = new InstanceManager(this);
|
||||
@@ -597,6 +596,7 @@ public class Player implements GameDatabaseObject {
|
||||
this.formations = this.loadManagerFromDatabase(FormationManager.class);
|
||||
this.mailbox = this.loadManagerFromDatabase(Mailbox.class);
|
||||
this.progress = this.loadManagerFromDatabase(PlayerProgress.class);
|
||||
this.gachaManager = this.loadManagerFromDatabase(GachaManager.class);
|
||||
this.storyManager = this.loadManagerFromDatabase(StoryManager.class);
|
||||
this.questManager = this.loadManagerFromDatabase(QuestManager.class);
|
||||
this.agentManager = this.loadManagerFromDatabase(AgentManager.class);
|
||||
|
||||
@@ -16,7 +16,7 @@ import emu.nebula.game.character.Character;
|
||||
import emu.nebula.game.character.GameDisc;
|
||||
import emu.nebula.game.formation.FormationManager;
|
||||
import emu.nebula.game.friends.Friendship;
|
||||
import emu.nebula.game.gacha.GachaBannerInfo;
|
||||
import emu.nebula.game.gacha.GachaManager;
|
||||
import emu.nebula.game.inventory.GameItem;
|
||||
import emu.nebula.game.inventory.GameResource;
|
||||
import emu.nebula.game.inventory.Inventory;
|
||||
@@ -172,12 +172,12 @@ public class PlayerModule extends GameContextModule {
|
||||
datastore.getCollection(GameItem.class).deleteMany(multiFilter);
|
||||
datastore.getCollection(GameResource.class).deleteMany(multiFilter);
|
||||
datastore.getCollection(StarTowerBuild.class).deleteMany(multiFilter);
|
||||
datastore.getCollection(GachaBannerInfo.class).deleteMany(multiFilter);
|
||||
|
||||
datastore.getCollection(Inventory.class).deleteOne(idFilter);
|
||||
datastore.getCollection(FormationManager.class).deleteOne(idFilter);
|
||||
datastore.getCollection(Mailbox.class).deleteOne(idFilter);
|
||||
datastore.getCollection(PlayerProgress.class).deleteOne(idFilter);
|
||||
datastore.getCollection(GachaManager.class).deleteOne(idFilter);
|
||||
datastore.getCollection(StoryManager.class).deleteOne(idFilter);
|
||||
datastore.getCollection(QuestManager.class).deleteOne(idFilter);
|
||||
datastore.getCollection(AgentManager.class).deleteOne(idFilter);
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package emu.nebula.server.handlers;
|
||||
|
||||
import emu.nebula.net.NetHandler;
|
||||
import emu.nebula.net.NetMsgId;
|
||||
import emu.nebula.proto.GachaHistoriesOuterClass.GachaHistories;
|
||||
import emu.nebula.proto.Public.UI32;
|
||||
import emu.nebula.net.HandlerId;
|
||||
import emu.nebula.net.GameSession;
|
||||
|
||||
@HandlerId(NetMsgId.gacha_histories_req)
|
||||
public class HandlerGachaHistoriesReq extends NetHandler {
|
||||
|
||||
@Override
|
||||
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||
// Parse request
|
||||
var req = UI32.parseFrom(message);
|
||||
|
||||
// Get history log
|
||||
var list = session.getPlayer().getGachaManager().getHistories().get(req.getValue());
|
||||
|
||||
// Build response
|
||||
var rsp = GachaHistories.newInstance();
|
||||
|
||||
if (list != null) {
|
||||
for (var log : list) {
|
||||
rsp.addList(log.toProto());
|
||||
}
|
||||
}
|
||||
|
||||
// Encode and send
|
||||
return session.encodeMsg(NetMsgId.gacha_histories_succeed_ack, rsp);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user