mirror of
https://github.com/Melledy/Nebula.git
synced 2026-09-20 01:29:54 +02:00
Reimplement gacha (#32)
* Fix some grammar warning * Reimplement gacha * Update GachaResult#toSpinResp declaration --------- Co-authored-by: Yostarcc <lubenwei7758258@gmail.com>
This commit is contained in:
@@ -1,13 +1,18 @@
|
||||
package emu.nebula.data.resources;
|
||||
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.data.BaseDef;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.data.ResourceType;
|
||||
import emu.nebula.data.ResourceType.LoadPriority;
|
||||
import emu.nebula.util.Utils;
|
||||
import emu.nebula.util.WeightedList;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@ResourceType(name = "Gacha.json")
|
||||
@ResourceType(name = "Gacha.json", loadPriority = LoadPriority.LOWEST)
|
||||
public class GachaDef extends BaseDef {
|
||||
private int Id;
|
||||
private int StorageId;
|
||||
@@ -16,6 +21,14 @@ public class GachaDef extends BaseDef {
|
||||
private int GuaranteeTimes;
|
||||
private int GuaranteeTid;
|
||||
private int GuaranteeQty;
|
||||
private int ATypeGuaranteeTimes;
|
||||
|
||||
private int SpecificTid;
|
||||
private int SpecificQty;
|
||||
|
||||
private int FirstTenShow;
|
||||
private String StartTime;
|
||||
private String EndTime;
|
||||
|
||||
// Packages
|
||||
private int ATypePkg;
|
||||
@@ -31,6 +44,11 @@ public class GachaDef extends BaseDef {
|
||||
private transient WeightedList<GachaPackage> packageA;
|
||||
private transient WeightedList<GachaPackage> packageB;
|
||||
private transient WeightedList<GachaPackage> packageC;
|
||||
private transient GachaTypeDef typeData;
|
||||
private transient IntList allowedCoinItems;
|
||||
private transient long startTimeSeconds;
|
||||
private transient long endTimeSeconds;
|
||||
private transient boolean valid = true;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
@@ -44,18 +62,110 @@ public class GachaDef extends BaseDef {
|
||||
public GachaStorageDef getStorageData() {
|
||||
return GameData.getGachaStorageDataTable().get(this.getStorageId());
|
||||
}
|
||||
|
||||
|
||||
public GachaTypeDef getTypeData() {
|
||||
if (this.typeData != null) {
|
||||
return this.typeData;
|
||||
}
|
||||
|
||||
return GameData.getGachaTypeDataTable().get(this.getGachaType());
|
||||
}
|
||||
|
||||
public boolean containsAllowedCoinItem(int itemId) {
|
||||
return this.allowedCoinItems != null && this.allowedCoinItems.contains(itemId);
|
||||
}
|
||||
|
||||
public boolean isActiveAt(long now) {
|
||||
return this.valid && now >= this.startTimeSeconds && now <= this.endTimeSeconds;
|
||||
}
|
||||
|
||||
public int getDisplayAUpGuaranteeTimes() {
|
||||
if (this.ATypeGuaranteeTimes > 0) {
|
||||
return this.ATypeGuaranteeTimes;
|
||||
}
|
||||
|
||||
var storage = this.getStorageData();
|
||||
return storage != null ? storage.getAUpGuaranteeTimes() : 0;
|
||||
}
|
||||
|
||||
private boolean hasValidPackage(int packageId) {
|
||||
if (packageId <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var pkg = GachaPkgDef.getPackageById(packageId);
|
||||
return pkg != null && pkg.size() > 0;
|
||||
}
|
||||
|
||||
private boolean isSpinConfigValid() {
|
||||
boolean hasValidA = (this.ATypePkg > 0 && hasValidPackage(this.ATypePkg))
|
||||
|| (this.ATypeUpPkg > 0 && hasValidPackage(this.ATypeUpPkg));
|
||||
boolean hasValidB = (this.BTypePkg > 0 && hasValidPackage(this.BTypePkg))
|
||||
|| (this.BGuaranteePkg > 0 && hasValidPackage(this.BGuaranteePkg))
|
||||
|| (this.BTypeUpPkg > 0 && hasValidPackage(this.BTypeUpPkg));
|
||||
boolean hasValidC = this.CTypePkg > 0 && hasValidPackage(this.CTypePkg);
|
||||
|
||||
return this.packageA != null && this.packageA.size() > 0
|
||||
&& this.packageB != null && this.packageB.size() > 0
|
||||
&& this.packageC != null && this.packageC.size() > 0
|
||||
&& hasValidA && hasValidB && hasValidC;
|
||||
}
|
||||
|
||||
private void markInvalid(String message) {
|
||||
this.valid = false;
|
||||
this.startTimeSeconds = 1L;
|
||||
this.endTimeSeconds = 0L;
|
||||
Nebula.getLogger().error("Skip invalid gacha config for banner {}: {}", this.getId(), message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
this.valid = true;
|
||||
this.startTimeSeconds = 0L;
|
||||
this.endTimeSeconds = Long.MAX_VALUE;
|
||||
|
||||
this.packageA = new WeightedList<>();
|
||||
this.packageB = new WeightedList<>();
|
||||
this.packageC = new WeightedList<>();
|
||||
this.allowedCoinItems = new IntArrayList();
|
||||
|
||||
this.typeData = this.getTypeData();
|
||||
if (this.typeData == null) {
|
||||
markInvalid("invalid GachaType " + this.getGachaType());
|
||||
return;
|
||||
}
|
||||
if (this.typeData.getCoinItem() != null) {
|
||||
this.allowedCoinItems.addAll(this.typeData.getCoinItem());
|
||||
}
|
||||
|
||||
if (this.StartTime != null && !this.StartTime.isBlank()) {
|
||||
this.startTimeSeconds = Utils.dateToMilliseconds(this.StartTime) / 1000;
|
||||
}
|
||||
if (this.EndTime != null && !this.EndTime.isBlank()) {
|
||||
this.endTimeSeconds = Utils.dateToMilliseconds(this.EndTime) / 1000;
|
||||
}
|
||||
|
||||
// Get storage
|
||||
var storage = this.getStorageData();
|
||||
|
||||
if (storage == null) {
|
||||
markInvalid("invalid StorageId " + this.getStorageId());
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isNewbieBanner = GameData.getGachaNewbieDataTable().containsKey(this.getId());
|
||||
if (!isNewbieBanner) {
|
||||
// DefaultId can be a dedicated ticket item that is not listed in CoinItem.
|
||||
// Only the fallback currency (CostId) is required to be in the type whitelist.
|
||||
if (!this.containsAllowedCoinItem(storage.getCostId())) {
|
||||
markInvalid("CostId not allowed by GachaType: " + storage.getCostId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Package A
|
||||
this.packageA = new WeightedList<GachaPackage>();
|
||||
|
||||
if (this.ATypePkg > 0) {
|
||||
packageA.add(
|
||||
10000 - storage.getATypeUpProb(),
|
||||
10000 - storage.getATypeUpProb(),
|
||||
new GachaPackage(GachaPackageType.A, this.ATypePkg)
|
||||
);
|
||||
}
|
||||
@@ -65,38 +175,38 @@ public class GachaDef extends BaseDef {
|
||||
new GachaPackage(GachaPackageType.A_UP, this.ATypeUpPkg)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Package B
|
||||
this.packageB = new WeightedList<GachaPackage>();
|
||||
|
||||
if (this.BTypePkg > 0) {
|
||||
packageB.add(
|
||||
storage.getBTypeProb(),
|
||||
storage.getBTypeProb(),
|
||||
new GachaPackage(GachaPackageType.B, this.BTypePkg)
|
||||
);
|
||||
}
|
||||
if (this.BGuaranteePkg > 0) {
|
||||
packageB.add(
|
||||
storage.getBTypeGuaranteeProb(),
|
||||
storage.getBTypeGuaranteeProb(),
|
||||
new GachaPackage(GachaPackageType.B, this.BGuaranteePkg)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (this.BTypeUpPkg > 0) {
|
||||
packageB.add(
|
||||
storage.getBTypeUpProb(),
|
||||
new GachaPackage(GachaPackageType.B_UP, this.BTypeUpPkg)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Package C
|
||||
this.packageC = new WeightedList<GachaPackage>();
|
||||
|
||||
if (this.CTypePkg > 0) {
|
||||
packageC.add(
|
||||
10000,
|
||||
new GachaPackage(GachaPackageType.C, this.CTypePkg)
|
||||
);
|
||||
}
|
||||
|
||||
if (!isSpinConfigValid()) {
|
||||
markInvalid("spin package/probability composition is invalid");
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
|
||||
Reference in New Issue
Block a user