diff --git a/src/main/java/emu/nebula/data/GameData.java b/src/main/java/emu/nebula/data/GameData.java index ef4841d..e0b7ffc 100644 --- a/src/main/java/emu/nebula/data/GameData.java +++ b/src/main/java/emu/nebula/data/GameData.java @@ -87,6 +87,9 @@ public class GameData { @Getter private static DataTable DailyQuestDataTable = new DataTable<>(); @Getter private static DataTable DailyQuestActiveDataTable = new DataTable<>(); + // Tutorial + @Getter private static DataTable TutorialLevelDataTable = new DataTable<>(); + // Star tower @Getter private static DataTable StarTowerDataTable = new DataTable<>(); @Getter private static DataTable StarTowerStageDataTable = new DataTable<>(); diff --git a/src/main/java/emu/nebula/data/resources/TutorialLevelDef.java b/src/main/java/emu/nebula/data/resources/TutorialLevelDef.java new file mode 100644 index 0000000..7304ce5 --- /dev/null +++ b/src/main/java/emu/nebula/data/resources/TutorialLevelDef.java @@ -0,0 +1,20 @@ +package emu.nebula.data.resources; + +import emu.nebula.data.BaseDef; +import emu.nebula.data.ResourceType; + +import lombok.Getter; + +@Getter +@ResourceType(name = "TutorialLevel.json") +public class TutorialLevelDef extends BaseDef { + private int Id; + private int WorldClass; + private int Item1; + private int Qty1; + + @Override + public int getId() { + return Id; + } +} diff --git a/src/main/java/emu/nebula/game/GameContext.java b/src/main/java/emu/nebula/game/GameContext.java index 03f917e..aee75eb 100644 --- a/src/main/java/emu/nebula/game/GameContext.java +++ b/src/main/java/emu/nebula/game/GameContext.java @@ -11,6 +11,7 @@ import emu.nebula.Nebula; import emu.nebula.game.gacha.GachaModule; import emu.nebula.game.player.PlayerModule; import emu.nebula.game.scoreboss.ScoreBossModule; +import emu.nebula.game.tutorial.TutorialModule; import emu.nebula.net.GameSession; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; @@ -25,6 +26,7 @@ public class GameContext implements Runnable { // Modules private final PlayerModule playerModule; private final GachaModule gachaModule; + private final TutorialModule tutorialModule; private final ScoreBossModule scoreBossModule; // Game loop @@ -39,6 +41,7 @@ public class GameContext implements Runnable { // Setup game modules this.playerModule = new PlayerModule(this); this.gachaModule = new GachaModule(this); + this.tutorialModule = new TutorialModule(this); this.scoreBossModule = new ScoreBossModule(this); // Run game loop diff --git a/src/main/java/emu/nebula/game/player/PlayerProgress.java b/src/main/java/emu/nebula/game/player/PlayerProgress.java index 16c1c0c..08d3772 100644 --- a/src/main/java/emu/nebula/game/player/PlayerProgress.java +++ b/src/main/java/emu/nebula/game/player/PlayerProgress.java @@ -8,6 +8,7 @@ import dev.morphia.annotations.Id; import emu.nebula.Nebula; import emu.nebula.data.GameData; import emu.nebula.database.GameDatabaseObject; +import emu.nebula.game.tutorial.TutorialLevelLog; import emu.nebula.game.vampire.VampireSurvivorLog; import emu.nebula.proto.PlayerData.PlayerInfo; import emu.nebula.proto.Public.CharGemInstance; @@ -48,6 +49,9 @@ public class PlayerProgress extends PlayerManager implements GameDatabaseObject // Fate cards private IntSet fateCards; + + // Tutorial + private Map tutorialLog; @Deprecated // Morphia only public PlayerProgress() { @@ -74,8 +78,13 @@ public class PlayerProgress extends PlayerManager implements GameDatabaseObject // Vampire Survivor this.vampireLog = new HashMap<>(); this.vampireTalents = new Bitset(); + + // Fate cards this.fateCards = new IntOpenHashSet(); + // Tutorials + this.tutorialLog = new HashMap<>(); + // Save to database this.save(); } @@ -219,5 +228,10 @@ public class PlayerProgress extends PlayerManager implements GameDatabaseObject vsProto.addRecords(log.toProto()); } } + + // Tutorials + for (var tutorial : this.getTutorialLog().values()) { + proto.addTutorialLevels(tutorial.toProto()); + } } } diff --git a/src/main/java/emu/nebula/game/tutorial/TutorialLevelLog.java b/src/main/java/emu/nebula/game/tutorial/TutorialLevelLog.java new file mode 100644 index 0000000..45e9069 --- /dev/null +++ b/src/main/java/emu/nebula/game/tutorial/TutorialLevelLog.java @@ -0,0 +1,36 @@ +package emu.nebula.game.tutorial; + +import dev.morphia.annotations.Entity; +import emu.nebula.proto.Public.TutorialLevel; +import lombok.Getter; + +@Getter +@Entity(useDiscriminator = false) +public class TutorialLevelLog { + private int id; + private boolean claimed; + + @Deprecated // Morphia only + public TutorialLevelLog() { + + } + + public TutorialLevelLog(int id) { + this.id = id; + } + + public void setClaimed(boolean value) { + this.claimed = value; + } + + // Proto + + public TutorialLevel toProto() { + var proto = TutorialLevel.newInstance() + .setLevelId(this.getId()) + .setPassed(true) + .setRewardReceived(this.isClaimed()); + + return proto; + } +} diff --git a/src/main/java/emu/nebula/game/tutorial/TutorialModule.java b/src/main/java/emu/nebula/game/tutorial/TutorialModule.java new file mode 100644 index 0000000..dc4b056 --- /dev/null +++ b/src/main/java/emu/nebula/game/tutorial/TutorialModule.java @@ -0,0 +1,63 @@ +package emu.nebula.game.tutorial; + +import emu.nebula.Nebula; +import emu.nebula.data.GameData; +import emu.nebula.game.GameContext; +import emu.nebula.game.GameContextModule; +import emu.nebula.game.player.Player; +import emu.nebula.game.player.PlayerChangeInfo; + +public class TutorialModule extends GameContextModule { + + public TutorialModule(GameContext context) { + super(context); + } + + public boolean settle(Player player, int id) { + // Check if the tutorial was completed + if (player.getProgress().getTutorialLog().containsKey(id)) { + return true; + } + + // Get data + var data = GameData.getTutorialLevelDataTable().get(id); + if (data == null) { + return false; + } + + // Create log + var log = new TutorialLevelLog(id); + + // Add to progress tutorial map + player.getProgress().getTutorialLog().put(id, log); + + // Save to database + Nebula.getGameDatabase().update(player.getProgress(), player.getUid(), "tutorialLog." + log.getId(), log); + + // Success + return true; + } + + public PlayerChangeInfo recvReward(Player player, int id) { + // Get tutorial log + var log = player.getProgress().getTutorialLog().get(id); + if (log == null || log.isClaimed()) { + return null; + } + + // Get data + var data = GameData.getTutorialLevelDataTable().get(id); + if (data == null) { + return null; + } + + // Set claim state + log.setClaimed(true); + + // Save to database + Nebula.getGameDatabase().update(player.getProgress(), player.getUid(), "tutorialLog." + log.getId(), log); + + // Add reward item + return player.getInventory().addItem(data.getItem1(), data.getQty1()); + } +} diff --git a/src/main/java/emu/nebula/server/handlers/HandlerTutorialLevelRewardReceiveReq.java b/src/main/java/emu/nebula/server/handlers/HandlerTutorialLevelRewardReceiveReq.java new file mode 100644 index 0000000..ac38521 --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerTutorialLevelRewardReceiveReq.java @@ -0,0 +1,29 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.Public.UI32; +import emu.nebula.net.HandlerId; +import emu.nebula.Nebula; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.tutorial_level_reward_receive_req) +public class HandlerTutorialLevelRewardReceiveReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse request + var req = UI32.parseFrom(message); + + // Get rewards + var change = Nebula.getGameContext().getTutorialModule().recvReward(session.getPlayer(), req.getValue()); + + if (change == null) { + return session.encodeMsg(NetMsgId.tutorial_level_reward_receive_failed_ack); + } + + // Encode and send + return session.encodeMsg(NetMsgId.tutorial_level_reward_receive_succeed_ack, change.toProto()); + } + +} diff --git a/src/main/java/emu/nebula/server/handlers/HandlerTutorialLevelSettleReq.java b/src/main/java/emu/nebula/server/handlers/HandlerTutorialLevelSettleReq.java new file mode 100644 index 0000000..57de2d9 --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerTutorialLevelSettleReq.java @@ -0,0 +1,29 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.Public.UI32; +import emu.nebula.net.HandlerId; +import emu.nebula.Nebula; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.tutorial_level_settle_req) +public class HandlerTutorialLevelSettleReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse request + var req = UI32.parseFrom(message); + + // Settle + boolean success = Nebula.getGameContext().getTutorialModule().settle(session.getPlayer(), req.getValue()); + + if (success == false) { + return session.encodeMsg(NetMsgId.tutorial_level_settle_failed_ack); + } + + // Encode and send + return session.encodeMsg(NetMsgId.tutorial_level_settle_succeed_ack); + } + +}