Implement gallery showcase

This commit is contained in:
Melledy
2025-10-30 08:04:42 -07:00
parent 0524278cac
commit 2b42c727dc
7 changed files with 166 additions and 14 deletions

View File

@@ -12,5 +12,5 @@ public class GameConstants {
public static final int EXP_ITEM_ID = 21;
public static final int MAX_FORMATIONS = 5;
public static final int MAX_SHOWCASE_IDS = 5;
}

View File

@@ -49,6 +49,7 @@ public class GameData {
@Getter private static DataTable<WorldClassDef> WorldClassDataTable = new DataTable<>();
@Getter private static DataTable<GuideGroupDef> GuideGroupDataTable = new DataTable<>();
@Getter private static DataTable<HandbookDef> HandbookDataTable = new DataTable<>();
@Getter private static DataTable<StoryDef> StoryDataTable = new DataTable<>();
@Getter private static DataTable<StorySetSectionDef> StorySetSectionDataTable = new DataTable<>();

View File

@@ -0,0 +1,24 @@
package emu.nebula.data.resources;
import emu.nebula.data.BaseDef;
import emu.nebula.data.ResourceType;
import emu.nebula.data.ResourceType.LoadPriority;
import lombok.Getter;
@Getter
@ResourceType(name = "Handbook.json", loadPriority = LoadPriority.LOW)
public class HandbookDef extends BaseDef {
private int Id;
private int Index;
private int Type;
@Override
public int getId() {
return Id;
}
@Override
public void onLoad() {
}
}

View File

@@ -8,6 +8,7 @@ import emu.nebula.data.resources.CharacterDef;
import emu.nebula.data.resources.DiscDef;
import emu.nebula.game.player.PlayerManager;
import emu.nebula.game.player.Player;
import emu.nebula.game.player.PlayerHandbook;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.Getter;
@@ -68,6 +69,21 @@ public class CharacterStorage extends PlayerManager {
return this.getCharacters().values();
}
public PlayerHandbook getCharacterHandbook() {
var handbook = new PlayerHandbook(1);
for (var character : this.getCharacterCollection()) {
// Get handbook
var data = GameData.getHandbookDataTable().get(400000 + character.getSkin());
if (data == null) continue;
// Set flag
handbook.setBit(data.getIndex());
}
return handbook;
}
// Discs
public GameDisc getDiscById(int id) {
@@ -112,6 +128,20 @@ public class CharacterStorage extends PlayerManager {
return this.getDiscs().values();
}
public PlayerHandbook getDiscHandbook() {
var handbook = new PlayerHandbook(2);
for (var disc : this.getDiscCollection()) {
// Get handbook
var data = GameData.getHandbookDataTable().get(disc.getDiscId());
if (data == null) continue;
// Set flag
handbook.setBit(data.getIndex());
}
return handbook;
}
// Database

View File

@@ -33,6 +33,7 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import lombok.Getter;
import us.hebi.quickbuf.RepeatedInt;
@Getter
@Entity(value = "players", useDiscriminator = false)
@@ -56,7 +57,7 @@ public class Player implements GameDatabaseObject {
private int energy;
private IntSet boards;
private int[] boards;
private IntSet headIcons;
private IntSet titles;
@@ -101,7 +102,7 @@ public class Player implements GameDatabaseObject {
this.titleSuffix = 2;
this.level = 1;
this.energy = 240;
this.boards = new IntOpenHashSet();
this.boards = new int[] {410301};
this.headIcons = new IntOpenHashSet();
this.titles = new IntOpenHashSet();
this.createTime = Nebula.getCurrentTime();
@@ -120,9 +121,6 @@ public class Player implements GameDatabaseObject {
// Add titles
this.getTitles().add(this.getTitlePrefix());
this.getTitles().add(this.getTitleSuffix());
// Add board ids
this.getBoards().add(410301);
}
public Account getAccount() {
@@ -225,6 +223,28 @@ public class Player implements GameDatabaseObject {
// Success
return true;
}
public boolean setBoard(RepeatedInt ids) {
// Length check
if (ids.length() <= 0 || ids.length() > GameConstants.MAX_SHOWCASE_IDS) {
return false;
}
// Get max length
this.boards = new int[ids.length()];
// Copy ids to our boards array
for (int i = 0; i < ids.length(); i++) {
int id = ids.get(i);
this.boards[i] = id;
}
// Save to database
Nebula.getGameDatabase().update(this, this.getUid(), "boards", this.getBoards());
// Success
return true;
}
public void setNewbieInfo(int groupId, int stepId) {
// TODO
@@ -338,7 +358,9 @@ public class Player implements GameDatabaseObject {
// Proto
public PlayerInfo toProto() {
PlayerInfo proto = PlayerInfo.newInstance();
PlayerInfo proto = PlayerInfo.newInstance()
.setServerTs(Nebula.getCurrentTime())
.setAchievements(new byte[64]);
var acc = proto.getMutableAcc()
.setNickName(this.getName())
@@ -452,16 +474,15 @@ public class Player implements GameDatabaseObject {
proto.addDictionaries(dictionaryProto);
}
// Server timestamp
proto.setServerTs(Nebula.getCurrentTime());
// Extra
proto.setAchievements(new byte[64]);
// Add instance
// Add instances
this.getInstanceManager().toProto(proto);
// Handbook
proto.addHandbook(this.getCharacters().getCharacterHandbook().toProto());
proto.addHandbook(this.getCharacters().getDiscHandbook().toProto());
// Extra
proto.getMutableVampireSurvivorRecord()
.getMutableSeason();

View File

@@ -0,0 +1,53 @@
package emu.nebula.game.player;
import emu.nebula.proto.Public.HandbookInfo;
import lombok.Getter;
@Getter
public class PlayerHandbook {
private int type;
private long[] data;
public PlayerHandbook(int type) {
this.type = type;
this.data = new long[1];
}
public void setBit(int index) {
int longArrayOffset = (int) Math.floor((index - 1) / 64D);
int bytePosition = ((index - 1) % 64);
if (longArrayOffset >= this.data.length) {
var oldData = this.data;
this.data = new long[longArrayOffset + 1];
System.arraycopy(oldData, 0, this.data, 0, oldData.length);
}
this.data[longArrayOffset] |= (1L << bytePosition);
}
public byte[] toByteArray() {
byte[] array = new byte[this.getData().length * 8];
for (int i = 0; i < this.getData().length; i++) {
long value = this.getData()[i];
for (int x = 7; x >= 0; x--) {
array[(i * 8) + x] = (byte) (value & 0xFF);
value >>= Byte.SIZE;
}
}
return array;
}
// Proto
public HandbookInfo toProto() {
var proto = HandbookInfo.newInstance()
.setType(this.getType())
.setData(this.toByteArray());
return proto;
}
}

View File

@@ -0,0 +1,23 @@
package emu.nebula.server.handlers;
import emu.nebula.net.NetHandler;
import emu.nebula.net.NetMsgId;
import emu.nebula.proto.PlayerBoard.PlayerBoardSetReq;
import emu.nebula.net.HandlerId;
import emu.nebula.net.GameSession;
@HandlerId(NetMsgId.player_board_set_req)
public class HandlerPlayerBoardSetReq extends NetHandler {
@Override
public byte[] handle(GameSession session, byte[] message) throws Exception {
// Parse request
var req = PlayerBoardSetReq.parseFrom(message);
// Set board
boolean success = session.getPlayer().setBoard(req.getIds());
return this.encodeMsg(success ? NetMsgId.player_board_set_succeed_ack : NetMsgId.player_board_set_failed_ack);
}
}