Implement event story

This commit is contained in:
Melledy
2026-09-07 22:41:31 -07:00
parent e140f8f839
commit 3bd5da7111
9 changed files with 316 additions and 3 deletions
@@ -188,6 +188,9 @@ public class GameData {
// Activity: Task // Activity: Task
@Getter private static DataTable<ActivityTaskDef> ActivityTaskDataTable = new DataTable<>(); @Getter private static DataTable<ActivityTaskDef> ActivityTaskDataTable = new DataTable<>();
@Getter private static DataTable<ActivityTaskGroupDef> ActivityTaskGroupDataTable = new DataTable<>(); @Getter private static DataTable<ActivityTaskGroupDef> ActivityTaskGroupDataTable = new DataTable<>();
// Activity: Story
@Getter private static DataTable<ActivityStoryDef> ActivityStoryDataTable = new DataTable<>();
// Activity: Shop // Activity: Shop
@Getter private static DataTable<ActivityShopDef> ActivityShopDataTable = new DataTable<>(); @Getter private static DataTable<ActivityShopDef> ActivityShopDataTable = new DataTable<>();
@@ -0,0 +1,27 @@
package emu.nebula.data.resources;
import emu.nebula.data.BaseDef;
import emu.nebula.data.ResourceType;
import emu.nebula.game.inventory.ItemParamMap;
import lombok.Getter;
@Getter
@ResourceType(name = "ActivityStory.json")
public class ActivityStoryDef extends BaseDef {
private int Id;
private int ChapterId;
private String FirstCompleteReward;
private transient ItemParamMap rewards;
@Override
public int getId() {
return Id;
}
@Override
public void onLoad() {
this.rewards = ItemParamMap.fromJsonString(this.FirstCompleteReward);
}
}
@@ -137,6 +137,7 @@ public class ActivityManager extends PlayerManager implements GameDatabaseObject
case Task -> new TaskActivity(this, data); case Task -> new TaskActivity(this, data);
case Shop -> new ShopActivity(this, data); case Shop -> new ShopActivity(this, data);
case TrekkerVersus -> new TrekkerVersusActivity(this, data); case TrekkerVersus -> new TrekkerVersusActivity(this, data);
case Story -> new StoryActivity(this, data);
case PenguinCard -> new PenguinCardActivity(this, data); case PenguinCard -> new PenguinCardActivity(this, data);
case Soldier -> new SoldierActivity(this, data); case Soldier -> new SoldierActivity(this, data);
default -> null; default -> null;
@@ -81,6 +81,7 @@ public class ActivityModule extends GameContextModule {
// Go, My Lady! Training Handbook Plus! // Go, My Lady! Training Handbook Plus!
this.activities.add(1011101); this.activities.add(1011101);
this.activities.add(1011102);
this.activities.add(1011103); this.activities.add(1011103);
this.activities.add(1011104); this.activities.add(1011104);
@@ -0,0 +1,204 @@
package emu.nebula.game.activity.type;
import java.util.HashMap;
import java.util.Map;
import dev.morphia.annotations.Entity;
import emu.nebula.data.GameData;
import emu.nebula.data.resources.ActivityDef;
import emu.nebula.game.activity.ActivityManager;
import emu.nebula.game.activity.GameActivity;
import emu.nebula.game.player.PlayerChangeInfo;
import emu.nebula.proto.ActivityDetail.ActivityMsg;
import emu.nebula.proto.ActivityStorySettleOuterClass.ActivityStorySettle;
import emu.nebula.proto.Public.ActivityStory;
import emu.nebula.proto.Public.ActivityStoryChoice;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import lombok.Getter;
import lombok.Setter;
import us.hebi.quickbuf.RepeatedInt;
@Getter
@Entity
public class StoryActivity extends GameActivity {
private Map<Integer, ActivityStoryInfo> stories;
private IntSet evidences;
private long buildId;
@Deprecated // Morphia only
public StoryActivity() {
}
public StoryActivity(ActivityManager manager, ActivityDef data) {
super(manager, data);
this.stories = new HashMap<>();
this.evidences = new IntOpenHashSet();
}
private int getChapterId() {
return (int) Math.floor(this.getId() / 100);
}
public boolean apply(int storyId, long buildId) {
// Check story id
var story = GameData.getActivityStoryDataTable().get(storyId);
if (story == null || story.getChapterId() != this.getChapterId()) {
return false;
}
// Set build id
if (buildId != 0) {
this.buildId = buildId;
}
return true;
}
public PlayerChangeInfo settle(Iterable<ActivityStorySettle> list, RepeatedInt evidences) {
// Create change info
var change = new PlayerChangeInfo();
// Boolean flag to check if any data was changed/added
boolean hasChanged = false;
// Handle settle info
for (var settle : list) {
// Get story data
var story = GameData.getActivityStoryDataTable().get(settle.getStoryId());
// Validate story
if (story == null || story.getChapterId() != this.getChapterId()) {
continue;
}
// Check if we have already completed this story
if (this.getStories().containsKey(story.getId())) {
continue;
}
// Create story info
var info = new ActivityStoryInfo(story.getId());
for (var option : settle.getMajor()) {
info.addMajor(option.getGroup(), option.getChoice());
}
for (var option : settle.getPersonality()) {
info.addPersonality(option.getGroup(), option.getChoice());
}
// Add to story log
this.stories.put(story.getId(), info);
// Set changed flag
hasChanged = true;
// Add rewards
this.getPlayer().getInventory().addItems(story.getRewards(), change);
}
// Add evidences
for (int i : evidences) {
this.getEvidences().add(i);
// Set changed flag
hasChanged = true;
}
// Save to database if anything has changed
if (hasChanged) {
this.save();
}
// Success
return change;
}
// Proto
@Override
public void encodeActivityMsg(ActivityMsg msg) {
var proto = msg.getMutableStoryChapter()
.setBuildId(this.getBuildId());
for (int i : this.getEvidences()) {
proto.addEvidences(i);
}
for (var info : this.getStories().values()) {
proto.addStories(info.toProto());
}
}
@Setter
@Getter
@Entity(useDiscriminator = false)
public static class ActivityStoryInfo {
private int id;
private Int2IntMap major;
private Int2IntMap personality;
@Deprecated // Morphia only
public ActivityStoryInfo() {
}
public ActivityStoryInfo(int id) {
this.id = id;
}
public void addMajor(int group, int choice) {
if (this.major == null) {
this.major = new Int2IntOpenHashMap();
}
this.major.put(group, choice);
}
public void addPersonality(int group, int choice) {
if (this.personality == null) {
this.personality = new Int2IntOpenHashMap();
}
this.personality.put(group, choice);
}
// Proto
public ActivityStory toProto() {
var proto = ActivityStory.newInstance()
.setId(this.id);
if (this.major != null) {
for (var entry : this.major.int2IntEntrySet()) {
var choice = ActivityStoryChoice.newInstance()
.setGroup(entry.getIntKey())
.setValue(entry.getIntValue());
proto.addMajor(choice);
}
}
if (this.personality != null) {
for (var entry : this.personality.int2IntEntrySet()) {
var choice = ActivityStoryChoice.newInstance()
.setGroup(entry.getIntKey())
.setValue(entry.getIntValue());
proto.addPersonality(choice);
}
}
return proto;
}
}
}
@@ -149,8 +149,10 @@ public class ItemParamMap extends Int2IntLinkedOpenHashMap implements ObjectBidi
var map = new ItemParamMap(); var map = new ItemParamMap();
var json = JsonUtils.decodeMap(jsonString, Integer.class, Integer.class); var json = JsonUtils.decodeMap(jsonString, Integer.class, Integer.class);
for (var entry : json.entrySet()) { if (json != null) {
map.add(entry.getKey(), entry.getValue()); for (var entry : json.entrySet()) {
map.add(entry.getKey(), entry.getValue());
}
} }
return map; return map;
@@ -0,0 +1,36 @@
package emu.nebula.server.handlers;
import emu.nebula.net.NetHandler;
import emu.nebula.net.NetMsgId;
import emu.nebula.proto.ActivityStoryApply.ActivityStoryApplyReq;
import emu.nebula.net.HandlerId;
import emu.nebula.game.activity.type.StoryActivity;
import emu.nebula.net.GameSession;
@HandlerId(NetMsgId.activity_story_apply_req)
public class HandlerActivityStoryApplyReq extends NetHandler {
@Override
public byte[] handle(GameSession session, byte[] message) throws Exception {
// Parse req
var req = ActivityStoryApplyReq.parseFrom(message);
// Get activity
var activity = session.getPlayer().getActivityManager().getActivity(StoryActivity.class, req.getActivityId());
if (activity == null) {
return session.encodeMsg(NetMsgId.activity_story_apply_failed_ack);
}
// Apply
boolean success = activity.apply(req.getStoryId(), req.getBuildId());
if (success == false) {
return session.encodeMsg(NetMsgId.activity_story_apply_failed_ack);
}
// Encode and send
return session.encodeMsg(NetMsgId.activity_story_apply_succeed_ack);
}
}
@@ -0,0 +1,39 @@
package emu.nebula.server.handlers;
import emu.nebula.net.NetHandler;
import emu.nebula.net.NetMsgId;
import emu.nebula.proto.ActivityStorySettleOuterClass.ActivityStorySettleReq;
import emu.nebula.net.HandlerId;
import emu.nebula.game.activity.type.StoryActivity;
import emu.nebula.net.GameSession;
@HandlerId(NetMsgId.activity_story_settle_req)
public class HandlerActivityStorySettleReq extends NetHandler {
@Override
public byte[] handle(GameSession session, byte[] message) throws Exception {
// Parse req
var req = ActivityStorySettleReq.parseFrom(message);
// Get activity
var activity = session.getPlayer().getActivityManager().getActivity(StoryActivity.class, req.getActivityId());
if (activity == null) {
return session.encodeMsg(NetMsgId.activity_story_settle_failed_ack);
}
// Apply
var change = activity.settle(req.getMutableList(), req.getMutableEvidences());
if (change == null) {
return session.encodeMsg(NetMsgId.activity_story_settle_failed_ack);
}
// Handle client events for achievements
session.getPlayer().getAchievementManager().handleClientEvents(req.getEvents());
// Encode and send
return session.encodeMsg(NetMsgId.activity_story_settle_succeed_ack, change.toProto());
}
}
+1 -1
View File
@@ -2,6 +2,6 @@
"global": 134, "global": 134,
"kr": 139, "kr": 139,
"jp": 137, "jp": 137,
"tw": 142, "tw": 143,
"cn": 133 "cn": 133
} }