mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-02-12 21:43:56 +08:00
Merge branch 'development' into patch-3
This commit is contained in:
commit
85821eb16b
@ -70,7 +70,7 @@ dependencies {
|
|||||||
|
|
||||||
implementation group: 'io.netty', name: 'netty-all', version: '4.1.71.Final'
|
implementation group: 'io.netty', name: 'netty-all', version: '4.1.71.Final'
|
||||||
|
|
||||||
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.8'
|
implementation group: 'com.google.code.gson', name: 'gson', version: '2.9.0'
|
||||||
implementation group: 'com.google.protobuf', name: 'protobuf-java', version: '3.18.2'
|
implementation group: 'com.google.protobuf', name: 'protobuf-java', version: '3.18.2'
|
||||||
|
|
||||||
implementation group: 'org.reflections', name: 'reflections', version: '0.10.2'
|
implementation group: 'org.reflections', name: 'reflections', version: '0.10.2'
|
||||||
|
5
data/TowerSchedule.json
Normal file
5
data/TowerSchedule.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"scheduleId" : 1,
|
||||||
|
"scheduleStartTime" : "2022-05-01T00:00:00+08:00",
|
||||||
|
"nextScheduleChangeTime" : "2022-05-30T00:00:00+08:00"
|
||||||
|
}
|
11
proto/AbilityActionGenerateElemBall.proto
Normal file
11
proto/AbilityActionGenerateElemBall.proto
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "Vector.proto";
|
||||||
|
|
||||||
|
message AbilityActionGenerateElemBall {
|
||||||
|
Vector pos = 1;
|
||||||
|
Vector rot = 2;
|
||||||
|
uint32 room_id = 3;
|
||||||
|
}
|
21
proto/AbilityMetaModifierChange.proto
Normal file
21
proto/AbilityMetaModifierChange.proto
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "ModifierAction.proto";
|
||||||
|
import "AbilityString.proto";
|
||||||
|
import "AbilityAttachedModifier.proto";
|
||||||
|
import "ModifierProperty.proto";
|
||||||
|
|
||||||
|
message AbilityMetaModifierChange {
|
||||||
|
ModifierAction action = 1;
|
||||||
|
AbilityString parent_ability_name = 2;
|
||||||
|
AbilityString parent_ability_override = 3;
|
||||||
|
AbilityAttachedModifier attached_instanced_modifier = 4;
|
||||||
|
repeated ModifierProperty properties = 5;
|
||||||
|
int32 modifier_local_id = 6;
|
||||||
|
bool is_mute_remote = 7;
|
||||||
|
uint32 apply_entity_id = 8;
|
||||||
|
bool is_attached_parent_ability = 9;
|
||||||
|
uint32 server_buff_uid = 10;
|
||||||
|
}
|
9
proto/AbilityMetaReInitOverrideMap.proto
Normal file
9
proto/AbilityMetaReInitOverrideMap.proto
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "AbilityScalarValueEntry.proto";
|
||||||
|
|
||||||
|
message AbilityMetaReInitOverrideMap {
|
||||||
|
repeated AbilityScalarValueEntry override_map = 1;
|
||||||
|
}
|
8
proto/ModifierAction.proto
Normal file
8
proto/ModifierAction.proto
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
enum ModifierAction {
|
||||||
|
ADDED = 0;
|
||||||
|
REMOVED = 1;
|
||||||
|
}
|
10
proto/ModifierProperty.proto
Normal file
10
proto/ModifierProperty.proto
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "emu.grasscutter.net.proto";
|
||||||
|
|
||||||
|
import "AbilityString.proto";
|
||||||
|
|
||||||
|
message ModifierProperty {
|
||||||
|
AbilityString key = 1;
|
||||||
|
float value = 2;
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package emu.grasscutter.command.commands;
|
||||||
|
|
||||||
|
import emu.grasscutter.command.Command;
|
||||||
|
import emu.grasscutter.command.CommandHandler;
|
||||||
|
import emu.grasscutter.game.player.Player;
|
||||||
|
import emu.grasscutter.game.tower.TowerLevelRecord;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
|
||||||
|
@Command(label = "unlocktower", usage = "unlocktower", aliases = {"ut"},
|
||||||
|
description = "Unlock all levels of tower", permission = "player.tower")
|
||||||
|
public class UnlockTowerCommand implements CommandHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||||
|
unlockFloor(sender, sender.getServer().getTowerScheduleManager()
|
||||||
|
.getCurrentTowerScheduleData().getEntranceFloorId());
|
||||||
|
|
||||||
|
unlockFloor(sender, sender.getServer().getTowerScheduleManager()
|
||||||
|
.getScheduleFloors());
|
||||||
|
|
||||||
|
CommandHandler.sendMessage(sender, translate("commands.tower.unlock_done"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unlockFloor(Player player, List<Integer> floors){
|
||||||
|
floors.stream()
|
||||||
|
.filter(id -> !player.getTowerManager().getRecordMap().containsKey(id))
|
||||||
|
.forEach(id -> player.getTowerManager().getRecordMap().put(id, new TowerLevelRecord(id)));
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,8 @@ import java.util.Map;
|
|||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
import emu.grasscutter.data.custom.AbilityEmbryoEntry;
|
import emu.grasscutter.data.custom.AbilityEmbryoEntry;
|
||||||
|
import emu.grasscutter.data.custom.AbilityModifier;
|
||||||
|
import emu.grasscutter.data.custom.AbilityModifierEntry;
|
||||||
import emu.grasscutter.data.custom.OpenConfigEntry;
|
import emu.grasscutter.data.custom.OpenConfigEntry;
|
||||||
import emu.grasscutter.data.custom.ScenePointEntry;
|
import emu.grasscutter.data.custom.ScenePointEntry;
|
||||||
import emu.grasscutter.data.def.*;
|
import emu.grasscutter.data.def.*;
|
||||||
@ -22,6 +24,7 @@ public class GameData {
|
|||||||
// BinOutputs
|
// BinOutputs
|
||||||
private static final Int2ObjectMap<String> abilityHashes = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<String> abilityHashes = new Int2ObjectOpenHashMap<>();
|
||||||
private static final Map<String, AbilityEmbryoEntry> abilityEmbryos = new HashMap<>();
|
private static final Map<String, AbilityEmbryoEntry> abilityEmbryos = new HashMap<>();
|
||||||
|
private static final Map<String, AbilityModifierEntry> abilityModifiers = new HashMap<>();
|
||||||
private static final Map<String, OpenConfigEntry> openConfigEntries = new HashMap<>();
|
private static final Map<String, OpenConfigEntry> openConfigEntries = new HashMap<>();
|
||||||
private static final Map<String, ScenePointEntry> scenePointEntries = new HashMap<>();
|
private static final Map<String, ScenePointEntry> scenePointEntries = new HashMap<>();
|
||||||
|
|
||||||
@ -70,6 +73,7 @@ public class GameData {
|
|||||||
private static final Int2ObjectMap<RewardPreviewData> rewardPreviewDataMap = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<RewardPreviewData> rewardPreviewDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
private static final Int2ObjectMap<TowerFloorData> towerFloorDataMap = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<TowerFloorData> towerFloorDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
private static final Int2ObjectMap<TowerLevelData> towerLevelDataMap = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<TowerLevelData> towerLevelDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
private static final Int2ObjectMap<TowerScheduleData> towerScheduleDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
// Cache
|
// Cache
|
||||||
private static Map<Integer, List<Integer>> fetters = new HashMap<>();
|
private static Map<Integer, List<Integer>> fetters = new HashMap<>();
|
||||||
@ -101,6 +105,10 @@ public class GameData {
|
|||||||
return abilityEmbryos;
|
return abilityEmbryos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Map<String, AbilityModifierEntry> getAbilityModifiers() {
|
||||||
|
return abilityModifiers;
|
||||||
|
}
|
||||||
|
|
||||||
public static Map<String, OpenConfigEntry> getOpenConfigEntries() {
|
public static Map<String, OpenConfigEntry> getOpenConfigEntries() {
|
||||||
return openConfigEntries;
|
return openConfigEntries;
|
||||||
}
|
}
|
||||||
@ -320,4 +328,7 @@ public class GameData {
|
|||||||
public static Int2ObjectMap<TowerLevelData> getTowerLevelDataMap(){
|
public static Int2ObjectMap<TowerLevelData> getTowerLevelDataMap(){
|
||||||
return towerLevelDataMap;
|
return towerLevelDataMap;
|
||||||
}
|
}
|
||||||
|
public static Int2ObjectMap<TowerScheduleData> getTowerScheduleDataMap(){
|
||||||
|
return towerScheduleDataMap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,11 @@ import emu.grasscutter.Grasscutter;
|
|||||||
import emu.grasscutter.data.common.PointData;
|
import emu.grasscutter.data.common.PointData;
|
||||||
import emu.grasscutter.data.common.ScenePointConfig;
|
import emu.grasscutter.data.common.ScenePointConfig;
|
||||||
import emu.grasscutter.data.custom.AbilityEmbryoEntry;
|
import emu.grasscutter.data.custom.AbilityEmbryoEntry;
|
||||||
|
import emu.grasscutter.data.custom.AbilityModifier;
|
||||||
|
import emu.grasscutter.data.custom.AbilityModifier.AbilityConfigData;
|
||||||
|
import emu.grasscutter.data.custom.AbilityModifier.AbilityModifierAction;
|
||||||
|
import emu.grasscutter.data.custom.AbilityModifier.AbilityModifierActionType;
|
||||||
|
import emu.grasscutter.data.custom.AbilityModifierEntry;
|
||||||
import emu.grasscutter.data.custom.OpenConfigEntry;
|
import emu.grasscutter.data.custom.OpenConfigEntry;
|
||||||
import emu.grasscutter.data.custom.ScenePointEntry;
|
import emu.grasscutter.data.custom.ScenePointEntry;
|
||||||
import emu.grasscutter.game.world.SpawnDataEntry;
|
import emu.grasscutter.game.world.SpawnDataEntry;
|
||||||
@ -47,6 +52,7 @@ public class ResourceLoader {
|
|||||||
// Load ability lists
|
// Load ability lists
|
||||||
loadAbilityEmbryos();
|
loadAbilityEmbryos();
|
||||||
loadOpenConfig();
|
loadOpenConfig();
|
||||||
|
loadAbilityModifiers();
|
||||||
// Load resources
|
// Load resources
|
||||||
loadResources();
|
loadResources();
|
||||||
// Process into depots
|
// Process into depots
|
||||||
@ -244,6 +250,69 @@ public class ResourceLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void loadAbilityModifiers() {
|
||||||
|
// Load from BinOutput
|
||||||
|
File folder = new File(Utils.toFilePath(Grasscutter.getConfig().RESOURCE_FOLDER + "BinOutput/Ability/Temp/AvatarAbilities/"));
|
||||||
|
File[] files = folder.listFiles();
|
||||||
|
if (files == null) {
|
||||||
|
Grasscutter.getLogger().error("Error loading ability modifiers: no files found in " + folder.getAbsolutePath());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (File file : files) {
|
||||||
|
List<AbilityConfigData> abilityConfigList = null;
|
||||||
|
|
||||||
|
try (FileReader fileReader = new FileReader(file)) {
|
||||||
|
abilityConfigList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, AbilityConfigData.class).getType());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (AbilityConfigData data : abilityConfigList) {
|
||||||
|
if (data.Default.modifiers == null || data.Default.modifiers.size() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbilityModifierEntry modifierEntry = new AbilityModifierEntry(data.Default.abilityName);
|
||||||
|
|
||||||
|
for (Entry<String, AbilityModifier> entry : data.Default.modifiers.entrySet()) {
|
||||||
|
AbilityModifier modifier = entry.getValue();
|
||||||
|
|
||||||
|
// Stare.
|
||||||
|
if (modifier.onAdded != null) {
|
||||||
|
for (AbilityModifierAction action : modifier.onAdded) {
|
||||||
|
if (action.$type.contains("HealHP")) {
|
||||||
|
action.type = AbilityModifierActionType.HealHP;
|
||||||
|
modifierEntry.getOnAdded().add(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modifier.onThinkInterval != null) {
|
||||||
|
for (AbilityModifierAction action : modifier.onThinkInterval) {
|
||||||
|
if (action.$type.contains("HealHP")) {
|
||||||
|
action.type = AbilityModifierActionType.HealHP;
|
||||||
|
modifierEntry.getOnThinkInterval().add(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modifier.onRemoved != null) {
|
||||||
|
for (AbilityModifierAction action : modifier.onRemoved) {
|
||||||
|
if (action.$type.contains("HealHP")) {
|
||||||
|
action.type = AbilityModifierActionType.HealHP;
|
||||||
|
modifierEntry.getOnRemoved().add(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GameData.getAbilityModifiers().put(modifierEntry.getName(), modifierEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void loadSpawnData() {
|
private static void loadSpawnData() {
|
||||||
// Read from cached file if exists
|
// Read from cached file if exists
|
||||||
File spawnDataEntries = new File(Grasscutter.getConfig().DATA_FOLDER + "Spawns.json");
|
File spawnDataEntries = new File(Grasscutter.getConfig().DATA_FOLDER + "Spawns.json");
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
package emu.grasscutter.data.custom;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class AbilityModifier {
|
||||||
|
public AbilityModifierAction[] onAdded;
|
||||||
|
public AbilityModifierAction[] onThinkInterval;
|
||||||
|
public AbilityModifierAction[] onRemoved;
|
||||||
|
|
||||||
|
public static class AbilityConfigData {
|
||||||
|
public AbilityData Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AbilityData {
|
||||||
|
public String abilityName;
|
||||||
|
public Map<String, AbilityModifier> modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AbilityModifierAction {
|
||||||
|
public String $type;
|
||||||
|
public AbilityModifierActionType type;
|
||||||
|
public String target;
|
||||||
|
public AbilityModifierValue amount;
|
||||||
|
public AbilityModifierValue amountByTargetCurrentHPRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AbilityModifierValue {
|
||||||
|
public boolean isFormula;
|
||||||
|
public boolean isDynamic;
|
||||||
|
public String dynamicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AbilityModifierActionType {
|
||||||
|
HealHP, ApplyModifier, LoseHP;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package emu.grasscutter.data.custom;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import emu.grasscutter.data.custom.AbilityModifier.AbilityModifierAction;
|
||||||
|
|
||||||
|
public class AbilityModifierEntry {
|
||||||
|
private String name; // Custom value
|
||||||
|
public List<AbilityModifierAction> onModifierAdded;
|
||||||
|
public List<AbilityModifierAction> onThinkInterval;
|
||||||
|
public List<AbilityModifierAction> onRemoved;
|
||||||
|
|
||||||
|
public AbilityModifierEntry(String name) {
|
||||||
|
this.name = name;
|
||||||
|
this.onModifierAdded = new ArrayList<>();
|
||||||
|
this.onThinkInterval = new ArrayList<>();
|
||||||
|
this.onRemoved = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AbilityModifierAction> getOnAdded() {
|
||||||
|
return onModifierAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AbilityModifierAction> getOnThinkInterval() {
|
||||||
|
return onThinkInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AbilityModifierAction> getOnRemoved() {
|
||||||
|
return onRemoved;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package emu.grasscutter.data.def;
|
||||||
|
|
||||||
|
import emu.grasscutter.data.GameResource;
|
||||||
|
import emu.grasscutter.data.ResourceType;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@ResourceType(name = "TowerScheduleExcelConfigData.json")
|
||||||
|
public class TowerScheduleData extends GameResource {
|
||||||
|
private int ScheduleId;
|
||||||
|
private List<Integer> EntranceFloorId;
|
||||||
|
private List<ScheduleDetail> Schedules;
|
||||||
|
private int MonthlyLevelConfigId;
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return ScheduleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
super.onLoad();
|
||||||
|
this.Schedules = this.Schedules.stream()
|
||||||
|
.filter(item -> item.getFloorList().size() > 0)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getScheduleId() {
|
||||||
|
return ScheduleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScheduleId(int scheduleId) {
|
||||||
|
ScheduleId = scheduleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Integer> getEntranceFloorId() {
|
||||||
|
return EntranceFloorId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEntranceFloorId(List<Integer> entranceFloorId) {
|
||||||
|
EntranceFloorId = entranceFloorId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ScheduleDetail> getSchedules() {
|
||||||
|
return Schedules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSchedules(List<ScheduleDetail> schedules) {
|
||||||
|
Schedules = schedules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMonthlyLevelConfigId() {
|
||||||
|
return MonthlyLevelConfigId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMonthlyLevelConfigId(int monthlyLevelConfigId) {
|
||||||
|
MonthlyLevelConfigId = monthlyLevelConfigId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ScheduleDetail{
|
||||||
|
private List<Integer> FloorList;
|
||||||
|
|
||||||
|
public List<Integer> getFloorList() {
|
||||||
|
return FloorList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFloorList(List<Integer> floorList) {
|
||||||
|
FloorList = floorList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
202
src/main/java/emu/grasscutter/game/ability/AbilityManager.java
Normal file
202
src/main/java/emu/grasscutter/game/ability/AbilityManager.java
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
package emu.grasscutter.game.ability;
|
||||||
|
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
|
||||||
|
import emu.grasscutter.Grasscutter;
|
||||||
|
import emu.grasscutter.data.GameData;
|
||||||
|
import emu.grasscutter.data.custom.AbilityModifier;
|
||||||
|
import emu.grasscutter.data.custom.AbilityModifier.AbilityModifierAction;
|
||||||
|
import emu.grasscutter.data.custom.AbilityModifier.AbilityModifierActionType;
|
||||||
|
import emu.grasscutter.data.def.ItemData;
|
||||||
|
import emu.grasscutter.data.custom.AbilityModifierEntry;
|
||||||
|
import emu.grasscutter.game.entity.EntityItem;
|
||||||
|
import emu.grasscutter.game.entity.GameEntity;
|
||||||
|
import emu.grasscutter.game.player.Player;
|
||||||
|
import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall;
|
||||||
|
import emu.grasscutter.net.proto.AbilityInvokeArgumentOuterClass.AbilityInvokeArgument;
|
||||||
|
import emu.grasscutter.net.proto.AbilityInvokeEntryHeadOuterClass.AbilityInvokeEntryHead;
|
||||||
|
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
||||||
|
import emu.grasscutter.net.proto.AbilityMetaModifierChangeOuterClass.AbilityMetaModifierChange;
|
||||||
|
import emu.grasscutter.net.proto.AbilityMetaReInitOverrideMapOuterClass.AbilityMetaReInitOverrideMap;
|
||||||
|
import emu.grasscutter.net.proto.AbilityScalarTypeOuterClass.AbilityScalarType;
|
||||||
|
import emu.grasscutter.net.proto.AbilityScalarValueEntryOuterClass.AbilityScalarValueEntry;
|
||||||
|
import emu.grasscutter.net.proto.ModifierActionOuterClass.ModifierAction;
|
||||||
|
import emu.grasscutter.utils.Position;
|
||||||
|
import emu.grasscutter.utils.Utils;
|
||||||
|
|
||||||
|
public class AbilityManager {
|
||||||
|
private Player player;
|
||||||
|
|
||||||
|
public AbilityManager(Player player) {
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return this.player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAbilityInvoke(AbilityInvokeEntry invoke) throws Exception {
|
||||||
|
//System.out.println(invoke.getArgumentType() + " (" + invoke.getArgumentTypeValue() + "): " + Utils.bytesToHex(invoke.toByteArray()));
|
||||||
|
switch (invoke.getArgumentType()) {
|
||||||
|
case ABILITY_META_OVERRIDE_PARAM:
|
||||||
|
handleOverrideParam(invoke);
|
||||||
|
break;
|
||||||
|
case ABILITY_META_REINIT_OVERRIDEMAP:
|
||||||
|
handleReinitOverrideMap(invoke);
|
||||||
|
break;
|
||||||
|
case ABILITY_META_MODIFIER_CHANGE:
|
||||||
|
handleModifierChange(invoke);
|
||||||
|
break;
|
||||||
|
case ABILITY_MIXIN_COST_STAMINA:
|
||||||
|
handleMixinCostStamina(invoke);
|
||||||
|
break;
|
||||||
|
case ABILITY_ACTION_GENERATE_ELEM_BALL:
|
||||||
|
handleGenerateElemBall(invoke);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleOverrideParam(AbilityInvokeEntry invoke) throws Exception {
|
||||||
|
GameEntity entity = player.getScene().getEntityById(invoke.getEntityId());
|
||||||
|
|
||||||
|
if (entity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbilityScalarValueEntry entry = AbilityScalarValueEntry.parseFrom(invoke.getAbilityData());
|
||||||
|
|
||||||
|
entity.getMetaOverrideMap().put(entry.getKey().getStr(), entry.getFloatValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleReinitOverrideMap(AbilityInvokeEntry invoke) throws Exception {
|
||||||
|
GameEntity entity = player.getScene().getEntityById(invoke.getEntityId());
|
||||||
|
|
||||||
|
if (entity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbilityMetaReInitOverrideMap map = AbilityMetaReInitOverrideMap.parseFrom(invoke.getAbilityData());
|
||||||
|
|
||||||
|
for (AbilityScalarValueEntry entry : map.getOverrideMapList()) {
|
||||||
|
entity.getMetaOverrideMap().put(entry.getKey().getStr(), entry.getFloatValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleModifierChange(AbilityInvokeEntry invoke) throws Exception {
|
||||||
|
GameEntity target = player.getScene().getEntityById(invoke.getEntityId());
|
||||||
|
if (target == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbilityInvokeEntryHead head = invoke.getHead();
|
||||||
|
if (head == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbilityMetaModifierChange data = AbilityMetaModifierChange.parseFrom(invoke.getAbilityData());
|
||||||
|
if (data == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameEntity sourceEntity = player.getScene().getEntityById(data.getApplyEntityId());
|
||||||
|
if (sourceEntity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is not how it works but we will keep it for now since healing abilities dont work properly anyways
|
||||||
|
if (data.getAction() == ModifierAction.ADDED && data.getParentAbilityName() != null) {
|
||||||
|
// Handle add modifier here
|
||||||
|
String modifierString = data.getParentAbilityName().getStr();
|
||||||
|
AbilityModifierEntry modifier = GameData.getAbilityModifiers().get(modifierString);
|
||||||
|
|
||||||
|
if (modifier != null && modifier.getOnAdded().size() > 0) {
|
||||||
|
for (AbilityModifierAction action : modifier.getOnAdded()) {
|
||||||
|
invokeAction(action, target, sourceEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to meta modifier list
|
||||||
|
target.getMetaModifiers().put(head.getInstancedModifierId(), modifierString);
|
||||||
|
} else if (data.getAction() == ModifierAction.REMOVED) {
|
||||||
|
String modifierString = target.getMetaModifiers().get(head.getInstancedModifierId());
|
||||||
|
|
||||||
|
if (modifierString != null) {
|
||||||
|
// Get modifier and call on remove event
|
||||||
|
AbilityModifierEntry modifier = GameData.getAbilityModifiers().get(modifierString);
|
||||||
|
|
||||||
|
if (modifier != null && modifier.getOnRemoved().size() > 0) {
|
||||||
|
for (AbilityModifierAction action : modifier.getOnRemoved()) {
|
||||||
|
invokeAction(action, target, sourceEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from meta modifiers
|
||||||
|
target.getMetaModifiers().remove(head.getInstancedModifierId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleMixinCostStamina(AbilityInvokeEntry invoke) {
|
||||||
|
// Not the right way of doing this
|
||||||
|
if (Grasscutter.getConfig().OpenStamina) {
|
||||||
|
// getPlayer().getStaminaManager().updateStamina(getPlayer().getSession(), -450);
|
||||||
|
// TODO
|
||||||
|
// set flag in stamina/movement manager that specifies the player is currently using an alternate sprint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleGenerateElemBall(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException {
|
||||||
|
AbilityActionGenerateElemBall action = AbilityActionGenerateElemBall.parseFrom(invoke.getAbilityData());
|
||||||
|
if (action == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemData itemData = GameData.getItemDataMap().get(2024);
|
||||||
|
if (itemData == null) {
|
||||||
|
return; // Should never happen
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityItem energyBall = new EntityItem(getPlayer().getScene(), getPlayer(), itemData, new Position(action.getPos()), 1);
|
||||||
|
energyBall.getRotation().set(action.getRot());
|
||||||
|
|
||||||
|
getPlayer().getScene().addEntity(energyBall);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invokeAction(AbilityModifierAction action, GameEntity target, GameEntity sourceEntity) {
|
||||||
|
switch (action.type) {
|
||||||
|
case HealHP -> {
|
||||||
|
if (action.amount == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float healAmount = 0;
|
||||||
|
|
||||||
|
if (action.amount.isDynamic && action.amount.dynamicKey != null) {
|
||||||
|
healAmount = sourceEntity.getMetaOverrideMap().getOrDefault(action.amount.dynamicKey, 0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (healAmount > 0) {
|
||||||
|
target.heal(healAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case LoseHP -> {
|
||||||
|
if (action.amountByTargetCurrentHPRatio == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float damageAmount = 0;
|
||||||
|
|
||||||
|
if (action.amount.isDynamic && action.amount.dynamicKey != null) {
|
||||||
|
damageAmount = sourceEntity.getMetaOverrideMap().getOrDefault(action.amount.dynamicKey, 0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (damageAmount > 0) {
|
||||||
|
target.damage(damageAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -69,6 +69,7 @@ public class Avatar {
|
|||||||
|
|
||||||
@Transient private Player owner;
|
@Transient private Player owner;
|
||||||
@Transient private AvatarData data;
|
@Transient private AvatarData data;
|
||||||
|
@Transient private AvatarSkillDepotData skillDepot;
|
||||||
@Transient private long guid; // Player unique id
|
@Transient private long guid; // Player unique id
|
||||||
private int avatarId; // Id of avatar
|
private int avatarId; // Id of avatar
|
||||||
|
|
||||||
@ -103,8 +104,8 @@ public class Avatar {
|
|||||||
private int nameCardRewardId;
|
private int nameCardRewardId;
|
||||||
private int nameCardId;
|
private int nameCardId;
|
||||||
|
|
||||||
|
@Deprecated // Do not use. Morhpia only!
|
||||||
public Avatar() {
|
public Avatar() {
|
||||||
// Morhpia only!
|
|
||||||
this.equips = new Int2ObjectOpenHashMap<>();
|
this.equips = new Int2ObjectOpenHashMap<>();
|
||||||
this.fightProp = new Int2FloatOpenHashMap();
|
this.fightProp = new Int2FloatOpenHashMap();
|
||||||
this.extraAbilityEmbryos = new HashSet<>();
|
this.extraAbilityEmbryos = new HashSet<>();
|
||||||
@ -140,7 +141,7 @@ public class Avatar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Skill depot
|
// Skill depot
|
||||||
this.setSkillDepot(getAvatarData().getSkillDepot());
|
this.setSkillDepotData(getAvatarData().getSkillDepot());
|
||||||
|
|
||||||
// Set stats
|
// Set stats
|
||||||
this.recalcStats();
|
this.recalcStats();
|
||||||
@ -164,7 +165,8 @@ public class Avatar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void setAvatarData(AvatarData data) {
|
protected void setAvatarData(AvatarData data) {
|
||||||
this.data = data;
|
if (this.data != null) return;
|
||||||
|
this.data = data; // Used while loading this from the database
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOwnerId() {
|
public int getOwnerId() {
|
||||||
@ -257,9 +259,19 @@ public class Avatar {
|
|||||||
return skillDepotId;
|
return skillDepotId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSkillDepot(AvatarSkillDepotData skillDepot) {
|
public AvatarSkillDepotData getSkillDepot() {
|
||||||
// Set id
|
return skillDepot;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setSkillDepot(AvatarSkillDepotData skillDepot) {
|
||||||
|
if (this.skillDepot != null) return;
|
||||||
|
this.skillDepot = skillDepot; // Used while loading this from the database
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSkillDepotData(AvatarSkillDepotData skillDepot) {
|
||||||
|
// Set id and depot
|
||||||
this.skillDepotId = skillDepot.getId();
|
this.skillDepotId = skillDepot.getId();
|
||||||
|
this.skillDepot = skillDepot;
|
||||||
// Clear, then add skills
|
// Clear, then add skills
|
||||||
getSkillLevelMap().clear();
|
getSkillLevelMap().clear();
|
||||||
if (skillDepot.getEnergySkill() > 0) {
|
if (skillDepot.getEnergySkill() > 0) {
|
||||||
@ -501,8 +513,8 @@ public class Avatar {
|
|||||||
// Set energy usage
|
// Set energy usage
|
||||||
if (data.getSkillDepot() != null && data.getSkillDepot().getEnergySkillData() != null) {
|
if (data.getSkillDepot() != null && data.getSkillDepot().getEnergySkillData() != null) {
|
||||||
ElementType element = data.getSkillDepot().getElementType();
|
ElementType element = data.getSkillDepot().getElementType();
|
||||||
this.setFightProperty(element.getEnergyProperty(), data.getSkillDepot().getEnergySkillData().getCostElemVal());
|
this.setFightProperty(element.getMaxEnergyProp(), data.getSkillDepot().getEnergySkillData().getCostElemVal());
|
||||||
this.setFightProperty((element.getEnergyProperty().getId() % 70) + 1000, data.getSkillDepot().getEnergySkillData().getCostElemVal());
|
this.setFightProperty((element.getMaxEnergyProp().getId() % 70) + 1000, data.getSkillDepot().getEnergySkillData().getCostElemVal());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Artifacts
|
// Artifacts
|
||||||
|
@ -5,6 +5,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.def.AvatarData;
|
import emu.grasscutter.data.def.AvatarData;
|
||||||
|
import emu.grasscutter.data.def.AvatarSkillDepotData;
|
||||||
import emu.grasscutter.database.DatabaseHelper;
|
import emu.grasscutter.database.DatabaseHelper;
|
||||||
import emu.grasscutter.game.entity.EntityAvatar;
|
import emu.grasscutter.game.entity.EntityAvatar;
|
||||||
import emu.grasscutter.game.inventory.GameItem;
|
import emu.grasscutter.game.inventory.GameItem;
|
||||||
@ -139,12 +140,14 @@ public class AvatarStorage implements Iterable<Avatar> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AvatarData avatarData = GameData.getAvatarDataMap().get(avatar.getAvatarId());
|
AvatarData avatarData = GameData.getAvatarDataMap().get(avatar.getAvatarId());
|
||||||
if (avatarData == null) {
|
AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(avatar.getSkillDepotId());
|
||||||
|
if (avatarData == null || skillDepot == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set ownerships
|
// Set ownerships
|
||||||
avatar.setAvatarData(avatarData);
|
avatar.setAvatarData(avatarData);
|
||||||
|
avatar.setSkillDepot(skillDepot);
|
||||||
avatar.setOwner(getPlayer());
|
avatar.setOwner(getPlayer());
|
||||||
|
|
||||||
// Force recalc of const boosted skills
|
// Force recalc of const boosted skills
|
||||||
|
@ -12,12 +12,18 @@ public class TowerDungeonSettleListener implements DungeonSettleListener {
|
|||||||
scene.setAutoCloseTime(Utils.getCurrentSeconds() + 1000);
|
scene.setAutoCloseTime(Utils.getCurrentSeconds() + 1000);
|
||||||
var towerManager = scene.getPlayers().get(0).getTowerManager();
|
var towerManager = scene.getPlayers().get(0).getTowerManager();
|
||||||
|
|
||||||
towerManager.notifyCurLevelRecordChangeWhenDone();
|
towerManager.notifyCurLevelRecordChangeWhenDone(3);
|
||||||
scene.broadcastPacket(new PacketTowerFloorRecordChangeNotify(towerManager.getCurrentFloorId()));
|
scene.broadcastPacket(new PacketTowerFloorRecordChangeNotify(
|
||||||
scene.broadcastPacket(new PacketDungeonSettleNotify(scene.getChallenge(),
|
towerManager.getCurrentFloorId(),
|
||||||
true,
|
3,
|
||||||
|
towerManager.canEnterScheduleFloor()
|
||||||
|
));
|
||||||
|
|
||||||
|
scene.broadcastPacket(new PacketDungeonSettleNotify(
|
||||||
|
scene.getChallenge(),
|
||||||
|
towerManager.hasNextFloor(),
|
||||||
towerManager.hasNextLevel(),
|
towerManager.hasNextLevel(),
|
||||||
towerManager.getNextFloorId()
|
towerManager.hasNextLevel() ? 0 : towerManager.getNextFloorId()
|
||||||
));
|
));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,17 +17,22 @@ import emu.grasscutter.net.proto.AbilityControlBlockOuterClass.AbilityControlBlo
|
|||||||
import emu.grasscutter.net.proto.AbilityEmbryoOuterClass.AbilityEmbryo;
|
import emu.grasscutter.net.proto.AbilityEmbryoOuterClass.AbilityEmbryo;
|
||||||
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
||||||
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
|
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
|
||||||
|
import emu.grasscutter.net.proto.ChangeHpReasonOuterClass.ChangeHpReason;
|
||||||
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
|
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
|
||||||
import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData;
|
import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData;
|
||||||
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
|
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
|
||||||
import emu.grasscutter.net.proto.FightPropPairOuterClass.FightPropPair;
|
import emu.grasscutter.net.proto.FightPropPairOuterClass.FightPropPair;
|
||||||
import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType;
|
import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType;
|
||||||
|
import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
|
||||||
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
|
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
|
||||||
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
|
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
|
||||||
import emu.grasscutter.net.proto.SceneAvatarInfoOuterClass.SceneAvatarInfo;
|
import emu.grasscutter.net.proto.SceneAvatarInfoOuterClass.SceneAvatarInfo;
|
||||||
import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
|
import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
|
||||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||||
|
import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify;
|
||||||
|
import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify;
|
||||||
|
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import emu.grasscutter.utils.ProtoHelper;
|
import emu.grasscutter.utils.ProtoHelper;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
@ -110,6 +115,35 @@ public class EntityAvatar extends GameEntity {
|
|||||||
this.killedBy = killerId;
|
this.killedBy = killerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float heal(float amount) {
|
||||||
|
float healed = super.heal(amount);
|
||||||
|
|
||||||
|
if (healed > 0f) {
|
||||||
|
getScene().broadcastPacket(
|
||||||
|
new PacketEntityFightPropChangeReasonNotify(this, FightProperty.FIGHT_PROP_CUR_HP, healed, PropChangeReason.PROP_CHANGE_ABILITY, ChangeHpReason.ChangeHpAddAbility)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return healed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addEnergy(float amount) {
|
||||||
|
FightProperty curEnergyProp = getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
||||||
|
FightProperty maxEnergyProp = getAvatar().getSkillDepot().getElementType().getMaxEnergyProp();
|
||||||
|
|
||||||
|
float curEnergy = this.getFightProperty(curEnergyProp);
|
||||||
|
float maxEnergy = this.getFightProperty(maxEnergyProp);
|
||||||
|
float newEnergy = Math.min(curEnergy + amount, maxEnergy);
|
||||||
|
|
||||||
|
if (newEnergy != curEnergy) {
|
||||||
|
setFightProperty(curEnergyProp, newEnergy);
|
||||||
|
|
||||||
|
getScene().broadcastPacket(new PacketAvatarFightPropUpdateNotify(getAvatar(), curEnergyProp));
|
||||||
|
getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, newEnergy, PropChangeReason.PROP_CHANGE_ENERGY_BALL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public SceneAvatarInfo getSceneAvatarInfo() {
|
public SceneAvatarInfo getSceneAvatarInfo() {
|
||||||
SceneAvatarInfo.Builder avatarInfo = SceneAvatarInfo.newBuilder()
|
SceneAvatarInfo.Builder avatarInfo = SceneAvatarInfo.newBuilder()
|
||||||
.setUid(this.getPlayer().getUid())
|
.setUid(this.getPlayer().getUid())
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package emu.grasscutter.game.entity;
|
package emu.grasscutter.game.entity;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.game.props.LifeState;
|
import emu.grasscutter.game.props.LifeState;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
@ -9,8 +12,11 @@ import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
|||||||
import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState;
|
import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState;
|
||||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||||
|
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
|
||||||
public abstract class GameEntity {
|
public abstract class GameEntity {
|
||||||
protected int id;
|
protected int id;
|
||||||
@ -25,6 +31,10 @@ public abstract class GameEntity {
|
|||||||
private int lastMoveSceneTimeMs;
|
private int lastMoveSceneTimeMs;
|
||||||
private int lastMoveReliableSeq;
|
private int lastMoveReliableSeq;
|
||||||
|
|
||||||
|
// Abilities
|
||||||
|
private Map<String, Float> metaOverrideMap;
|
||||||
|
private Int2ObjectMap<String> metaModifiers;
|
||||||
|
|
||||||
public GameEntity(Scene scene) {
|
public GameEntity(Scene scene) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.moveState = MotionState.MOTION_NONE;
|
this.moveState = MotionState.MOTION_NONE;
|
||||||
@ -54,6 +64,20 @@ public abstract class GameEntity {
|
|||||||
return isAlive() ? LifeState.LIFE_ALIVE : LifeState.LIFE_DEAD;
|
return isAlive() ? LifeState.LIFE_ALIVE : LifeState.LIFE_DEAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, Float> getMetaOverrideMap() {
|
||||||
|
if (this.metaOverrideMap == null) {
|
||||||
|
this.metaOverrideMap = new HashMap<>();
|
||||||
|
}
|
||||||
|
return this.metaOverrideMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Int2ObjectMap<String> getMetaModifiers() {
|
||||||
|
if (this.metaModifiers == null) {
|
||||||
|
this.metaModifiers = new Int2ObjectOpenHashMap<>();
|
||||||
|
}
|
||||||
|
return this.metaModifiers;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract Int2FloatOpenHashMap getFightProperties();
|
public abstract Int2FloatOpenHashMap getFightProperties();
|
||||||
|
|
||||||
public abstract Position getPosition();
|
public abstract Position getPosition();
|
||||||
@ -146,4 +170,53 @@ public abstract class GameEntity {
|
|||||||
public void setSpawnEntry(SpawnDataEntry spawnEntry) {
|
public void setSpawnEntry(SpawnDataEntry spawnEntry) {
|
||||||
this.spawnEntry = spawnEntry;
|
this.spawnEntry = spawnEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float heal(float amount) {
|
||||||
|
if (this.getFightProperties() == null) {
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float curHp = getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||||
|
float maxHp = getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||||
|
|
||||||
|
if (curHp >= maxHp) {
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float healed = Math.min(maxHp - curHp, amount);
|
||||||
|
this.addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, healed);
|
||||||
|
|
||||||
|
getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, FightProperty.FIGHT_PROP_CUR_HP));
|
||||||
|
|
||||||
|
return healed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void damage(float amount) {
|
||||||
|
damage(amount, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void damage(float amount, int killerId) {
|
||||||
|
// Sanity check
|
||||||
|
if (getFightProperties() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lose hp
|
||||||
|
addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, -amount);
|
||||||
|
|
||||||
|
// Check if dead
|
||||||
|
boolean isDead = false;
|
||||||
|
if (getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) <= 0f) {
|
||||||
|
setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f);
|
||||||
|
isDead = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Packets
|
||||||
|
this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, FightProperty.FIGHT_PROP_CUR_HP));
|
||||||
|
|
||||||
|
// Check if dead
|
||||||
|
if (isDead) {
|
||||||
|
getScene().killEntity(this, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,6 +172,9 @@ public class Inventory implements Iterable<GameItem> {
|
|||||||
// Handle
|
// Handle
|
||||||
this.addVirtualItem(item.getItemId(), item.getCount());
|
this.addVirtualItem(item.getItemId(), item.getCount());
|
||||||
return item;
|
return item;
|
||||||
|
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_ADSORBATE) {
|
||||||
|
player.getTeamManager().addEnergyToTeam(item);
|
||||||
|
return null;
|
||||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_AVATAR) {
|
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_AVATAR) {
|
||||||
// Get avatar id
|
// Get avatar id
|
||||||
int avatarId = (item.getItemId() % 1000) + 10000000;
|
int avatarId = (item.getItemId() % 1000) + 10000000;
|
||||||
|
@ -30,7 +30,7 @@ public class InvokeHandler<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void update(Player player) {
|
public synchronized void update(Player player) {
|
||||||
if (player.getWorld() == null) {
|
if (player.getWorld() == null || player.getScene() == null) {
|
||||||
this.entryListForwardAll.clear();
|
this.entryListForwardAll.clear();
|
||||||
this.entryListForwardAllExceptCur.clear();
|
this.entryListForwardAllExceptCur.clear();
|
||||||
this.entryListForwardHost.clear();
|
this.entryListForwardHost.clear();
|
||||||
|
@ -8,6 +8,7 @@ import emu.grasscutter.data.def.PlayerLevelData;
|
|||||||
import emu.grasscutter.database.DatabaseHelper;
|
import emu.grasscutter.database.DatabaseHelper;
|
||||||
import emu.grasscutter.game.Account;
|
import emu.grasscutter.game.Account;
|
||||||
import emu.grasscutter.game.CoopRequest;
|
import emu.grasscutter.game.CoopRequest;
|
||||||
|
import emu.grasscutter.game.ability.AbilityManager;
|
||||||
import emu.grasscutter.game.avatar.Avatar;
|
import emu.grasscutter.game.avatar.Avatar;
|
||||||
import emu.grasscutter.game.avatar.AvatarProfileData;
|
import emu.grasscutter.game.avatar.AvatarProfileData;
|
||||||
import emu.grasscutter.game.avatar.AvatarStorage;
|
import emu.grasscutter.game.avatar.AvatarStorage;
|
||||||
@ -89,6 +90,7 @@ public class Player {
|
|||||||
@Transient private FriendsList friendsList;
|
@Transient private FriendsList friendsList;
|
||||||
@Transient private MailHandler mailHandler;
|
@Transient private MailHandler mailHandler;
|
||||||
@Transient private MessageHandler messageHandler;
|
@Transient private MessageHandler messageHandler;
|
||||||
|
@Transient private AbilityManager abilityManager;
|
||||||
|
|
||||||
@Transient private SotSManager sotsManager;
|
@Transient private SotSManager sotsManager;
|
||||||
|
|
||||||
@ -142,6 +144,7 @@ public class Player {
|
|||||||
this.friendsList = new FriendsList(this);
|
this.friendsList = new FriendsList(this);
|
||||||
this.mailHandler = new MailHandler(this);
|
this.mailHandler = new MailHandler(this);
|
||||||
this.towerManager = new TowerManager(this);
|
this.towerManager = new TowerManager(this);
|
||||||
|
this.abilityManager = new AbilityManager(this);
|
||||||
this.pos = new Position();
|
this.pos = new Position();
|
||||||
this.rotation = new Position();
|
this.rotation = new Position();
|
||||||
this.properties = new HashMap<>();
|
this.properties = new HashMap<>();
|
||||||
@ -1025,6 +1028,10 @@ public class Player {
|
|||||||
|
|
||||||
public SotSManager getSotSManager() { return sotsManager; }
|
public SotSManager getSotSManager() { return sotsManager; }
|
||||||
|
|
||||||
|
public AbilityManager getAbilityManager() {
|
||||||
|
return abilityManager;
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void onTick() {
|
public synchronized void onTick() {
|
||||||
// Check ping
|
// Check ping
|
||||||
if (this.getLastPingTime() > System.currentTimeMillis() + 60000) {
|
if (this.getLastPingTime() > System.currentTimeMillis() + 60000) {
|
||||||
|
@ -10,6 +10,7 @@ import emu.grasscutter.data.def.AvatarSkillDepotData;
|
|||||||
import emu.grasscutter.game.avatar.Avatar;
|
import emu.grasscutter.game.avatar.Avatar;
|
||||||
import emu.grasscutter.game.entity.EntityAvatar;
|
import emu.grasscutter.game.entity.EntityAvatar;
|
||||||
import emu.grasscutter.game.entity.EntityBaseGadget;
|
import emu.grasscutter.game.entity.EntityBaseGadget;
|
||||||
|
import emu.grasscutter.game.inventory.GameItem;
|
||||||
import emu.grasscutter.game.props.ElementType;
|
import emu.grasscutter.game.props.ElementType;
|
||||||
import emu.grasscutter.game.props.EnterReason;
|
import emu.grasscutter.game.props.EnterReason;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
@ -580,6 +581,24 @@ public class TeamManager {
|
|||||||
getPlayer().sendPacket(new BasePacket(PacketOpcodes.WorldPlayerReviveRsp));
|
getPlayer().sendPacket(new BasePacket(PacketOpcodes.WorldPlayerReviveRsp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void addEnergyToTeam(GameItem energyBall) {
|
||||||
|
// TODO
|
||||||
|
float baseEnergy = 2;
|
||||||
|
|
||||||
|
for (int i = 0; i < getActiveTeam().size(); i++) {
|
||||||
|
EntityAvatar entity = getActiveTeam().get(i);
|
||||||
|
|
||||||
|
float energyGain = baseEnergy;
|
||||||
|
|
||||||
|
// Active character gets full hp
|
||||||
|
if (getCurrentCharacterIndex() != i) {
|
||||||
|
energyGain *= Math.max(1.0 - (getActiveTeam().size() * .1f), .6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.addEnergy(energyGain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void saveAvatars() {
|
public void saveAvatars() {
|
||||||
// Save all avatars from active team
|
// Save all avatars from active team
|
||||||
for (EntityAvatar entity : getActiveTeam()) {
|
for (EntityAvatar entity : getActiveTeam()) {
|
||||||
|
@ -9,21 +9,22 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
|||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
|
||||||
public enum ElementType {
|
public enum ElementType {
|
||||||
None (0, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
None (0, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
||||||
Fire (1, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, 10101, "TeamResonance_Fire_Lv2"),
|
Fire (1, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, 10101, "TeamResonance_Fire_Lv2"),
|
||||||
Water (2, FightProperty.FIGHT_PROP_MAX_WATER_ENERGY, 10201, "TeamResonance_Water_Lv2"),
|
Water (2, FightProperty.FIGHT_PROP_CUR_WATER_ENERGY, FightProperty.FIGHT_PROP_MAX_WATER_ENERGY, 10201, "TeamResonance_Water_Lv2"),
|
||||||
Grass (3, FightProperty.FIGHT_PROP_MAX_GRASS_ENERGY),
|
Grass (3, FightProperty.FIGHT_PROP_CUR_GRASS_ENERGY, FightProperty.FIGHT_PROP_MAX_GRASS_ENERGY),
|
||||||
Electric (4, FightProperty.FIGHT_PROP_MAX_ELEC_ENERGY, 10401, "TeamResonance_Electric_Lv2"),
|
Electric (4, FightProperty.FIGHT_PROP_CUR_ELEC_ENERGY, FightProperty.FIGHT_PROP_MAX_ELEC_ENERGY, 10401, "TeamResonance_Electric_Lv2"),
|
||||||
Ice (5, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY, 10601, "TeamResonance_Ice_Lv2"),
|
Ice (5, FightProperty.FIGHT_PROP_CUR_ICE_ENERGY, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY, 10601, "TeamResonance_Ice_Lv2"),
|
||||||
Frozen (6, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY),
|
Frozen (6, FightProperty.FIGHT_PROP_CUR_ICE_ENERGY, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY),
|
||||||
Wind (7, FightProperty.FIGHT_PROP_MAX_WIND_ENERGY, 10301, "TeamResonance_Wind_Lv2"),
|
Wind (7, FightProperty.FIGHT_PROP_CUR_WIND_ENERGY, FightProperty.FIGHT_PROP_MAX_WIND_ENERGY, 10301, "TeamResonance_Wind_Lv2"),
|
||||||
Rock (8, FightProperty.FIGHT_PROP_MAX_ROCK_ENERGY, 10701, "TeamResonance_Rock_Lv2"),
|
Rock (8, FightProperty.FIGHT_PROP_CUR_ROCK_ENERGY, FightProperty.FIGHT_PROP_MAX_ROCK_ENERGY, 10701, "TeamResonance_Rock_Lv2"),
|
||||||
AntiFire (9, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
AntiFire (9, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
||||||
Default (255, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, 10801, "TeamResonance_AllDifferent");
|
Default (255, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, 10801, "TeamResonance_AllDifferent");
|
||||||
|
|
||||||
private final int value;
|
private final int value;
|
||||||
private final int teamResonanceId;
|
private final int teamResonanceId;
|
||||||
private final FightProperty energyProperty;
|
private final FightProperty curEnergyProp;
|
||||||
|
private final FightProperty maxEnergyProp;
|
||||||
private final int configHash;
|
private final int configHash;
|
||||||
private static final Int2ObjectMap<ElementType> map = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<ElementType> map = new Int2ObjectOpenHashMap<>();
|
||||||
private static final Map<String, ElementType> stringMap = new HashMap<>();
|
private static final Map<String, ElementType> stringMap = new HashMap<>();
|
||||||
@ -35,13 +36,14 @@ public enum ElementType {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private ElementType(int value, FightProperty energyProperty) {
|
private ElementType(int value, FightProperty curEnergyProp, FightProperty maxEnergyProp) {
|
||||||
this(value, energyProperty, 0, null);
|
this(value, curEnergyProp, maxEnergyProp, 0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ElementType(int value, FightProperty energyProperty, int teamResonanceId, String configName) {
|
private ElementType(int value, FightProperty curEnergyProp, FightProperty maxEnergyProp, int teamResonanceId, String configName) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.energyProperty = energyProperty;
|
this.curEnergyProp = curEnergyProp;
|
||||||
|
this.maxEnergyProp = maxEnergyProp;
|
||||||
this.teamResonanceId = teamResonanceId;
|
this.teamResonanceId = teamResonanceId;
|
||||||
if (configName != null) {
|
if (configName != null) {
|
||||||
this.configHash = Utils.abilityHash(configName);
|
this.configHash = Utils.abilityHash(configName);
|
||||||
@ -54,8 +56,12 @@ public enum ElementType {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FightProperty getEnergyProperty() {
|
public FightProperty getCurEnergyProp() {
|
||||||
return energyProperty;
|
return curEnergyProp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FightProperty getMaxEnergyProp() {
|
||||||
|
return maxEnergyProp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTeamResonanceId() {
|
public int getTeamResonanceId() {
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
package emu.grasscutter.game.tower;
|
||||||
|
|
||||||
|
import dev.morphia.annotations.Entity;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class TowerLevelRecord {
|
||||||
|
/**
|
||||||
|
* floorId in config
|
||||||
|
*/
|
||||||
|
private int floorId;
|
||||||
|
/**
|
||||||
|
* LevelId - Stars
|
||||||
|
*/
|
||||||
|
private Map<Integer, Integer> passedLevelMap;
|
||||||
|
|
||||||
|
private int floorStarRewardProgress;
|
||||||
|
|
||||||
|
public TowerLevelRecord setLevelStars(int levelId, int stars){
|
||||||
|
passedLevelMap.put(levelId, stars);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStarCount() {
|
||||||
|
return passedLevelMap.values().stream().mapToInt(Integer::intValue).sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TowerLevelRecord(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public TowerLevelRecord(int floorId){
|
||||||
|
this.floorId = floorId;
|
||||||
|
this.passedLevelMap = new HashMap<>();
|
||||||
|
this.floorStarRewardProgress = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFloorId() {
|
||||||
|
return floorId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFloorId(int floorId) {
|
||||||
|
this.floorId = floorId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, Integer> getPassedLevelMap() {
|
||||||
|
return passedLevelMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassedLevelMap(Map<Integer, Integer> passedLevelMap) {
|
||||||
|
this.passedLevelMap = passedLevelMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFloorStarRewardProgress() {
|
||||||
|
return floorStarRewardProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFloorStarRewardProgress(int floorStarRewardProgress) {
|
||||||
|
this.floorStarRewardProgress = floorStarRewardProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -9,10 +9,12 @@ import emu.grasscutter.game.dungeons.TowerDungeonSettleListener;
|
|||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.server.packet.send.PacketCanUseSkillNotify;
|
import emu.grasscutter.server.packet.send.PacketCanUseSkillNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketTowerCurLevelRecordChangeNotify;
|
import emu.grasscutter.server.packet.send.PacketTowerCurLevelRecordChangeNotify;
|
||||||
|
|
||||||
import emu.grasscutter.server.packet.send.PacketTowerEnterLevelRsp;
|
import emu.grasscutter.server.packet.send.PacketTowerEnterLevelRsp;
|
||||||
|
import emu.grasscutter.server.packet.send.PacketTowerLevelStarCondNotify;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
public class TowerManager {
|
public class TowerManager {
|
||||||
@ -26,11 +28,19 @@ public class TowerManager {
|
|||||||
this.player = player;
|
this.player = player;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the floor players chose
|
||||||
|
*/
|
||||||
private int currentFloorId;
|
private int currentFloorId;
|
||||||
private int currentLevel;
|
private int currentLevel;
|
||||||
@Transient
|
@Transient
|
||||||
private int currentLevelId;
|
private int currentLevelId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* floorId - Record
|
||||||
|
*/
|
||||||
|
private Map<Integer, TowerLevelRecord> recordMap;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private int entryScene;
|
private int entryScene;
|
||||||
|
|
||||||
@ -38,7 +48,26 @@ public class TowerManager {
|
|||||||
return currentFloorId;
|
return currentFloorId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getCurrentLevelId(){
|
||||||
|
return this.currentLevelId + currentLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* form 1-3
|
||||||
|
*/
|
||||||
|
public int getCurrentLevel(){
|
||||||
|
return currentLevel + 1;
|
||||||
|
}
|
||||||
private static final List<DungeonSettleListener> towerDungeonSettleListener = List.of(new TowerDungeonSettleListener());
|
private static final List<DungeonSettleListener> towerDungeonSettleListener = List.of(new TowerDungeonSettleListener());
|
||||||
|
|
||||||
|
public Map<Integer, TowerLevelRecord> getRecordMap() {
|
||||||
|
if(recordMap == null){
|
||||||
|
recordMap = new HashMap<>();
|
||||||
|
recordMap.put(1001, new TowerLevelRecord(1001));
|
||||||
|
}
|
||||||
|
return recordMap;
|
||||||
|
}
|
||||||
|
|
||||||
public void teamSelect(int floor, List<List<Long>> towerTeams) {
|
public void teamSelect(int floor, List<List<Long>> towerTeams) {
|
||||||
var floorData = GameData.getTowerFloorDataMap().get(floor);
|
var floorData = GameData.getTowerFloorDataMap().get(floor);
|
||||||
|
|
||||||
@ -54,51 +83,73 @@ public class TowerManager {
|
|||||||
entryScene = player.getSceneId();
|
entryScene = player.getSceneId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
player.getTeamManager().setupTemporaryTeam(towerTeams);
|
player.getTeamManager().setupTemporaryTeam(towerTeams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void enterLevel(int enterPointId) {
|
public void enterLevel(int enterPointId) {
|
||||||
var levelData = GameData.getTowerLevelDataMap().get(currentLevelId + currentLevel);
|
var levelData = GameData.getTowerLevelDataMap().get(getCurrentLevelId());
|
||||||
|
|
||||||
this.currentLevel++;
|
var dungeonId = levelData.getDungeonId();
|
||||||
var id = levelData.getDungeonId();
|
|
||||||
|
|
||||||
notifyCurLevelRecordChange();
|
notifyCurLevelRecordChange();
|
||||||
// use team user choose
|
// use team user choose
|
||||||
player.getTeamManager().useTemporaryTeam(0);
|
player.getTeamManager().useTemporaryTeam(0);
|
||||||
player.getServer().getDungeonManager().handoffDungeon(player, id,
|
player.getServer().getDungeonManager().handoffDungeon(player, dungeonId,
|
||||||
towerDungeonSettleListener);
|
towerDungeonSettleListener);
|
||||||
|
|
||||||
// make sure user can exit dungeon correctly
|
// make sure user can exit dungeon correctly
|
||||||
player.getScene().setPrevScene(entryScene);
|
player.getScene().setPrevScene(entryScene);
|
||||||
player.getScene().setPrevScenePoint(enterPointId);
|
player.getScene().setPrevScenePoint(enterPointId);
|
||||||
|
|
||||||
player.getSession().send(new PacketTowerEnterLevelRsp(currentFloorId, currentLevel));
|
player.getSession().send(new PacketTowerEnterLevelRsp(currentFloorId, getCurrentLevel()));
|
||||||
// stop using skill
|
// stop using skill
|
||||||
player.getSession().send(new PacketCanUseSkillNotify(false));
|
player.getSession().send(new PacketCanUseSkillNotify(false));
|
||||||
|
// notify the cond of stars
|
||||||
|
player.getSession().send(new PacketTowerLevelStarCondNotify(currentFloorId, getCurrentLevel()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyCurLevelRecordChange(){
|
public void notifyCurLevelRecordChange(){
|
||||||
player.getSession().send(new PacketTowerCurLevelRecordChangeNotify(currentFloorId, currentLevel));
|
player.getSession().send(new PacketTowerCurLevelRecordChangeNotify(currentFloorId, getCurrentLevel()));
|
||||||
}
|
}
|
||||||
public void notifyCurLevelRecordChangeWhenDone(){
|
public void notifyCurLevelRecordChangeWhenDone(int stars){
|
||||||
player.getSession().send(new PacketTowerCurLevelRecordChangeNotify(currentFloorId, currentLevel + 1));
|
if(!recordMap.containsKey(currentFloorId)){
|
||||||
|
recordMap.put(currentFloorId,
|
||||||
|
new TowerLevelRecord(currentFloorId).setLevelStars(getCurrentLevelId(),stars));
|
||||||
|
}else{
|
||||||
|
recordMap.put(currentFloorId,
|
||||||
|
recordMap.get(currentFloorId).setLevelStars(getCurrentLevelId(),stars));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentLevel++;
|
||||||
|
|
||||||
|
if(!hasNextLevel()){
|
||||||
|
// set up the next floor
|
||||||
|
recordMap.put(getNextFloorId(), new TowerLevelRecord(getNextFloorId()));
|
||||||
|
player.getSession().send(new PacketTowerCurLevelRecordChangeNotify(getNextFloorId(), 1));
|
||||||
|
}else{
|
||||||
|
player.getSession().send(new PacketTowerCurLevelRecordChangeNotify(currentFloorId, getCurrentLevel()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public boolean hasNextLevel(){
|
public boolean hasNextLevel(){
|
||||||
return this.currentLevel < 3;
|
return this.currentLevel < 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNextFloorId() {
|
public int getNextFloorId() {
|
||||||
if(hasNextLevel()){
|
return player.getServer().getTowerScheduleManager().getNextFloorId(this.currentFloorId);
|
||||||
return 0;
|
}
|
||||||
}
|
public boolean hasNextFloor(){
|
||||||
this.currentFloorId++;
|
return player.getServer().getTowerScheduleManager().getNextFloorId(this.currentFloorId) > 0;
|
||||||
return this.currentFloorId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearEntry() {
|
public void clearEntry() {
|
||||||
this.entryScene = 0;
|
this.entryScene = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canEnterScheduleFloor(){
|
||||||
|
if(!recordMap.containsKey(player.getServer().getTowerScheduleManager().getLastEntranceFloor())){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return recordMap.get(player.getServer().getTowerScheduleManager().getLastEntranceFloor())
|
||||||
|
.getStarCount() >= 6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
package emu.grasscutter.game.tower;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class TowerScheduleConfig {
|
||||||
|
private int scheduleId;
|
||||||
|
|
||||||
|
private Date scheduleStartTime;
|
||||||
|
private Date nextScheduleChangeTime;
|
||||||
|
|
||||||
|
|
||||||
|
public int getScheduleId() {
|
||||||
|
return scheduleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScheduleId(int scheduleId) {
|
||||||
|
this.scheduleId = scheduleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getScheduleStartTime() {
|
||||||
|
return scheduleStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScheduleStartTime(Date scheduleStartTime) {
|
||||||
|
this.scheduleStartTime = scheduleStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getNextScheduleChangeTime() {
|
||||||
|
return nextScheduleChangeTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNextScheduleChangeTime(Date nextScheduleChangeTime) {
|
||||||
|
this.nextScheduleChangeTime = nextScheduleChangeTime;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package emu.grasscutter.game.tower;
|
||||||
|
|
||||||
|
import emu.grasscutter.Grasscutter;
|
||||||
|
import emu.grasscutter.data.GameData;
|
||||||
|
import emu.grasscutter.data.def.TowerScheduleData;
|
||||||
|
import emu.grasscutter.server.game.GameServer;
|
||||||
|
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TowerScheduleManager {
|
||||||
|
private final GameServer gameServer;
|
||||||
|
|
||||||
|
public GameServer getGameServer() {
|
||||||
|
return gameServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TowerScheduleManager(GameServer gameServer) {
|
||||||
|
this.gameServer = gameServer;
|
||||||
|
this.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
private TowerScheduleConfig towerScheduleConfig;
|
||||||
|
|
||||||
|
public synchronized void load(){
|
||||||
|
try (FileReader fileReader = new FileReader(Grasscutter.getConfig().DATA_FOLDER + "TowerSchedule.json")) {
|
||||||
|
towerScheduleConfig = Grasscutter.getGsonFactory().fromJson(fileReader, TowerScheduleConfig.class);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Grasscutter.getLogger().error("Unable to load tower schedule config.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TowerScheduleConfig getTowerScheduleConfig() {
|
||||||
|
return towerScheduleConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TowerScheduleData getCurrentTowerScheduleData(){
|
||||||
|
var data = GameData.getTowerScheduleDataMap().get(towerScheduleConfig.getScheduleId());
|
||||||
|
if(data == null){
|
||||||
|
Grasscutter.getLogger().error("Could not get current tower schedule data by config:{}", towerScheduleConfig);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Integer> getScheduleFloors() {
|
||||||
|
return getCurrentTowerScheduleData().getSchedules().get(0).getFloorList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNextFloorId(int floorId){
|
||||||
|
var entranceFloors = getCurrentTowerScheduleData().getEntranceFloorId();
|
||||||
|
var nextId = 0;
|
||||||
|
// find in entrance floors first
|
||||||
|
for(int i=0;i<entranceFloors.size()-1;i++){
|
||||||
|
if(floorId == entranceFloors.get(i)){
|
||||||
|
nextId = entranceFloors.get(i+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(nextId != 0){
|
||||||
|
return nextId;
|
||||||
|
}
|
||||||
|
var scheduleFloors = getScheduleFloors();
|
||||||
|
// find in schedule floors
|
||||||
|
for(int i=0;i<scheduleFloors.size()-1;i++){
|
||||||
|
if(floorId == scheduleFloors.get(i)){
|
||||||
|
nextId = scheduleFloors.get(i+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nextId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getLastEntranceFloor() {
|
||||||
|
return getCurrentTowerScheduleData().getEntranceFloorId().get(getCurrentTowerScheduleData().getEntranceFloorId().size()-1);
|
||||||
|
}
|
||||||
|
}
|
@ -385,27 +385,7 @@ public class Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (target.getFightProperties() == null) {
|
target.damage(result.getDamage(), result.getAttackerId());
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lose hp
|
|
||||||
target.addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, -result.getDamage());
|
|
||||||
|
|
||||||
// Check if dead
|
|
||||||
boolean isDead = false;
|
|
||||||
if (target.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) <= 0f) {
|
|
||||||
target.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f);
|
|
||||||
isDead = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Packets
|
|
||||||
this.broadcastPacket(new PacketEntityFightPropUpdateNotify(target, FightProperty.FIGHT_PROP_CUR_HP));
|
|
||||||
|
|
||||||
// Check if dead
|
|
||||||
if (isDead) {
|
|
||||||
this.killEntity(target, result.getAttackerId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void killEntity(GameEntity target, int attackerId) {
|
public void killEntity(GameEntity target, int attackerId) {
|
||||||
|
@ -90,6 +90,10 @@ public class SceneScriptManager {
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SceneGroup getCurrentGroup() {
|
||||||
|
return currentGroup;
|
||||||
|
}
|
||||||
|
|
||||||
public List<SceneBlock> getBlocks() {
|
public List<SceneBlock> getBlocks() {
|
||||||
return blocks;
|
return blocks;
|
||||||
}
|
}
|
||||||
@ -237,16 +241,16 @@ public class SceneScriptManager {
|
|||||||
|
|
||||||
for (SceneSuite suite : group.suites) {
|
for (SceneSuite suite : group.suites) {
|
||||||
suite.sceneMonsters = new ArrayList<>(suite.monsters.size());
|
suite.sceneMonsters = new ArrayList<>(suite.monsters.size());
|
||||||
for (int id : suite.monsters) {
|
suite.monsters.forEach(id -> {
|
||||||
try {
|
Object objEntry = map.get(id.intValue());
|
||||||
SceneMonster monster = (SceneMonster) map.get(id);
|
if (objEntry instanceof Map.Entry<?,?> monsterEntry) {
|
||||||
if (monster != null) {
|
Object monster = monsterEntry.getValue();
|
||||||
suite.sceneMonsters.add(monster);
|
if(monster instanceof SceneMonster sceneMonster){
|
||||||
|
suite.sceneMonsters.add(sceneMonster);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
suite.sceneGadgets = new ArrayList<>(suite.gadgets.size());
|
suite.sceneGadgets = new ArrayList<>(suite.gadgets.size());
|
||||||
for (int id : suite.gadgets) {
|
for (int id : suite.gadgets) {
|
||||||
try {
|
try {
|
||||||
@ -320,13 +324,15 @@ public class SceneScriptManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void spawnMonstersInGroup(SceneGroup group, int suiteIndex) {
|
public void spawnMonstersInGroup(SceneGroup group, int suiteIndex) {
|
||||||
this.currentGroup = group;
|
|
||||||
this.monsterSceneLimit = 0;
|
|
||||||
var suite = group.getSuiteByIndex(suiteIndex);
|
var suite = group.getSuiteByIndex(suiteIndex);
|
||||||
if(suite == null){
|
if(suite == null){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
suite.sceneMonsters.forEach(mob -> spawnMonstersInGroup(group, mob));
|
if(suite.sceneMonsters.size() > 0){
|
||||||
|
this.currentGroup = group;
|
||||||
|
this.monsterSceneLimit = 0;
|
||||||
|
suite.sceneMonsters.forEach(mob -> spawnMonstersInGroup(group, mob));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void spawnMonstersInGroup(SceneGroup group) {
|
public void spawnMonstersInGroup(SceneGroup group) {
|
||||||
@ -401,6 +407,7 @@ public class SceneScriptManager {
|
|||||||
spawnMonstersInGroup(this.currentGroup, this.currentGroup.monsters.get(this.monsterOrders.poll()));
|
spawnMonstersInGroup(this.currentGroup, this.currentGroup.monsters.get(this.monsterOrders.poll()));
|
||||||
}else if(this.monsterAlive.get() == 0){
|
}else if(this.monsterAlive.get() == 0){
|
||||||
// spawn the last turn of monsters
|
// spawn the last turn of monsters
|
||||||
|
//callEvent(EventType.EVENT_MONSTER_TIDE_DIE, new ScriptArgs());
|
||||||
while(!this.monsterOrders.isEmpty()){
|
while(!this.monsterOrders.isEmpty()){
|
||||||
spawnMonstersInGroup(this.currentGroup, this.currentGroup.monsters.get(this.monsterOrders.poll()));
|
spawnMonstersInGroup(this.currentGroup, this.currentGroup.monsters.get(this.monsterOrders.poll()));
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,6 @@ public class ScriptLib {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO just spawn all from group for now
|
|
||||||
this.getSceneScriptManager().spawnMonstersInGroup(group, suite);
|
this.getSceneScriptManager().spawnMonstersInGroup(group, suite);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -160,6 +159,12 @@ public class ScriptLib {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(getSceneScriptManager().getScene().getChallenge() != null &&
|
||||||
|
getSceneScriptManager().getScene().getChallenge().inProgress())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
DungeonChallenge challenge = new DungeonChallenge(getSceneScriptManager().getScene(), group);
|
DungeonChallenge challenge = new DungeonChallenge(getSceneScriptManager().getScene(), group);
|
||||||
challenge.setChallengeId(challengeId);
|
challenge.setChallengeId(challengeId);
|
||||||
challenge.setChallengeIndex(challengeIndex);
|
challenge.setChallengeIndex(challengeIndex);
|
||||||
@ -249,7 +254,7 @@ public class ScriptLib {
|
|||||||
var1);
|
var1);
|
||||||
|
|
||||||
return (int) getSceneScriptManager().getScene().getEntities().values().stream()
|
return (int) getSceneScriptManager().getScene().getEntities().values().stream()
|
||||||
.filter(e -> e instanceof EntityMonster)
|
.filter(e -> e instanceof EntityMonster && e.getGroupId() == getSceneScriptManager().getCurrentGroup().id)
|
||||||
.count();
|
.count();
|
||||||
}
|
}
|
||||||
public int SetMonsterBattleByGroup(int var1, int var2, int var3){
|
public int SetMonsterBattleByGroup(int var1, int var2, int var3){
|
||||||
@ -266,13 +271,11 @@ public class ScriptLib {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// 8-1
|
// 8-1
|
||||||
public int GetGroupVariableValueByGroup(int var1, String var2, int var3){
|
public int GetGroupVariableValueByGroup(String name, int groupId){
|
||||||
logger.debug("[LUA] Call GetGroupVariableValueByGroup with {},{},{}",
|
logger.debug("[LUA] Call GetGroupVariableValueByGroup with {},{}",
|
||||||
var1,var2,var3);
|
name,groupId);
|
||||||
|
|
||||||
//TODO
|
return getSceneScriptManager().getVariables().getOrDefault(name, 0);
|
||||||
|
|
||||||
return getSceneScriptManager().getVariables().getOrDefault(var2, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int SetIsAllowUseSkill(int canUse, int var2){
|
public int SetIsAllowUseSkill(int canUse, int var2){
|
||||||
@ -299,4 +302,11 @@ public class ScriptLib {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int SetGroupVariableValueByGroup(String key, int value, int groupId){
|
||||||
|
logger.debug("[LUA] Call SetGroupVariableValueByGroup with {},{},{}",
|
||||||
|
key,value,groupId);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import emu.grasscutter.game.managers.InventoryManager;
|
|||||||
import emu.grasscutter.game.managers.MultiplayerManager;
|
import emu.grasscutter.game.managers.MultiplayerManager;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.shop.ShopManager;
|
import emu.grasscutter.game.shop.ShopManager;
|
||||||
|
import emu.grasscutter.game.tower.TowerScheduleManager;
|
||||||
import emu.grasscutter.game.world.World;
|
import emu.grasscutter.game.world.World;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
|
import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
|
||||||
@ -54,6 +55,7 @@ public final class GameServer extends KcpServer {
|
|||||||
private final DropManager dropManager;
|
private final DropManager dropManager;
|
||||||
|
|
||||||
private final CombineManger combineManger;
|
private final CombineManger combineManger;
|
||||||
|
private final TowerScheduleManager towerScheduleManager;
|
||||||
|
|
||||||
public GameServer() {
|
public GameServer() {
|
||||||
this(new InetSocketAddress(
|
this(new InetSocketAddress(
|
||||||
@ -82,7 +84,7 @@ public final class GameServer extends KcpServer {
|
|||||||
this.dropManager = new DropManager(this);
|
this.dropManager = new DropManager(this);
|
||||||
this.expeditionManager = new ExpeditionManager(this);
|
this.expeditionManager = new ExpeditionManager(this);
|
||||||
this.combineManger = new CombineManger(this);
|
this.combineManger = new CombineManger(this);
|
||||||
|
this.towerScheduleManager = new TowerScheduleManager(this);
|
||||||
// Hook into shutdown event.
|
// Hook into shutdown event.
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(this::onServerShutdown));
|
Runtime.getRuntime().addShutdownHook(new Thread(this::onServerShutdown));
|
||||||
}
|
}
|
||||||
@ -139,6 +141,10 @@ public final class GameServer extends KcpServer {
|
|||||||
return this.combineManger;
|
return this.combineManger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TowerScheduleManager getTowerScheduleManager() {
|
||||||
|
return towerScheduleManager;
|
||||||
|
}
|
||||||
|
|
||||||
public TaskMap getTaskMap() {
|
public TaskMap getTaskMap() {
|
||||||
return this.taskMap;
|
return this.taskMap;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import emu.grasscutter.net.proto.AbilityInvocationsNotifyOuterClass.AbilityInvoc
|
|||||||
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
|
import emu.grasscutter.utils.Utils;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.AbilityInvocationsNotify)
|
@Opcodes(PacketOpcodes.AbilityInvocationsNotify)
|
||||||
public class HandlerAbilityInvocationsNotify extends PacketHandler {
|
public class HandlerAbilityInvocationsNotify extends PacketHandler {
|
||||||
@ -15,13 +16,9 @@ public class HandlerAbilityInvocationsNotify extends PacketHandler {
|
|||||||
AbilityInvocationsNotify notif = AbilityInvocationsNotify.parseFrom(payload);
|
AbilityInvocationsNotify notif = AbilityInvocationsNotify.parseFrom(payload);
|
||||||
|
|
||||||
for (AbilityInvokeEntry entry : notif.getInvokesList()) {
|
for (AbilityInvokeEntry entry : notif.getInvokesList()) {
|
||||||
//System.out.println(entry.getArgumentType() + ": " + Utils.bytesToHex(entry.getAbilityData().toByteArray()));
|
session.getPlayer().getAbilityManager().onAbilityInvoke(entry);
|
||||||
session.getPlayer().getAbilityInvokeHandler().addEntry(entry.getForwardType(), entry);
|
session.getPlayer().getAbilityInvokeHandler().addEntry(entry.getForwardType(), entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notif.getInvokesList().size() > 0) {
|
|
||||||
session.getPlayer().getAbilityInvokeHandler().update(session.getPlayer());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry
|
|||||||
import emu.grasscutter.net.proto.ClientAbilityInitFinishNotifyOuterClass.ClientAbilityInitFinishNotify;
|
import emu.grasscutter.net.proto.ClientAbilityInitFinishNotifyOuterClass.ClientAbilityInitFinishNotify;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
|
import emu.grasscutter.utils.Utils;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.ClientAbilityInitFinishNotify)
|
@Opcodes(PacketOpcodes.ClientAbilityInitFinishNotify)
|
||||||
public class HandlerClientAbilityInitFinishNotify extends PacketHandler {
|
public class HandlerClientAbilityInitFinishNotify extends PacketHandler {
|
||||||
@ -15,6 +16,7 @@ public class HandlerClientAbilityInitFinishNotify extends PacketHandler {
|
|||||||
ClientAbilityInitFinishNotify notif = ClientAbilityInitFinishNotify.parseFrom(payload);
|
ClientAbilityInitFinishNotify notif = ClientAbilityInitFinishNotify.parseFrom(payload);
|
||||||
|
|
||||||
for (AbilityInvokeEntry entry : notif.getInvokesList()) {
|
for (AbilityInvokeEntry entry : notif.getInvokesList()) {
|
||||||
|
session.getPlayer().getAbilityManager().onAbilityInvoke(entry);
|
||||||
session.getPlayer().getClientAbilityInitFinishHandler().addEntry(entry.getForwardType(), entry);
|
session.getPlayer().getClientAbilityInitFinishHandler().addEntry(entry.getForwardType(), entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,14 +74,6 @@ public class HandlerCombatInvocationsNotify extends PacketHandler {
|
|||||||
|
|
||||||
session.getPlayer().getCombatInvokeHandler().addEntry(entry.getForwardType(), entry);
|
session.getPlayer().getCombatInvokeHandler().addEntry(entry.getForwardType(), entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notif.getInvokeListList().size() > 0) {
|
|
||||||
session.getPlayer().getCombatInvokeHandler().update(session.getPlayer());
|
|
||||||
}
|
|
||||||
// Handle attack results last
|
|
||||||
while (!session.getPlayer().getAttackResults().isEmpty()) {
|
|
||||||
session.getPlayer().getScene().handleAttack(session.getPlayer().getAttackResults().poll());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleFallOnGround(GameSession session, GameEntity entity, MotionState motionState) {
|
private void handleFallOnGround(GameSession session, GameEntity entity, MotionState motionState) {
|
||||||
|
@ -14,11 +14,6 @@ public class HandlerEvtCreateGadgetNotify extends PacketHandler {
|
|||||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||||
EvtCreateGadgetNotify notify = EvtCreateGadgetNotify.parseFrom(payload);
|
EvtCreateGadgetNotify notify = EvtCreateGadgetNotify.parseFrom(payload);
|
||||||
|
|
||||||
// Dont handle in singleplayer
|
|
||||||
if (!session.getPlayer().getWorld().isMultiplayer()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sanity check - dont add duplicate entities
|
// Sanity check - dont add duplicate entities
|
||||||
if (session.getPlayer().getScene().getEntityById(notify.getEntityId()) != null) {
|
if (session.getPlayer().getScene().getEntityById(notify.getEntityId()) != null) {
|
||||||
return;
|
return;
|
||||||
|
@ -13,11 +13,6 @@ public class HandlerEvtDestroyGadgetNotify extends PacketHandler {
|
|||||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||||
EvtDestroyGadgetNotify notify = EvtDestroyGadgetNotify.parseFrom(payload);
|
EvtDestroyGadgetNotify notify = EvtDestroyGadgetNotify.parseFrom(payload);
|
||||||
|
|
||||||
// Dont handle in singleplayer
|
|
||||||
if (!session.getPlayer().getWorld().isMultiplayer()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
session.getPlayer().getScene().onPlayerDestroyGadget(notify.getEntityId());
|
session.getPlayer().getScene().onPlayerDestroyGadget(notify.getEntityId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ public class HandlerSetEntityClientDataNotify extends PacketHandler {
|
|||||||
BasePacket packet = new BasePacket(PacketOpcodes.SetEntityClientDataNotify, true);
|
BasePacket packet = new BasePacket(PacketOpcodes.SetEntityClientDataNotify, true);
|
||||||
packet.setData(notif);
|
packet.setData(notif);
|
||||||
|
|
||||||
session.getPlayer().getScene().broadcastPacketToOthers(session.getPlayer(), packet);
|
session.getPlayer().getScene().broadcastPacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ public class HandlerSetPlayerBornDataReq extends PacketHandler {
|
|||||||
// Create avatar
|
// Create avatar
|
||||||
if (player.getAvatars().getAvatarCount() == 0) {
|
if (player.getAvatars().getAvatarCount() == 0) {
|
||||||
Avatar mainCharacter = new Avatar(avatarId);
|
Avatar mainCharacter = new Avatar(avatarId);
|
||||||
mainCharacter.setSkillDepot(GameData.getAvatarSkillDepotDataMap().get(startingSkillDepot));
|
mainCharacter.setSkillDepotData(GameData.getAvatarSkillDepotDataMap().get(startingSkillDepot));
|
||||||
player.addAvatar(mainCharacter);
|
player.addAvatar(mainCharacter);
|
||||||
player.setMainCharacterId(avatarId);
|
player.setMainCharacterId(avatarId);
|
||||||
player.setHeadImage(avatarId);
|
player.setHeadImage(avatarId);
|
||||||
|
@ -11,7 +11,10 @@ public class HandlerTowerAllDataReq extends PacketHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||||
session.send(new PacketTowerAllDataRsp());
|
session.send(new PacketTowerAllDataRsp(
|
||||||
|
session.getServer().getTowerScheduleManager(),
|
||||||
|
session.getPlayer().getTowerManager()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,5 +15,14 @@ public class HandlerUnionCmdNotify extends PacketHandler {
|
|||||||
for (UnionCmd cmd : req.getCmdListList()) {
|
for (UnionCmd cmd : req.getCmdListList()) {
|
||||||
session.getServer().getPacketHandler().handle(session, cmd.getMessageId(), EMPTY_BYTE_ARRAY, cmd.getBody().toByteArray());
|
session.getServer().getPacketHandler().handle(session, cmd.getMessageId(), EMPTY_BYTE_ARRAY, cmd.getBody().toByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update
|
||||||
|
session.getPlayer().getCombatInvokeHandler().update(session.getPlayer());
|
||||||
|
session.getPlayer().getAbilityInvokeHandler().update(session.getPlayer());
|
||||||
|
|
||||||
|
// Handle attack results last
|
||||||
|
while (!session.getPlayer().getAttackResults().isEmpty()) {
|
||||||
|
session.getPlayer().getScene().handleAttack(session.getPlayer().getAttackResults().poll());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ public class PacketDungeonSettleNotify extends BasePacket {
|
|||||||
.setCount(1000)
|
.setCount(1000)
|
||||||
.build())
|
.build())
|
||||||
;
|
;
|
||||||
if(nextFloorId > 0){
|
if(nextFloorId > 0 && canJump){
|
||||||
towerLevelEndNotify.setNextFloorId(nextFloorId);
|
towerLevelEndNotify.setNextFloorId(nextFloorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,21 +11,27 @@ import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class PacketEntityFightPropChangeReasonNotify extends BasePacket {
|
public class PacketEntityFightPropChangeReasonNotify extends BasePacket {
|
||||||
|
|
||||||
public PacketEntityFightPropChangeReasonNotify(GameEntity entity, FightProperty prop, Float value, List<Integer> param, PropChangeReason reason, ChangeHpReason changeHpReason) {
|
public PacketEntityFightPropChangeReasonNotify(GameEntity entity, FightProperty prop, Float value, List<Integer> param, PropChangeReason reason, ChangeHpReason changeHpReason) {
|
||||||
super(PacketOpcodes.EntityFightPropChangeReasonNotify);
|
super(PacketOpcodes.EntityFightPropChangeReasonNotify);
|
||||||
|
|
||||||
EntityFightPropChangeReasonNotify.Builder proto = EntityFightPropChangeReasonNotify.newBuilder()
|
EntityFightPropChangeReasonNotify.Builder proto = EntityFightPropChangeReasonNotify.newBuilder()
|
||||||
.setEntityId(entity.getId())
|
.setEntityId(entity.getId())
|
||||||
.setPropType(prop.getId())
|
.setPropType(prop.getId())
|
||||||
.setPropDelta(value)
|
.setPropDelta(value)
|
||||||
.setReason(reason)
|
.setReason(reason)
|
||||||
.setChangeHpReason(changeHpReason);
|
.setChangeHpReason(changeHpReason);
|
||||||
for(int p: param){
|
|
||||||
|
for(int p : param){
|
||||||
proto.addParamList(p);
|
proto.addParamList(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PacketEntityFightPropChangeReasonNotify(GameEntity entity, FightProperty prop, Float value, PropChangeReason reason, ChangeHpReason changeHpReason) {
|
public PacketEntityFightPropChangeReasonNotify(GameEntity entity, FightProperty prop, Float value, PropChangeReason reason, ChangeHpReason changeHpReason) {
|
||||||
super(PacketOpcodes.EntityFightPropChangeReasonNotify);
|
super(PacketOpcodes.EntityFightPropChangeReasonNotify);
|
||||||
|
|
||||||
EntityFightPropChangeReasonNotify proto = EntityFightPropChangeReasonNotify.newBuilder()
|
EntityFightPropChangeReasonNotify proto = EntityFightPropChangeReasonNotify.newBuilder()
|
||||||
.setEntityId(entity.getId())
|
.setEntityId(entity.getId())
|
||||||
.setPropType(prop.getId())
|
.setPropType(prop.getId())
|
||||||
@ -33,6 +39,20 @@ public class PacketEntityFightPropChangeReasonNotify extends BasePacket {
|
|||||||
.setReason(reason)
|
.setReason(reason)
|
||||||
.setChangeHpReason(changeHpReason)
|
.setChangeHpReason(changeHpReason)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
this.setData(proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketEntityFightPropChangeReasonNotify(GameEntity entity, FightProperty prop, Float value, PropChangeReason reason) {
|
||||||
|
super(PacketOpcodes.EntityFightPropChangeReasonNotify);
|
||||||
|
|
||||||
|
EntityFightPropChangeReasonNotify proto = EntityFightPropChangeReasonNotify.newBuilder()
|
||||||
|
.setEntityId(entity.getId())
|
||||||
|
.setPropType(prop.getId())
|
||||||
|
.setPropDelta(value)
|
||||||
|
.setReason(reason)
|
||||||
|
.build();
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,37 +1,64 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.game.tower.TowerManager;
|
||||||
import emu.grasscutter.data.def.TowerFloorData;
|
import emu.grasscutter.game.tower.TowerScheduleManager;
|
||||||
import emu.grasscutter.net.packet.BasePacket;
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.TowerAllDataRspOuterClass.TowerAllDataRsp;
|
import emu.grasscutter.net.proto.TowerAllDataRspOuterClass.TowerAllDataRsp;
|
||||||
import emu.grasscutter.net.proto.TowerCurLevelRecordOuterClass.TowerCurLevelRecord;
|
import emu.grasscutter.net.proto.TowerCurLevelRecordOuterClass.TowerCurLevelRecord;
|
||||||
import emu.grasscutter.net.proto.TowerFloorRecordOuterClass.TowerFloorRecord;
|
import emu.grasscutter.net.proto.TowerFloorRecordOuterClass.TowerFloorRecord;
|
||||||
|
import emu.grasscutter.net.proto.TowerLevelRecordOuterClass;
|
||||||
|
import emu.grasscutter.utils.DateHelper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
public class PacketTowerAllDataRsp extends BasePacket {
|
public class PacketTowerAllDataRsp extends BasePacket {
|
||||||
|
|
||||||
public PacketTowerAllDataRsp() {
|
public PacketTowerAllDataRsp(TowerScheduleManager towerScheduleManager, TowerManager towerManager) {
|
||||||
super(PacketOpcodes.TowerAllDataRsp);
|
super(PacketOpcodes.TowerAllDataRsp);
|
||||||
|
|
||||||
var list = GameData.getTowerFloorDataMap().values().stream()
|
var recordList = towerManager.getRecordMap().values().stream()
|
||||||
.map(TowerFloorData::getFloorId)
|
.map(rec -> TowerFloorRecord.newBuilder()
|
||||||
.map(id -> TowerFloorRecord.newBuilder().setFloorId(id).build())
|
.setFloorId(rec.getFloorId())
|
||||||
.collect(Collectors.toList());
|
.setFloorStarRewardProgress(rec.getFloorStarRewardProgress())
|
||||||
|
.putAllPassedLevelMap(rec.getPassedLevelMap())
|
||||||
|
.addAllPassedLevelRecordList(buildFromPassedLevelMap(rec.getPassedLevelMap()))
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
var openTimeMap = towerScheduleManager.getScheduleFloors().stream()
|
||||||
|
.collect(Collectors.toMap(x -> x,
|
||||||
|
y -> DateHelper.getUnixTime(towerScheduleManager.getTowerScheduleConfig()
|
||||||
|
.getScheduleStartTime()))
|
||||||
|
);
|
||||||
|
|
||||||
TowerAllDataRsp proto = TowerAllDataRsp.newBuilder()
|
TowerAllDataRsp proto = TowerAllDataRsp.newBuilder()
|
||||||
.setTowerScheduleId(29)
|
.setTowerScheduleId(towerScheduleManager.getCurrentTowerScheduleData().getScheduleId())
|
||||||
.addAllTowerFloorRecordList(list)
|
.addAllTowerFloorRecordList(recordList)
|
||||||
.setCurLevelRecord(TowerCurLevelRecord.newBuilder().setIsEmpty(true))
|
.setCurLevelRecord(TowerCurLevelRecord.newBuilder().setIsEmpty(true))
|
||||||
.setNextScheduleChangeTime(Integer.MAX_VALUE)
|
.setScheduleStartTime(DateHelper.getUnixTime(towerScheduleManager.getTowerScheduleConfig()
|
||||||
.putFloorOpenTimeMap(1024, 1630486800)
|
.getScheduleStartTime()))
|
||||||
.putFloorOpenTimeMap(1025, 1630486800)
|
.setNextScheduleChangeTime(DateHelper.getUnixTime(towerScheduleManager.getTowerScheduleConfig()
|
||||||
.putFloorOpenTimeMap(1026, 1630486800)
|
.getNextScheduleChangeTime()))
|
||||||
.putFloorOpenTimeMap(1027, 1630486800)
|
.putAllFloorOpenTimeMap(openTimeMap)
|
||||||
.setScheduleStartTime(1630486800)
|
.setIsFinishedEntranceFloor(towerManager.canEnterScheduleFloor())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<TowerLevelRecordOuterClass.TowerLevelRecord> buildFromPassedLevelMap(Map<Integer, Integer> map){
|
||||||
|
return map.entrySet().stream()
|
||||||
|
.map(item -> TowerLevelRecordOuterClass.TowerLevelRecord.newBuilder()
|
||||||
|
.setLevelId(item.getKey())
|
||||||
|
.addAllSatisfiedCondList(IntStream.range(1, item.getValue() + 1).boxed().toList())
|
||||||
|
.build())
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,13 @@ import emu.grasscutter.net.proto.TowerLevelRecordOuterClass.TowerLevelRecord;
|
|||||||
|
|
||||||
public class PacketTowerFloorRecordChangeNotify extends BasePacket {
|
public class PacketTowerFloorRecordChangeNotify extends BasePacket {
|
||||||
|
|
||||||
public PacketTowerFloorRecordChangeNotify(int floorId) {
|
public PacketTowerFloorRecordChangeNotify(int floorId, int stars, boolean canEnterScheduleFloor) {
|
||||||
super(PacketOpcodes.TowerFloorRecordChangeNotify);
|
super(PacketOpcodes.TowerFloorRecordChangeNotify);
|
||||||
|
|
||||||
TowerFloorRecordChangeNotify proto = TowerFloorRecordChangeNotify.newBuilder()
|
TowerFloorRecordChangeNotify proto = TowerFloorRecordChangeNotify.newBuilder()
|
||||||
.addTowerFloorRecordList(TowerFloorRecord.newBuilder()
|
.addTowerFloorRecordList(TowerFloorRecord.newBuilder()
|
||||||
.setFloorId(floorId)
|
.setFloorId(floorId)
|
||||||
.setFloorStarRewardProgress(3)
|
.setFloorStarRewardProgress(stars)
|
||||||
.addPassedLevelRecordList(TowerLevelRecord.newBuilder()
|
.addPassedLevelRecordList(TowerLevelRecord.newBuilder()
|
||||||
.setLevelId(1)
|
.setLevelId(1)
|
||||||
.addSatisfiedCondList(1)
|
.addSatisfiedCondList(1)
|
||||||
@ -22,7 +22,7 @@ public class PacketTowerFloorRecordChangeNotify extends BasePacket {
|
|||||||
.addSatisfiedCondList(3)
|
.addSatisfiedCondList(3)
|
||||||
.build())
|
.build())
|
||||||
.build())
|
.build())
|
||||||
.setIsFinishedEntranceFloor(true)
|
.setIsFinishedEntranceFloor(canEnterScheduleFloor)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
|
import emu.grasscutter.net.proto.TowerLevelStarCondDataOuterClass.TowerLevelStarCondData;
|
||||||
|
import emu.grasscutter.net.proto.TowerLevelStarCondNotifyOuterClass.TowerLevelStarCondNotify;
|
||||||
|
|
||||||
|
public class PacketTowerLevelStarCondNotify extends BasePacket {
|
||||||
|
|
||||||
|
public PacketTowerLevelStarCondNotify(int floorId, int levelIndex) {
|
||||||
|
super(PacketOpcodes.TowerLevelStarCondNotify);
|
||||||
|
|
||||||
|
TowerLevelStarCondNotify proto = TowerLevelStarCondNotify.newBuilder()
|
||||||
|
.setFloorId(floorId)
|
||||||
|
.setLevelIndex(levelIndex)
|
||||||
|
.addCondDataList(TowerLevelStarCondData.newBuilder()
|
||||||
|
.setCondValue(1)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.addCondDataList(TowerLevelStarCondData.newBuilder()
|
||||||
|
.setCondValue(2)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.addCondDataList(TowerLevelStarCondData.newBuilder()
|
||||||
|
.setCondValue(3)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
this.setData(proto);
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,5 @@
|
|||||||
package emu.grasscutter.task;
|
package emu.grasscutter.task;
|
||||||
|
|
||||||
import org.quartz.JobDataMap;
|
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@ -67,6 +67,40 @@ public final class TaskMap {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean pauseTask(String taskName) {
|
||||||
|
try {
|
||||||
|
Scheduler scheduler = schedulerFactory.getScheduler();
|
||||||
|
scheduler.pauseJob(new JobKey(taskName));
|
||||||
|
} catch (SchedulerException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean resumeTask(String taskName) {
|
||||||
|
try {
|
||||||
|
Scheduler scheduler = schedulerFactory.getScheduler();
|
||||||
|
scheduler.resumeJob(new JobKey(taskName));
|
||||||
|
} catch (SchedulerException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean cancelTask(String taskName) {
|
||||||
|
Task task = this.annotations.get(taskName);
|
||||||
|
if (task == null) return false;
|
||||||
|
try {
|
||||||
|
this.unregisterTask(this.tasks.get(taskName));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public TaskMap registerTask(String taskName, TaskHandler task) {
|
public TaskMap registerTask(String taskName, TaskHandler task) {
|
||||||
Task annotation = task.getClass().getAnnotation(Task.class);
|
Task annotation = task.getClass().getAnnotation(Task.class);
|
||||||
this.annotations.put(taskName, annotation);
|
this.annotations.put(taskName, annotation);
|
||||||
@ -116,7 +150,7 @@ public final class TaskMap {
|
|||||||
classes.forEach(annotated -> {
|
classes.forEach(annotated -> {
|
||||||
try {
|
try {
|
||||||
Task taskData = annotated.getAnnotation(Task.class);
|
Task taskData = annotated.getAnnotation(Task.class);
|
||||||
Object object = annotated.newInstance();
|
Object object = annotated.getDeclaredConstructor().newInstance();
|
||||||
if (object instanceof TaskHandler) {
|
if (object instanceof TaskHandler) {
|
||||||
this.registerTask(taskData.taskName(), (TaskHandler) object);
|
this.registerTask(taskData.taskName(), (TaskHandler) object);
|
||||||
if (taskData.executeImmediatelyAfterReset()) {
|
if (taskData.executeImmediatelyAfterReset()) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package emu.grasscutter.utils;
|
package emu.grasscutter.utils;
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
public final class DateHelper {
|
public final class DateHelper {
|
||||||
public static Date onlyYearMonthDay(Date now) {
|
public static Date onlyYearMonthDay(Date now) {
|
||||||
@ -13,4 +13,8 @@ public final class DateHelper {
|
|||||||
calendar.set(Calendar.MILLISECOND, 0);
|
calendar.set(Calendar.MILLISECOND, 0);
|
||||||
return calendar.getTime();
|
return calendar.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getUnixTime(Date localDateTime){
|
||||||
|
return (int)(localDateTime.getTime() / 1000L);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -312,6 +312,9 @@
|
|||||||
"success": "Teleported %s to %s, %s, %s in scene %s",
|
"success": "Teleported %s to %s, %s, %s in scene %s",
|
||||||
"description": "Change the player's position."
|
"description": "Change the player's position."
|
||||||
},
|
},
|
||||||
|
"tower": {
|
||||||
|
"unlock_done": "Abyss Corridor's Floors are all unlocked now."
|
||||||
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"usage": "Usage: weather <weatherId> [climateId]",
|
"usage": "Usage: weather <weatherId> [climateId]",
|
||||||
"success": "Changed weather to %s with climate %s",
|
"success": "Changed weather to %s with climate %s",
|
||||||
|
@ -95,17 +95,20 @@
|
|||||||
"create": "已建立账号,UID 为 %s 。",
|
"create": "已建立账号,UID 为 %s 。",
|
||||||
"delete": "账号已刪除。",
|
"delete": "账号已刪除。",
|
||||||
"no_account": "账号不存在。",
|
"no_account": "账号不存在。",
|
||||||
"command_usage": "用法:account <create|delete> <username> [uid]"
|
"command_usage": "用法:account <create|delete> <username> [uid]",
|
||||||
|
"description": "创建或删除账号。"
|
||||||
},
|
},
|
||||||
"broadcast": {
|
"broadcast": {
|
||||||
"command_usage": "用法:broadcast <消息>",
|
"command_usage": "用法:broadcast <消息>",
|
||||||
"message_sent": "公告已发送。"
|
"message_sent": "公告已发送。",
|
||||||
|
"description": "向所有玩家发送公告。"
|
||||||
},
|
},
|
||||||
"changescene": {
|
"changescene": {
|
||||||
"usage": "用法:changescene <scene id>",
|
"usage": "用法:changescene <scene id>",
|
||||||
"already_in_scene": "你已经在这个秘境中了。",
|
"already_in_scene": "你已经在这个秘境中了。",
|
||||||
"success": "已切换至秘境 %s.",
|
"success": "已切换至秘境 %s.",
|
||||||
"exists_error": "此秘境不存在。"
|
"exists_error": "此秘境不存在。",
|
||||||
|
"description": "切换指定秘境。"
|
||||||
},
|
},
|
||||||
"clear": {
|
"clear": {
|
||||||
"command_usage": "用法: clear <all|wp|art|mat>",
|
"command_usage": "用法: clear <all|wp|art|mat>",
|
||||||
@ -115,35 +118,41 @@
|
|||||||
"furniture": "已将 %s 的尘歌壶家具清空。",
|
"furniture": "已将 %s 的尘歌壶家具清空。",
|
||||||
"displays": "已清除 %s 的显示。",
|
"displays": "已清除 %s 的显示。",
|
||||||
"virtuals": "已将 %s 的所有货币和经验值清空。",
|
"virtuals": "已将 %s 的所有货币和经验值清空。",
|
||||||
"everything": "已将 %s 的所有物品清空。"
|
"everything": "已将 %s 的所有物品清空。",
|
||||||
|
"description": "从您的背包中删除所有未装备且已解锁的物品,包括稀有物品。"
|
||||||
},
|
},
|
||||||
"coop": {
|
"coop": {
|
||||||
"usage": "用法:coop <playerId> <target playerId>",
|
"usage": "用法:coop <playerId> <target playerId>",
|
||||||
"success": "已强制召唤 %s 到 %s的世界"
|
"success": "已强制召唤 %s 到 %s的世界",
|
||||||
|
"description": "强制召唤指定用户到他人的世界。"
|
||||||
},
|
},
|
||||||
"enter_dungeon": {
|
"enter_dungeon": {
|
||||||
"usage": "用法:enterdungeon <dungeon id>",
|
"usage": "用法:enterdungeon <dungeon id>",
|
||||||
"changed": "已进入秘境 %s",
|
"changed": "已进入秘境 %s",
|
||||||
"not_found_error": "此秘境不存在。",
|
"not_found_error": "此秘境不存在。",
|
||||||
"in_dungeon_error": "你已经在秘境中了。"
|
"in_dungeon_error": "你已经在秘境中了。",
|
||||||
|
"description": "进入指定秘境。"
|
||||||
},
|
},
|
||||||
"giveAll": {
|
"giveAll": {
|
||||||
"usage": "用法:giveall [player] [amount]",
|
"usage": "用法:giveall [player] [amount]",
|
||||||
"started": "正在给予全部物品...",
|
"started": "正在给予全部物品...",
|
||||||
"success": "已给予全部物品。",
|
"success": "已给予全部物品。",
|
||||||
"invalid_amount_or_playerId": "无效的数量/玩家ID。"
|
"invalid_amount_or_playerId": "无效的数量/玩家ID。",
|
||||||
|
"description": "给予所有物品。"
|
||||||
},
|
},
|
||||||
"giveArtifact": {
|
"giveArtifact": {
|
||||||
"usage": "用法:giveart|gart [player] <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]",
|
"usage": "用法:giveart|gart [player] <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]",
|
||||||
"id_error": "无效的圣遗物ID。",
|
"id_error": "无效的圣遗物ID。",
|
||||||
"success": "已将 %s 给予 %s。"
|
"success": "已将 %s 给予 %s。",
|
||||||
|
"description": "给予指定圣遗物。"
|
||||||
},
|
},
|
||||||
"giveChar": {
|
"giveChar": {
|
||||||
"usage": "用法:givechar <player> <itemId|itemName> [amount]",
|
"usage": "用法:givechar <player> <itemId|itemName> [amount]",
|
||||||
"given": "给予角色 %s 等级 %s 向UID %s.",
|
"given": "给予角色 %s 等级 %s 向UID %s.",
|
||||||
"invalid_avatar_id": "无效的角色ID。",
|
"invalid_avatar_id": "无效的角色ID。",
|
||||||
"invalid_avatar_level": "无效的角色等級。.",
|
"invalid_avatar_level": "无效的角色等級。.",
|
||||||
"invalid_avatar_or_player_id": "无效的角色ID/玩家ID。"
|
"invalid_avatar_or_player_id": "无效的角色ID/玩家ID。",
|
||||||
|
"description": "给予指定角色。"
|
||||||
},
|
},
|
||||||
"give": {
|
"give": {
|
||||||
"usage": "用法:give <player> <itemId|itemName> [amount] [level] [refinement]",
|
"usage": "用法:give <player> <itemId|itemName> [amount] [level] [refinement]",
|
||||||
@ -151,29 +160,36 @@
|
|||||||
"refinement_must_between_1_and_5": "精炼等阶必须在 1 到 5 之间。",
|
"refinement_must_between_1_and_5": "精炼等阶必须在 1 到 5 之间。",
|
||||||
"given": "已将 %s 个 %s 给予 %s。",
|
"given": "已将 %s 个 %s 给予 %s。",
|
||||||
"given_with_level_and_refinement": "已将 %s [等級%s, 精炼%s] %s个给予 %s",
|
"given_with_level_and_refinement": "已将 %s [等級%s, 精炼%s] %s个给予 %s",
|
||||||
"given_level": "已将 %s 等级 %s %s 个给予UID %s"
|
"given_level": "已将 %s 等级 %s %s 个给予UID %s",
|
||||||
|
"description": "给予指定物品。"
|
||||||
},
|
},
|
||||||
"godmode": {
|
"godmode": {
|
||||||
"success": "上帝模式已被设置为 %s 。 [用户:%s]"
|
"success": "上帝模式已被设置为 %s 。 [用户:%s]",
|
||||||
|
"description": "防止你受到伤害。"
|
||||||
},
|
},
|
||||||
"heal": {
|
"heal": {
|
||||||
"success": "所有角色已被治疗。"
|
"success": "所有角色已被治疗。",
|
||||||
|
"description": "治疗所选队伍的角色。"
|
||||||
},
|
},
|
||||||
"kick": {
|
"kick": {
|
||||||
"player_kick_player": "玩家 [%s:%s] 已将 [%s:%s] 踢出",
|
"player_kick_player": "玩家 [%s:%s] 已将 [%s:%s] 踢出",
|
||||||
"server_kick_player": "正在踢出玩家 [%s:%s]"
|
"server_kick_player": "正在踢出玩家 [%s:%s]",
|
||||||
|
"description": "从服务器内踢出指定玩家。"
|
||||||
},
|
},
|
||||||
"kill": {
|
"kill": {
|
||||||
"usage": "用法:killall [playerUid] [sceneId]",
|
"usage": "用法:killall [playerUid] [sceneId]",
|
||||||
"scene_not_found_in_player_world": "未在玩家世界中找到此场景",
|
"scene_not_found_in_player_world": "未在玩家世界中找到此场景",
|
||||||
"kill_monsters_in_scene": "已杀死 %s 个怪物。 [场景ID: %s]"
|
"kill_monsters_in_scene": "已杀死 %s 个怪物。 [场景ID: %s]",
|
||||||
|
"description": "杀死所有怪物"
|
||||||
},
|
},
|
||||||
"killCharacter": {
|
"killCharacter": {
|
||||||
"usage": "用法:/killcharacter [playerId]",
|
"usage": "用法:/killcharacter [playerId]",
|
||||||
"success": "已杀死 %s 目前使用的角色。"
|
"success": "已杀死 %s 目前使用的角色。",
|
||||||
|
"description": "杀死目前使用的角色"
|
||||||
},
|
},
|
||||||
"list": {
|
"list": {
|
||||||
"success": "目前在线人数:%s"
|
"success": "目前在线人数:%s",
|
||||||
|
"description": "查看所有玩家"
|
||||||
},
|
},
|
||||||
"permission": {
|
"permission": {
|
||||||
"usage": "用法:permission <add|remove> <username> <permission>",
|
"usage": "用法:permission <add|remove> <username> <permission>",
|
||||||
@ -181,21 +197,26 @@
|
|||||||
"has_error": "此玩家已拥有此权限!",
|
"has_error": "此玩家已拥有此权限!",
|
||||||
"remove": "权限已移除。",
|
"remove": "权限已移除。",
|
||||||
"not_have_error": "此玩家未拥有权限!",
|
"not_have_error": "此玩家未拥有权限!",
|
||||||
"account_error": "账号不存在!"
|
"account_error": "账号不存在!",
|
||||||
|
"description": "给予或移除指定玩家的权限。"
|
||||||
},
|
},
|
||||||
"position": {
|
"position": {
|
||||||
"success": "坐标:%.3f, %.3f, %.3f\n场景ID:%d"
|
"success": "坐标:%.3f, %.3f, %.3f\n场景ID:%d",
|
||||||
|
"description": "获取所在位置。"
|
||||||
},
|
},
|
||||||
"reload": {
|
"reload": {
|
||||||
"reload_start": "正在重载配置文件和数据。",
|
"reload_start": "正在重载配置文件和数据。",
|
||||||
"reload_done": "重载完毕。"
|
"reload_done": "重载完毕。",
|
||||||
|
"description": "重载配置文件和数据。"
|
||||||
},
|
},
|
||||||
"resetConst": {
|
"resetConst": {
|
||||||
"reset_all": "重置所有角色的命座。",
|
"reset_all": "重置所有角色的命座。",
|
||||||
"success": "已重置 %s 的命座,重新登录后将会生效。"
|
"success": "已重置 %s 的命座,重新登录后将会生效。",
|
||||||
|
"description": "重置当前角色的命之座,执行命令后需重新登录以生效。"
|
||||||
},
|
},
|
||||||
"resetShopLimit": {
|
"resetShopLimit": {
|
||||||
"usage": "用法:/resetshop <player id>"
|
"usage": "用法:/resetshop <player id>",
|
||||||
|
"description": "重置所选玩家的商店刷新时间。"
|
||||||
},
|
},
|
||||||
"sendMail": {
|
"sendMail": {
|
||||||
"usage": "用法:give [player] <itemId|itemName> [amount]",
|
"usage": "用法:give [player] <itemId|itemName> [amount]",
|
||||||
@ -217,17 +238,20 @@
|
|||||||
"message": "<正文>",
|
"message": "<正文>",
|
||||||
"sender": "<发件人>",
|
"sender": "<发件人>",
|
||||||
"arguments": "<itemId|itemName|finish> [数量] [等级]",
|
"arguments": "<itemId|itemName|finish> [数量] [等级]",
|
||||||
"error": "错误:无效的编写阶段 %s。需要 StackTrace 请查看服务器控制台。"
|
"error": "错误:无效的编写阶段 %s。需要 StackTrace 请查看服务器控制台。",
|
||||||
|
"description": "向指定用户发送邮件。 此命令的用法可根据附加的参数而变化。"
|
||||||
},
|
},
|
||||||
"sendMessage": {
|
"sendMessage": {
|
||||||
"usage": "用法:sendmessage <player> <message>",
|
"usage": "用法:sendmessage <player> <message>",
|
||||||
"success": "消息已发送。"
|
"success": "消息已发送。",
|
||||||
|
"description": "向指定玩家发送消息"
|
||||||
},
|
},
|
||||||
"setFetterLevel": {
|
"setFetterLevel": {
|
||||||
"usage": "用法:setfetterlevel <level>",
|
"usage": "用法:setfetterlevel <level>",
|
||||||
"range_error": "好感度等级必须在 0 到 10 之间。",
|
"range_error": "好感度等级必须在 0 到 10 之间。",
|
||||||
"fetter_set_level": "好感度已设置为 %s 级",
|
"fetter_set_level": "好感度已设置为 %s 级",
|
||||||
"level_error": "无效的好感度等级。"
|
"level_error": "无效的好感度等级。",
|
||||||
|
"description": "设置当前角色的好感度等级。"
|
||||||
},
|
},
|
||||||
"setStats": {
|
"setStats": {
|
||||||
"usage_console": "用法:setstats|stats @<UID> <stat> <value>",
|
"usage_console": "用法:setstats|stats @<UID> <stat> <value>",
|
||||||
@ -238,20 +262,24 @@
|
|||||||
"player_error": "玩家不存在或已离线。",
|
"player_error": "玩家不存在或已离线。",
|
||||||
"set_self": "%s 已经设置为 %s。",
|
"set_self": "%s 已经设置为 %s。",
|
||||||
"set_for_uid": "%s 的使用者 %s 更改为 %s。",
|
"set_for_uid": "%s 的使用者 %s 更改为 %s。",
|
||||||
"set_max_hp": "最大生命值更改为 %s。"
|
"set_max_hp": "最大生命值更改为 %s。",
|
||||||
|
"description": "设置当前角色的属性。"
|
||||||
},
|
},
|
||||||
"setWorldLevel": {
|
"setWorldLevel": {
|
||||||
"usage": "用法:setworldlevel <level>",
|
"usage": "用法:setworldlevel <level>",
|
||||||
"value_error": "世界等级必须设置在0-8之间。",
|
"value_error": "世界等级必须设置在0-8之间。",
|
||||||
"success": "已将世界等级设为%s。",
|
"success": "已将世界等级设为%s。",
|
||||||
"invalid_world_level": "无效的世界等级。"
|
"invalid_world_level": "无效的世界等级。",
|
||||||
|
"description": "设置世界等级,执行命令后需重新登录以生效。"
|
||||||
},
|
},
|
||||||
"spawn": {
|
"spawn": {
|
||||||
"usage": "用法:spawn <entityId> [amount] [level(仅限怪物]",
|
"usage": "用法:spawn <entityId> [amount] [level(仅限怪物]",
|
||||||
"success": "已生成 %s 个 %s。"
|
"success": "已生成 %s 个 %s。",
|
||||||
|
"description": "在你附近生成一个生物。"
|
||||||
},
|
},
|
||||||
"stop": {
|
"stop": {
|
||||||
"success": "正在关闭服务器..."
|
"success": "正在关闭服务器...",
|
||||||
|
"description": "停止服务器"
|
||||||
},
|
},
|
||||||
"talent": {
|
"talent": {
|
||||||
"usage_1": "设置天赋等级:/talent set <talentID> <value>",
|
"usage_1": "设置天赋等级:/talent set <talentID> <value>",
|
||||||
@ -267,32 +295,41 @@
|
|||||||
"invalid_level": "无效的天赋等级。",
|
"invalid_level": "无效的天赋等级。",
|
||||||
"normal_attack_id": "普通攻击的 ID 为 %s。",
|
"normal_attack_id": "普通攻击的 ID 为 %s。",
|
||||||
"e_skill_id": "元素战技ID %s。",
|
"e_skill_id": "元素战技ID %s。",
|
||||||
"q_skill_id": "元素爆发ID %s。"
|
"q_skill_id": "元素爆发ID %s。",
|
||||||
|
"description": "设置当前角色的天赋等级。"
|
||||||
},
|
},
|
||||||
"teleportAll": {
|
"teleportAll": {
|
||||||
"success": "已将全部玩家传送到你的位置",
|
"success": "已将全部玩家传送到你的位置",
|
||||||
"error": "命令仅限处于多人游戏状态下使用。"
|
"error": "命令仅限处于多人游戏状态下使用。",
|
||||||
|
"description": "将你世界中的所有玩家传送到你所在的位置。"
|
||||||
},
|
},
|
||||||
"teleport": {
|
"teleport": {
|
||||||
"usage_server": "用法:/tp @<player id> <x> <y> <z> [scene id]",
|
"usage_server": "用法:/tp @<player id> <x> <y> <z> [scene id]",
|
||||||
"usage": "用法:/tp [@<player id>] <x> <y> <z> [scene id]",
|
"usage": "用法:/tp [@<player id>] <x> <y> <z> [scene id]",
|
||||||
"specify_player_id": "你必须指定一个玩家ID。",
|
"specify_player_id": "你必须指定一个玩家ID。",
|
||||||
"invalid_position": "无效的位置。",
|
"invalid_position": "无效的位置。",
|
||||||
"success": "传送 %s 到坐标 %s,%s,%s,场景为 %s"
|
"success": "传送 %s 到坐标 %s,%s,%s,场景为 %s",
|
||||||
|
"description": "改变指定玩家的位置。"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"usage": "用法:weather <weatherId> [climateId]",
|
"usage": "用法:weather <weatherId> [climateId]",
|
||||||
"success": "已将当前天气设定为 %s,气候为 %s。",
|
"success": "已将当前天气设定为 %s,气候为 %s。",
|
||||||
"invalid_id": "无效的天气ID。"
|
"invalid_id": "无效的天气ID。",
|
||||||
|
"description": "改变天气"
|
||||||
},
|
},
|
||||||
"drop": {
|
"drop": {
|
||||||
"command_usage": "用法:drop <itemId|itemName> [amount]",
|
"command_usage": "用法:drop <itemId|itemName> [amount]",
|
||||||
"success": "已将 %s x %s 丟在附近。"
|
"success": "已将 %s x %s 丟在附近。",
|
||||||
|
"description": "在你附近丢一个物品。"
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"usage": "用法:",
|
"usage": "用法:",
|
||||||
"aliases": "別名:",
|
"aliases": "別名:",
|
||||||
"available_commands": "可用指令:"
|
"available_commands": "可用指令:",
|
||||||
|
"description": "发送帮助信息或显示指定命令的信息。"
|
||||||
|
},
|
||||||
|
"restart": {
|
||||||
|
"description": "重新启动服务器。"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user