mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-02-11 07:13:27 +08:00
Format code
This commit is contained in:
parent
b03870ab48
commit
a3970f8e43
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,139 +1,139 @@
|
|||||||
package emu.grasscutter.command.commands;
|
package emu.grasscutter.command.commands;
|
||||||
|
|
||||||
import static emu.grasscutter.command.CommandHelpers.*;
|
import static emu.grasscutter.command.CommandHelpers.*;
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
|
||||||
import emu.grasscutter.command.Command;
|
import emu.grasscutter.command.Command;
|
||||||
import emu.grasscutter.command.CommandHandler;
|
import emu.grasscutter.command.CommandHandler;
|
||||||
import emu.grasscutter.game.entity.*;
|
import emu.grasscutter.game.entity.*;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.ElementType;
|
import emu.grasscutter.game.props.ElementType;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.server.event.entity.EntityDamageEvent;
|
import emu.grasscutter.server.event.entity.EntityDamageEvent;
|
||||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
label = "entity",
|
label = "entity",
|
||||||
usage = {
|
usage = {
|
||||||
"<configId gadget> [state<state>] [maxhp<maxhp>] [hp<hp>(0 for infinite)] [atk<atk>] [def<def>]",
|
"<configId gadget> [state<state>] [maxhp<maxhp>] [hp<hp>(0 for infinite)] [atk<atk>] [def<def>]",
|
||||||
"<configId monster> [ai<aiId>] [maxhp<maxhp>] [hp<hp>(0 for infinite)] [atk<atk>] [def<def>]"
|
"<configId monster> [ai<aiId>] [maxhp<maxhp>] [hp<hp>(0 for infinite)] [atk<atk>] [def<def>]"
|
||||||
},
|
},
|
||||||
permission = "server.entity")
|
permission = "server.entity")
|
||||||
public final class EntityCommand implements CommandHandler {
|
public final class EntityCommand implements CommandHandler {
|
||||||
private static final Map<Pattern, BiConsumer<EntityParameters, Integer>> intCommandHandlers =
|
private static final Map<Pattern, BiConsumer<EntityParameters, Integer>> intCommandHandlers =
|
||||||
Map.ofEntries(
|
Map.ofEntries(
|
||||||
Map.entry(stateRegex, EntityParameters::setState),
|
Map.entry(stateRegex, EntityParameters::setState),
|
||||||
Map.entry(maxHPRegex, EntityParameters::setMaxHP),
|
Map.entry(maxHPRegex, EntityParameters::setMaxHP),
|
||||||
Map.entry(hpRegex, EntityParameters::setHp),
|
Map.entry(hpRegex, EntityParameters::setHp),
|
||||||
Map.entry(defRegex, EntityParameters::setDef),
|
Map.entry(defRegex, EntityParameters::setDef),
|
||||||
Map.entry(atkRegex, EntityParameters::setAtk),
|
Map.entry(atkRegex, EntityParameters::setAtk),
|
||||||
Map.entry(aiRegex, EntityParameters::setAi));
|
Map.entry(aiRegex, EntityParameters::setAi));
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||||
EntityParameters param = new EntityParameters();
|
EntityParameters param = new EntityParameters();
|
||||||
|
|
||||||
parseIntParameters(args, param, intCommandHandlers);
|
parseIntParameters(args, param, intCommandHandlers);
|
||||||
|
|
||||||
// At this point, first remaining argument MUST be the id and the rest the pos
|
// At this point, first remaining argument MUST be the id and the rest the pos
|
||||||
if (args.size() != 1) {
|
if (args.size() != 1) {
|
||||||
sendUsageMessage(sender); // Reachable if someone does `/give lv90` or similar
|
sendUsageMessage(sender); // Reachable if someone does `/give lv90` or similar
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
param.configId = Integer.parseInt(args.get(0));
|
param.configId = Integer.parseInt(args.get(0));
|
||||||
} catch (NumberFormatException ignored) {
|
} catch (NumberFormatException ignored) {
|
||||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.cfgId"));
|
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.cfgId"));
|
||||||
}
|
}
|
||||||
|
|
||||||
param.scene = targetPlayer.getScene();
|
param.scene = targetPlayer.getScene();
|
||||||
var entity = param.scene.getEntityByConfigId(param.configId);
|
var entity = param.scene.getEntityByConfigId(param.configId);
|
||||||
|
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
CommandHandler.sendMessage(sender, translate(sender, "commands.entity.not_found_error"));
|
CommandHandler.sendMessage(sender, translate(sender, "commands.entity.not_found_error"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
applyFightProps(entity, param);
|
applyFightProps(entity, param);
|
||||||
applyGadgetParams(entity, param);
|
applyGadgetParams(entity, param);
|
||||||
applyMonsterParams(entity, param);
|
applyMonsterParams(entity, param);
|
||||||
|
|
||||||
CommandHandler.sendMessage(sender, translate(sender, "commands.status.success"));
|
CommandHandler.sendMessage(sender, translate(sender, "commands.status.success"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyGadgetParams(GameEntity entity, EntityParameters param) {
|
private void applyGadgetParams(GameEntity entity, EntityParameters param) {
|
||||||
if (!(entity instanceof EntityGadget)) {
|
if (!(entity instanceof EntityGadget)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (param.state != -1) {
|
if (param.state != -1) {
|
||||||
((EntityGadget) entity).updateState(param.state);
|
((EntityGadget) entity).updateState(param.state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyMonsterParams(GameEntity entity, EntityParameters param) {
|
private void applyMonsterParams(GameEntity entity, EntityParameters param) {
|
||||||
if (!(entity instanceof EntityMonster)) {
|
if (!(entity instanceof EntityMonster)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (param.ai != -1) {
|
if (param.ai != -1) {
|
||||||
((EntityMonster) entity).setAiId(param.ai);
|
((EntityMonster) entity).setAiId(param.ai);
|
||||||
// TODO notify
|
// TODO notify
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyFightProps(GameEntity entity, EntityParameters param) {
|
private void applyFightProps(GameEntity entity, EntityParameters param) {
|
||||||
var changedFields = new ArrayList<FightProperty>();
|
var changedFields = new ArrayList<FightProperty>();
|
||||||
if (param.maxHP != -1) {
|
if (param.maxHP != -1) {
|
||||||
setFightProperty(entity, FightProperty.FIGHT_PROP_MAX_HP, param.maxHP, changedFields);
|
setFightProperty(entity, FightProperty.FIGHT_PROP_MAX_HP, param.maxHP, changedFields);
|
||||||
}
|
}
|
||||||
if (param.hp != -1) {
|
if (param.hp != -1) {
|
||||||
float targetHp = param.hp == 0 ? Float.MAX_VALUE : param.hp;
|
float targetHp = param.hp == 0 ? Float.MAX_VALUE : param.hp;
|
||||||
float oldHp = entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
float oldHp = entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||||
setFightProperty(entity, FightProperty.FIGHT_PROP_CUR_HP, targetHp, changedFields);
|
setFightProperty(entity, FightProperty.FIGHT_PROP_CUR_HP, targetHp, changedFields);
|
||||||
EntityDamageEvent event =
|
EntityDamageEvent event =
|
||||||
new EntityDamageEvent(entity, oldHp - targetHp, ElementType.None, null);
|
new EntityDamageEvent(entity, oldHp - targetHp, ElementType.None, null);
|
||||||
callHPEvents(entity, event);
|
callHPEvents(entity, event);
|
||||||
}
|
}
|
||||||
if (param.atk != -1) {
|
if (param.atk != -1) {
|
||||||
setFightProperty(entity, FightProperty.FIGHT_PROP_ATTACK, param.atk, changedFields);
|
setFightProperty(entity, FightProperty.FIGHT_PROP_ATTACK, param.atk, changedFields);
|
||||||
setFightProperty(entity, FightProperty.FIGHT_PROP_CUR_ATTACK, param.atk, changedFields);
|
setFightProperty(entity, FightProperty.FIGHT_PROP_CUR_ATTACK, param.atk, changedFields);
|
||||||
}
|
}
|
||||||
if (param.def != -1) {
|
if (param.def != -1) {
|
||||||
setFightProperty(entity, FightProperty.FIGHT_PROP_DEFENSE, param.def, changedFields);
|
setFightProperty(entity, FightProperty.FIGHT_PROP_DEFENSE, param.def, changedFields);
|
||||||
setFightProperty(entity, FightProperty.FIGHT_PROP_CUR_DEFENSE, param.def, changedFields);
|
setFightProperty(entity, FightProperty.FIGHT_PROP_CUR_DEFENSE, param.def, changedFields);
|
||||||
}
|
}
|
||||||
if (!changedFields.isEmpty()) {
|
if (!changedFields.isEmpty()) {
|
||||||
entity
|
entity
|
||||||
.getScene()
|
.getScene()
|
||||||
.broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, changedFields));
|
.broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, changedFields));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void callHPEvents(GameEntity entity, EntityDamageEvent event) {
|
private void callHPEvents(GameEntity entity, EntityDamageEvent event) {
|
||||||
entity.runLuaCallbacks(event);
|
entity.runLuaCallbacks(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setFightProperty(
|
private void setFightProperty(
|
||||||
GameEntity entity, FightProperty property, float value, List<FightProperty> modifiedProps) {
|
GameEntity entity, FightProperty property, float value, List<FightProperty> modifiedProps) {
|
||||||
entity.setFightProperty(property, value);
|
entity.setFightProperty(property, value);
|
||||||
modifiedProps.add(property);
|
modifiedProps.add(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class EntityParameters {
|
private static class EntityParameters {
|
||||||
@Setter public int configId = -1;
|
@Setter public int configId = -1;
|
||||||
@Setter public int state = -1;
|
@Setter public int state = -1;
|
||||||
@Setter public int hp = -1;
|
@Setter public int hp = -1;
|
||||||
@Setter public int maxHP = -1;
|
@Setter public int maxHP = -1;
|
||||||
@Setter public int atk = -1;
|
@Setter public int atk = -1;
|
||||||
@Setter public int def = -1;
|
@Setter public int def = -1;
|
||||||
@Setter public int ai = -1;
|
@Setter public int ai = -1;
|
||||||
public Scene scene = null;
|
public Scene scene = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,279 +1,279 @@
|
|||||||
package emu.grasscutter.command.commands;
|
package emu.grasscutter.command.commands;
|
||||||
|
|
||||||
import emu.grasscutter.command.Command;
|
import emu.grasscutter.command.Command;
|
||||||
import emu.grasscutter.command.CommandHandler;
|
import emu.grasscutter.command.CommandHandler;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.PlayerProperty;
|
import emu.grasscutter.game.props.PlayerProperty;
|
||||||
import emu.grasscutter.game.tower.TowerLevelRecord;
|
import emu.grasscutter.game.tower.TowerLevelRecord;
|
||||||
import emu.grasscutter.server.packet.send.PacketOpenStateChangeNotify;
|
import emu.grasscutter.server.packet.send.PacketOpenStateChangeNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketSceneAreaUnlockNotify;
|
import emu.grasscutter.server.packet.send.PacketSceneAreaUnlockNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketScenePointUnlockNotify;
|
import emu.grasscutter.server.packet.send.PacketScenePointUnlockNotify;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
label = "setProp",
|
label = "setProp",
|
||||||
aliases = {"prop"},
|
aliases = {"prop"},
|
||||||
usage = {"<prop> <value>"},
|
usage = {"<prop> <value>"},
|
||||||
permission = "player.setprop",
|
permission = "player.setprop",
|
||||||
permissionTargeted = "player.setprop.others")
|
permissionTargeted = "player.setprop.others")
|
||||||
public final class SetPropCommand implements CommandHandler {
|
public final class SetPropCommand implements CommandHandler {
|
||||||
// List of map areas. Unfortunately, there is no readily available source for them in excels or
|
// List of map areas. Unfortunately, there is no readily available source for them in excels or
|
||||||
// bins.
|
// bins.
|
||||||
private static final List<Integer> sceneAreas =
|
private static final List<Integer> sceneAreas =
|
||||||
List.of(
|
List.of(
|
||||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
|
||||||
28, 29, 32, 100, 101, 102, 103, 200, 210, 300, 400, 401, 402, 403);
|
28, 29, 32, 100, 101, 102, 103, 200, 210, 300, 400, 401, 402, 403);
|
||||||
Map<String, Prop> props;
|
Map<String, Prop> props;
|
||||||
|
|
||||||
public SetPropCommand() {
|
public SetPropCommand() {
|
||||||
this.props = new HashMap<>();
|
this.props = new HashMap<>();
|
||||||
// Full PlayerProperty enum that won't be advertised but can be used by devs
|
// Full PlayerProperty enum that won't be advertised but can be used by devs
|
||||||
for (PlayerProperty prop : PlayerProperty.values()) {
|
for (PlayerProperty prop : PlayerProperty.values()) {
|
||||||
String name = prop.toString().substring(5); // PROP_EXP -> EXP
|
String name = prop.toString().substring(5); // PROP_EXP -> EXP
|
||||||
String key = name.toLowerCase(); // EXP -> exp
|
String key = name.toLowerCase(); // EXP -> exp
|
||||||
this.props.put(key, new Prop(name, prop));
|
this.props.put(key, new Prop(name, prop));
|
||||||
}
|
}
|
||||||
// Add special props
|
// Add special props
|
||||||
Prop worldlevel =
|
Prop worldlevel =
|
||||||
new Prop("World Level", PlayerProperty.PROP_PLAYER_WORLD_LEVEL, PseudoProp.WORLD_LEVEL);
|
new Prop("World Level", PlayerProperty.PROP_PLAYER_WORLD_LEVEL, PseudoProp.WORLD_LEVEL);
|
||||||
this.props.put("worldlevel", worldlevel);
|
this.props.put("worldlevel", worldlevel);
|
||||||
this.props.put("wl", worldlevel);
|
this.props.put("wl", worldlevel);
|
||||||
|
|
||||||
Prop abyss = new Prop("Tower Level", PseudoProp.TOWER_LEVEL);
|
Prop abyss = new Prop("Tower Level", PseudoProp.TOWER_LEVEL);
|
||||||
this.props.put("abyss", abyss);
|
this.props.put("abyss", abyss);
|
||||||
this.props.put("abyssfloor", abyss);
|
this.props.put("abyssfloor", abyss);
|
||||||
this.props.put("ut", abyss);
|
this.props.put("ut", abyss);
|
||||||
this.props.put("tower", abyss);
|
this.props.put("tower", abyss);
|
||||||
this.props.put("towerlevel", abyss);
|
this.props.put("towerlevel", abyss);
|
||||||
this.props.put("unlocktower", abyss);
|
this.props.put("unlocktower", abyss);
|
||||||
|
|
||||||
Prop bplevel = new Prop("BP Level", PseudoProp.BP_LEVEL);
|
Prop bplevel = new Prop("BP Level", PseudoProp.BP_LEVEL);
|
||||||
this.props.put("bplevel", bplevel);
|
this.props.put("bplevel", bplevel);
|
||||||
this.props.put("bp", bplevel);
|
this.props.put("bp", bplevel);
|
||||||
this.props.put("battlepass", bplevel);
|
this.props.put("battlepass", bplevel);
|
||||||
|
|
||||||
Prop godmode = new Prop("GodMode", PseudoProp.GOD_MODE);
|
Prop godmode = new Prop("GodMode", PseudoProp.GOD_MODE);
|
||||||
this.props.put("godmode", godmode);
|
this.props.put("godmode", godmode);
|
||||||
this.props.put("god", godmode);
|
this.props.put("god", godmode);
|
||||||
|
|
||||||
Prop nostamina = new Prop("UnlimitedStamina", PseudoProp.UNLIMITED_STAMINA);
|
Prop nostamina = new Prop("UnlimitedStamina", PseudoProp.UNLIMITED_STAMINA);
|
||||||
this.props.put("unlimitedstamina", nostamina);
|
this.props.put("unlimitedstamina", nostamina);
|
||||||
this.props.put("us", nostamina);
|
this.props.put("us", nostamina);
|
||||||
this.props.put("nostamina", nostamina);
|
this.props.put("nostamina", nostamina);
|
||||||
this.props.put("nostam", nostamina);
|
this.props.put("nostam", nostamina);
|
||||||
this.props.put("ns", nostamina);
|
this.props.put("ns", nostamina);
|
||||||
|
|
||||||
Prop unlimitedenergy = new Prop("UnlimitedEnergy", PseudoProp.UNLIMITED_ENERGY);
|
Prop unlimitedenergy = new Prop("UnlimitedEnergy", PseudoProp.UNLIMITED_ENERGY);
|
||||||
this.props.put("unlimitedenergy", unlimitedenergy);
|
this.props.put("unlimitedenergy", unlimitedenergy);
|
||||||
this.props.put("ue", unlimitedenergy);
|
this.props.put("ue", unlimitedenergy);
|
||||||
|
|
||||||
Prop setopenstate = new Prop("SetOpenstate", PseudoProp.SET_OPENSTATE);
|
Prop setopenstate = new Prop("SetOpenstate", PseudoProp.SET_OPENSTATE);
|
||||||
this.props.put("setopenstate", setopenstate);
|
this.props.put("setopenstate", setopenstate);
|
||||||
this.props.put("so", setopenstate);
|
this.props.put("so", setopenstate);
|
||||||
|
|
||||||
Prop unsetopenstate = new Prop("UnsetOpenstate", PseudoProp.UNSET_OPENSTATE);
|
Prop unsetopenstate = new Prop("UnsetOpenstate", PseudoProp.UNSET_OPENSTATE);
|
||||||
this.props.put("unsetopenstate", unsetopenstate);
|
this.props.put("unsetopenstate", unsetopenstate);
|
||||||
this.props.put("uo", unsetopenstate);
|
this.props.put("uo", unsetopenstate);
|
||||||
|
|
||||||
Prop unlockmap = new Prop("UnlockMap", PseudoProp.UNLOCK_MAP);
|
Prop unlockmap = new Prop("UnlockMap", PseudoProp.UNLOCK_MAP);
|
||||||
this.props.put("unlockmap", unlockmap);
|
this.props.put("unlockmap", unlockmap);
|
||||||
this.props.put("um", unlockmap);
|
this.props.put("um", unlockmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||||
if (args.size() != 2) {
|
if (args.size() != 2) {
|
||||||
sendUsageMessage(sender);
|
sendUsageMessage(sender);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String propStr = args.get(0).toLowerCase();
|
String propStr = args.get(0).toLowerCase();
|
||||||
String valueStr = args.get(1).toLowerCase();
|
String valueStr = args.get(1).toLowerCase();
|
||||||
int value;
|
int value;
|
||||||
|
|
||||||
if (!props.containsKey(propStr)) {
|
if (!props.containsKey(propStr)) {
|
||||||
sendUsageMessage(sender);
|
sendUsageMessage(sender);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
value =
|
value =
|
||||||
switch (valueStr.toLowerCase()) {
|
switch (valueStr.toLowerCase()) {
|
||||||
case "on", "true" -> 1;
|
case "on", "true" -> 1;
|
||||||
case "off", "false" -> 0;
|
case "off", "false" -> 0;
|
||||||
case "toggle" -> -1;
|
case "toggle" -> -1;
|
||||||
default -> Integer.parseInt(valueStr);
|
default -> Integer.parseInt(valueStr);
|
||||||
};
|
};
|
||||||
} catch (NumberFormatException ignored) {
|
} catch (NumberFormatException ignored) {
|
||||||
CommandHandler.sendTranslatedMessage(sender, "commands.execution.argument_error");
|
CommandHandler.sendTranslatedMessage(sender, "commands.execution.argument_error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
Prop prop = props.get(propStr);
|
Prop prop = props.get(propStr);
|
||||||
|
|
||||||
success =
|
success =
|
||||||
switch (prop.pseudoProp) {
|
switch (prop.pseudoProp) {
|
||||||
case WORLD_LEVEL -> targetPlayer.setWorldLevel(value);
|
case WORLD_LEVEL -> targetPlayer.setWorldLevel(value);
|
||||||
case BP_LEVEL -> targetPlayer.getBattlePassManager().setLevel(value);
|
case BP_LEVEL -> targetPlayer.getBattlePassManager().setLevel(value);
|
||||||
case TOWER_LEVEL -> this.setTowerLevel(sender, targetPlayer, value);
|
case TOWER_LEVEL -> this.setTowerLevel(sender, targetPlayer, value);
|
||||||
case GOD_MODE, UNLIMITED_STAMINA, UNLIMITED_ENERGY -> this.setBool(
|
case GOD_MODE, UNLIMITED_STAMINA, UNLIMITED_ENERGY -> this.setBool(
|
||||||
sender, targetPlayer, prop.pseudoProp, value);
|
sender, targetPlayer, prop.pseudoProp, value);
|
||||||
case SET_OPENSTATE -> this.setOpenState(targetPlayer, value, 1);
|
case SET_OPENSTATE -> this.setOpenState(targetPlayer, value, 1);
|
||||||
case UNSET_OPENSTATE -> this.setOpenState(targetPlayer, value, 0);
|
case UNSET_OPENSTATE -> this.setOpenState(targetPlayer, value, 0);
|
||||||
case UNLOCK_MAP -> unlockMap(targetPlayer);
|
case UNLOCK_MAP -> unlockMap(targetPlayer);
|
||||||
default -> targetPlayer.setProperty(prop.prop, value);
|
default -> targetPlayer.setProperty(prop.prop, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
if (targetPlayer == sender) {
|
if (targetPlayer == sender) {
|
||||||
CommandHandler.sendTranslatedMessage(
|
CommandHandler.sendTranslatedMessage(
|
||||||
sender, "commands.generic.set_to", prop.name, valueStr);
|
sender, "commands.generic.set_to", prop.name, valueStr);
|
||||||
} else {
|
} else {
|
||||||
String uidStr = targetPlayer.getAccount().getId();
|
String uidStr = targetPlayer.getAccount().getId();
|
||||||
CommandHandler.sendTranslatedMessage(
|
CommandHandler.sendTranslatedMessage(
|
||||||
sender, "commands.generic.set_for_to", prop.name, uidStr, valueStr);
|
sender, "commands.generic.set_for_to", prop.name, uidStr, valueStr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (prop.prop
|
if (prop.prop
|
||||||
!= PlayerProperty.PROP_NONE) { // PseudoProps need to do their own error messages
|
!= PlayerProperty.PROP_NONE) { // PseudoProps need to do their own error messages
|
||||||
int min = targetPlayer.getPropertyMin(prop.prop);
|
int min = targetPlayer.getPropertyMin(prop.prop);
|
||||||
int max = targetPlayer.getPropertyMax(prop.prop);
|
int max = targetPlayer.getPropertyMax(prop.prop);
|
||||||
CommandHandler.sendTranslatedMessage(
|
CommandHandler.sendTranslatedMessage(
|
||||||
sender, "commands.generic.invalid.value_between", prop.name, min, max);
|
sender, "commands.generic.invalid.value_between", prop.name, min, max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean setTowerLevel(Player sender, Player targetPlayer, int topFloor) {
|
private boolean setTowerLevel(Player sender, Player targetPlayer, int topFloor) {
|
||||||
List<Integer> floorIds = targetPlayer.getServer().getTowerSystem().getAllFloors();
|
List<Integer> floorIds = targetPlayer.getServer().getTowerSystem().getAllFloors();
|
||||||
if (topFloor < 0 || topFloor > floorIds.size()) {
|
if (topFloor < 0 || topFloor > floorIds.size()) {
|
||||||
CommandHandler.sendTranslatedMessage(
|
CommandHandler.sendTranslatedMessage(
|
||||||
sender, "commands.generic.invalid.value_between", "Tower Level", 0, floorIds.size());
|
sender, "commands.generic.invalid.value_between", "Tower Level", 0, floorIds.size());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<Integer, TowerLevelRecord> recordMap = targetPlayer.getTowerManager().getRecordMap();
|
Map<Integer, TowerLevelRecord> recordMap = targetPlayer.getTowerManager().getRecordMap();
|
||||||
// Add records for each unlocked floor
|
// Add records for each unlocked floor
|
||||||
for (int floor : floorIds.subList(0, topFloor)) {
|
for (int floor : floorIds.subList(0, topFloor)) {
|
||||||
if (!recordMap.containsKey(floor)) {
|
if (!recordMap.containsKey(floor)) {
|
||||||
recordMap.put(floor, new TowerLevelRecord(floor));
|
recordMap.put(floor, new TowerLevelRecord(floor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Remove records for each floor past our target
|
// Remove records for each floor past our target
|
||||||
for (int floor : floorIds.subList(topFloor, floorIds.size())) {
|
for (int floor : floorIds.subList(topFloor, floorIds.size())) {
|
||||||
recordMap.remove(floor);
|
recordMap.remove(floor);
|
||||||
}
|
}
|
||||||
// Six stars required on Floor 8 to unlock Floor 9+
|
// Six stars required on Floor 8 to unlock Floor 9+
|
||||||
if (topFloor > 8) {
|
if (topFloor > 8) {
|
||||||
recordMap
|
recordMap
|
||||||
.get(floorIds.get(7))
|
.get(floorIds.get(7))
|
||||||
.setLevelStars(
|
.setLevelStars(
|
||||||
0,
|
0,
|
||||||
6); // levelIds seem to start at 1 for Floor 1 Chamber 1, so this doesn't get shown at
|
6); // levelIds seem to start at 1 for Floor 1 Chamber 1, so this doesn't get shown at
|
||||||
// all
|
// all
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean setBool(Player sender, Player targetPlayer, PseudoProp pseudoProp, int value) {
|
private boolean setBool(Player sender, Player targetPlayer, PseudoProp pseudoProp, int value) {
|
||||||
boolean enabled =
|
boolean enabled =
|
||||||
switch (pseudoProp) {
|
switch (pseudoProp) {
|
||||||
case GOD_MODE -> targetPlayer.isInGodMode();
|
case GOD_MODE -> targetPlayer.isInGodMode();
|
||||||
case UNLIMITED_STAMINA -> targetPlayer.isUnlimitedStamina();
|
case UNLIMITED_STAMINA -> targetPlayer.isUnlimitedStamina();
|
||||||
case UNLIMITED_ENERGY -> !targetPlayer.getEnergyManager().isEnergyUsage();
|
case UNLIMITED_ENERGY -> !targetPlayer.getEnergyManager().isEnergyUsage();
|
||||||
default -> false;
|
default -> false;
|
||||||
};
|
};
|
||||||
enabled =
|
enabled =
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case -1 -> !enabled;
|
case -1 -> !enabled;
|
||||||
case 0 -> false;
|
case 0 -> false;
|
||||||
default -> true;
|
default -> true;
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (pseudoProp) {
|
switch (pseudoProp) {
|
||||||
case GOD_MODE:
|
case GOD_MODE:
|
||||||
targetPlayer.setInGodMode(enabled);
|
targetPlayer.setInGodMode(enabled);
|
||||||
break;
|
break;
|
||||||
case UNLIMITED_STAMINA:
|
case UNLIMITED_STAMINA:
|
||||||
targetPlayer.setUnlimitedStamina(enabled);
|
targetPlayer.setUnlimitedStamina(enabled);
|
||||||
break;
|
break;
|
||||||
case UNLIMITED_ENERGY:
|
case UNLIMITED_ENERGY:
|
||||||
targetPlayer.getEnergyManager().setEnergyUsage(!enabled);
|
targetPlayer.getEnergyManager().setEnergyUsage(!enabled);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean setOpenState(Player targetPlayer, int state, int value) {
|
private boolean setOpenState(Player targetPlayer, int state, int value) {
|
||||||
targetPlayer.sendPacket(new PacketOpenStateChangeNotify(state, value));
|
targetPlayer.sendPacket(new PacketOpenStateChangeNotify(state, value));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean unlockMap(Player targetPlayer) {
|
private boolean unlockMap(Player targetPlayer) {
|
||||||
// Unlock.
|
// Unlock.
|
||||||
GameData.getScenePointsPerScene()
|
GameData.getScenePointsPerScene()
|
||||||
.forEach(
|
.forEach(
|
||||||
(sceneId, scenePoints) -> {
|
(sceneId, scenePoints) -> {
|
||||||
// Unlock trans points.
|
// Unlock trans points.
|
||||||
targetPlayer.getUnlockedScenePoints(sceneId).addAll(scenePoints);
|
targetPlayer.getUnlockedScenePoints(sceneId).addAll(scenePoints);
|
||||||
|
|
||||||
// Unlock map areas.
|
// Unlock map areas.
|
||||||
targetPlayer.getUnlockedSceneAreas(sceneId).addAll(sceneAreas);
|
targetPlayer.getUnlockedSceneAreas(sceneId).addAll(sceneAreas);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Send notify.
|
// Send notify.
|
||||||
int playerScene = targetPlayer.getSceneId();
|
int playerScene = targetPlayer.getSceneId();
|
||||||
targetPlayer.sendPacket(
|
targetPlayer.sendPacket(
|
||||||
new PacketScenePointUnlockNotify(
|
new PacketScenePointUnlockNotify(
|
||||||
playerScene, targetPlayer.getUnlockedScenePoints(playerScene)));
|
playerScene, targetPlayer.getUnlockedScenePoints(playerScene)));
|
||||||
targetPlayer.sendPacket(
|
targetPlayer.sendPacket(
|
||||||
new PacketSceneAreaUnlockNotify(
|
new PacketSceneAreaUnlockNotify(
|
||||||
playerScene, targetPlayer.getUnlockedSceneAreas(playerScene)));
|
playerScene, targetPlayer.getUnlockedSceneAreas(playerScene)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PseudoProp {
|
enum PseudoProp {
|
||||||
NONE,
|
NONE,
|
||||||
WORLD_LEVEL,
|
WORLD_LEVEL,
|
||||||
TOWER_LEVEL,
|
TOWER_LEVEL,
|
||||||
BP_LEVEL,
|
BP_LEVEL,
|
||||||
GOD_MODE,
|
GOD_MODE,
|
||||||
UNLIMITED_STAMINA,
|
UNLIMITED_STAMINA,
|
||||||
UNLIMITED_ENERGY,
|
UNLIMITED_ENERGY,
|
||||||
SET_OPENSTATE,
|
SET_OPENSTATE,
|
||||||
UNSET_OPENSTATE,
|
UNSET_OPENSTATE,
|
||||||
UNLOCK_MAP
|
UNLOCK_MAP
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Prop {
|
static class Prop {
|
||||||
String name;
|
String name;
|
||||||
PlayerProperty prop;
|
PlayerProperty prop;
|
||||||
PseudoProp pseudoProp;
|
PseudoProp pseudoProp;
|
||||||
|
|
||||||
public Prop(PlayerProperty prop) {
|
public Prop(PlayerProperty prop) {
|
||||||
this(prop.toString(), prop, PseudoProp.NONE);
|
this(prop.toString(), prop, PseudoProp.NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Prop(String name) {
|
public Prop(String name) {
|
||||||
this(name, PlayerProperty.PROP_NONE, PseudoProp.NONE);
|
this(name, PlayerProperty.PROP_NONE, PseudoProp.NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Prop(String name, PseudoProp pseudoProp) {
|
public Prop(String name, PseudoProp pseudoProp) {
|
||||||
this(name, PlayerProperty.PROP_NONE, pseudoProp);
|
this(name, PlayerProperty.PROP_NONE, pseudoProp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Prop(String name, PlayerProperty prop) {
|
public Prop(String name, PlayerProperty prop) {
|
||||||
this(name, prop, PseudoProp.NONE);
|
this(name, prop, PseudoProp.NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Prop(String name, PlayerProperty prop, PseudoProp pseudoProp) {
|
public Prop(String name, PlayerProperty prop, PseudoProp pseudoProp) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.prop = prop;
|
this.prop = prop;
|
||||||
this.pseudoProp = pseudoProp;
|
this.pseudoProp = pseudoProp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,58 +1,70 @@
|
|||||||
package emu.grasscutter.data.common;
|
package emu.grasscutter.data.common;
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.excels.dungeon.DailyDungeonData;
|
||||||
import emu.grasscutter.data.excels.dungeon.DailyDungeonData;
|
import emu.grasscutter.utils.Position;
|
||||||
import emu.grasscutter.utils.Position;
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
import it.unimi.dsi.fastutil.ints.IntList;
|
import lombok.Getter;
|
||||||
import lombok.Getter;
|
import lombok.Setter;
|
||||||
import lombok.Setter;
|
|
||||||
|
public final class PointData {
|
||||||
public final class PointData {
|
@Getter @Setter private int id;
|
||||||
@Getter @Setter private int id;
|
private String $type;
|
||||||
private String $type;
|
@Getter private Position tranPos;
|
||||||
@Getter private Position tranPos;
|
@Getter private Position pos;
|
||||||
@Getter private Position pos;
|
@Getter private Position rot;
|
||||||
@Getter private Position rot;
|
@Getter private Position size;
|
||||||
@Getter private Position size;
|
|
||||||
|
@SerializedName(
|
||||||
@SerializedName(value="dungeonIds", alternate={"JHHFPGJNMIN"})
|
value = "dungeonIds",
|
||||||
@Getter private int[] dungeonIds;
|
alternate = {"JHHFPGJNMIN"})
|
||||||
|
@Getter
|
||||||
@SerializedName(value="dungeonRandomList", alternate={"OIBKFJNBLHO"})
|
private int[] dungeonIds;
|
||||||
@Getter private int[] dungeonRandomList;
|
|
||||||
|
@SerializedName(
|
||||||
@SerializedName(value="groupIDs", alternate={"HFOBOOHKBGF"})
|
value = "dungeonRandomList",
|
||||||
@Getter private int[] groupIDs;
|
alternate = {"OIBKFJNBLHO"})
|
||||||
|
@Getter
|
||||||
@SerializedName(value="tranSceneId", alternate={"JHBICGBAPIH"})
|
private int[] dungeonRandomList;
|
||||||
@Getter @Setter private int tranSceneId;
|
|
||||||
|
@SerializedName(
|
||||||
public String getType() {
|
value = "groupIDs",
|
||||||
return $type;
|
alternate = {"HFOBOOHKBGF"})
|
||||||
}
|
@Getter
|
||||||
|
private int[] groupIDs;
|
||||||
public void updateDailyDungeon() {
|
|
||||||
if (this.dungeonRandomList == null || this.dungeonRandomList.length == 0) {
|
@SerializedName(
|
||||||
return;
|
value = "tranSceneId",
|
||||||
}
|
alternate = {"JHBICGBAPIH"})
|
||||||
|
@Getter
|
||||||
IntList newDungeons = new IntArrayList();
|
@Setter
|
||||||
int day = Grasscutter.getCurrentDayOfWeek();
|
private int tranSceneId;
|
||||||
|
|
||||||
for (int randomId : this.dungeonRandomList) {
|
public String getType() {
|
||||||
DailyDungeonData data = GameData.getDailyDungeonDataMap().get(randomId);
|
return $type;
|
||||||
|
}
|
||||||
if (data != null) {
|
|
||||||
for (int d : data.getDungeonsByDay(day)) {
|
public void updateDailyDungeon() {
|
||||||
newDungeons.add(d);
|
if (this.dungeonRandomList == null || this.dungeonRandomList.length == 0) {
|
||||||
}
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
IntList newDungeons = new IntArrayList();
|
||||||
this.dungeonIds = newDungeons.toIntArray();
|
int day = Grasscutter.getCurrentDayOfWeek();
|
||||||
}
|
|
||||||
}
|
for (int randomId : this.dungeonRandomList) {
|
||||||
|
DailyDungeonData data = GameData.getDailyDungeonDataMap().get(randomId);
|
||||||
|
|
||||||
|
if (data != null) {
|
||||||
|
for (int d : data.getDungeonsByDay(day)) {
|
||||||
|
newDungeons.add(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dungeonIds = newDungeons.toIntArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
package emu.grasscutter.data.excels;
|
package emu.grasscutter.data.excels;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameResource;
|
import emu.grasscutter.data.GameResource;
|
||||||
import emu.grasscutter.data.ResourceType;
|
import emu.grasscutter.data.ResourceType;
|
||||||
import emu.grasscutter.game.props.EntityType;
|
import emu.grasscutter.game.props.EntityType;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@ResourceType(name = "GadgetExcelConfigData.json")
|
@ResourceType(name = "GadgetExcelConfigData.json")
|
||||||
@Getter
|
@Getter
|
||||||
public final class GadgetData extends GameResource {
|
public final class GadgetData extends GameResource {
|
||||||
@Getter(onMethod_ = @Override)
|
@Getter(onMethod_ = @Override)
|
||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
private EntityType type;
|
private EntityType type;
|
||||||
private String jsonName;
|
private String jsonName;
|
||||||
private boolean isInteractive;
|
private boolean isInteractive;
|
||||||
private String[] tags;
|
private String[] tags;
|
||||||
private String itemJsonName;
|
private String itemJsonName;
|
||||||
private long nameTextMapHash;
|
private long nameTextMapHash;
|
||||||
private int campId;
|
private int campId;
|
||||||
private String visionLevel;
|
private String visionLevel;
|
||||||
}
|
}
|
||||||
|
@ -1,120 +1,133 @@
|
|||||||
package emu.grasscutter.data.excels.monster;
|
package emu.grasscutter.data.excels.monster;
|
||||||
|
|
||||||
import java.util.List;
|
import com.google.gson.annotations.SerializedName;
|
||||||
import java.util.Map.Entry;
|
import emu.grasscutter.data.GameData;
|
||||||
import java.util.Set;
|
import emu.grasscutter.data.GameResource;
|
||||||
|
import emu.grasscutter.data.ResourceType;
|
||||||
import com.google.gson.annotations.SerializedName;
|
import emu.grasscutter.data.ResourceType.LoadPriority;
|
||||||
|
import emu.grasscutter.data.common.PropGrowCurve;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.excels.GadgetData;
|
||||||
import emu.grasscutter.data.GameResource;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.data.ResourceType;
|
import emu.grasscutter.game.props.MonsterType;
|
||||||
import emu.grasscutter.data.ResourceType.LoadPriority;
|
import java.util.List;
|
||||||
import emu.grasscutter.data.common.PropGrowCurve;
|
import java.util.Map.Entry;
|
||||||
import emu.grasscutter.data.excels.GadgetData;
|
import java.util.Set;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import lombok.Getter;
|
||||||
import emu.grasscutter.game.props.MonsterType;
|
|
||||||
import lombok.Getter;
|
@ResourceType(name = "MonsterExcelConfigData.json", loadPriority = LoadPriority.LOW)
|
||||||
|
@Getter
|
||||||
@ResourceType(name = "MonsterExcelConfigData.json", loadPriority = LoadPriority.LOW)
|
public class MonsterData extends GameResource {
|
||||||
@Getter
|
public static Set<FightProperty> definedFightProperties =
|
||||||
public class MonsterData extends GameResource {
|
Set.of(
|
||||||
static public Set<FightProperty> definedFightProperties = Set.of(FightProperty.FIGHT_PROP_BASE_HP, FightProperty.FIGHT_PROP_BASE_ATTACK, FightProperty.FIGHT_PROP_BASE_DEFENSE, FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT, FightProperty.FIGHT_PROP_FIRE_SUB_HURT, FightProperty.FIGHT_PROP_ELEC_SUB_HURT, FightProperty.FIGHT_PROP_WATER_SUB_HURT, FightProperty.FIGHT_PROP_GRASS_SUB_HURT, FightProperty.FIGHT_PROP_WIND_SUB_HURT, FightProperty.FIGHT_PROP_ROCK_SUB_HURT, FightProperty.FIGHT_PROP_ICE_SUB_HURT);
|
FightProperty.FIGHT_PROP_BASE_HP,
|
||||||
|
FightProperty.FIGHT_PROP_BASE_ATTACK,
|
||||||
@Getter(onMethod_ = @Override)
|
FightProperty.FIGHT_PROP_BASE_DEFENSE,
|
||||||
private int id;
|
FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT,
|
||||||
|
FightProperty.FIGHT_PROP_FIRE_SUB_HURT,
|
||||||
private String monsterName;
|
FightProperty.FIGHT_PROP_ELEC_SUB_HURT,
|
||||||
private MonsterType type;
|
FightProperty.FIGHT_PROP_WATER_SUB_HURT,
|
||||||
private String serverScript;
|
FightProperty.FIGHT_PROP_GRASS_SUB_HURT,
|
||||||
private List<Integer> affix;
|
FightProperty.FIGHT_PROP_WIND_SUB_HURT,
|
||||||
private String ai;
|
FightProperty.FIGHT_PROP_ROCK_SUB_HURT,
|
||||||
private int[] equips;
|
FightProperty.FIGHT_PROP_ICE_SUB_HURT);
|
||||||
private List<HpDrops> hpDrops;
|
|
||||||
private int killDropId;
|
@Getter(onMethod_ = @Override)
|
||||||
private String excludeWeathers;
|
private int id;
|
||||||
private int featureTagGroupID;
|
|
||||||
private int mpPropID;
|
private String monsterName;
|
||||||
private String skin;
|
private MonsterType type;
|
||||||
private int describeId;
|
private String serverScript;
|
||||||
private int combatBGMLevel;
|
private List<Integer> affix;
|
||||||
private int entityBudgetLevel;
|
private String ai;
|
||||||
|
private int[] equips;
|
||||||
@SerializedName("hpBase")
|
private List<HpDrops> hpDrops;
|
||||||
private float baseHp;
|
private int killDropId;
|
||||||
@SerializedName("attackBase")
|
private String excludeWeathers;
|
||||||
private float baseAttack;
|
private int featureTagGroupID;
|
||||||
@SerializedName("defenseBase")
|
private int mpPropID;
|
||||||
private float baseDefense;
|
private String skin;
|
||||||
|
private int describeId;
|
||||||
private float fireSubHurt;
|
private int combatBGMLevel;
|
||||||
private float elecSubHurt;
|
private int entityBudgetLevel;
|
||||||
private float grassSubHurt;
|
|
||||||
private float waterSubHurt;
|
@SerializedName("hpBase")
|
||||||
private float windSubHurt;
|
private float baseHp;
|
||||||
private float rockSubHurt;
|
|
||||||
private float iceSubHurt;
|
@SerializedName("attackBase")
|
||||||
private float physicalSubHurt;
|
private float baseAttack;
|
||||||
private List<PropGrowCurve> propGrowCurves;
|
|
||||||
private long nameTextMapHash;
|
@SerializedName("defenseBase")
|
||||||
private int campID;
|
private float baseDefense;
|
||||||
|
|
||||||
// Transient
|
private float fireSubHurt;
|
||||||
private int weaponId;
|
private float elecSubHurt;
|
||||||
private MonsterDescribeData describeData;
|
private float grassSubHurt;
|
||||||
|
private float waterSubHurt;
|
||||||
private int specialNameId; // will only be set if describe data is available
|
private float windSubHurt;
|
||||||
|
private float rockSubHurt;
|
||||||
@Override
|
private float iceSubHurt;
|
||||||
public void onLoad() {
|
private float physicalSubHurt;
|
||||||
for (int id : this.equips) {
|
private List<PropGrowCurve> propGrowCurves;
|
||||||
if (id == 0) {
|
private long nameTextMapHash;
|
||||||
continue;
|
private int campID;
|
||||||
}
|
|
||||||
|
// Transient
|
||||||
GadgetData gadget = GameData.getGadgetDataMap().get(id);
|
private int weaponId;
|
||||||
if (gadget == null) {
|
private MonsterDescribeData describeData;
|
||||||
continue;
|
|
||||||
}
|
private int specialNameId; // will only be set if describe data is available
|
||||||
|
|
||||||
if (gadget.getItemJsonName().equals("Default_MonsterWeapon")) {
|
@Override
|
||||||
this.weaponId = id;
|
public void onLoad() {
|
||||||
}
|
for (int id : this.equips) {
|
||||||
}
|
if (id == 0) {
|
||||||
|
continue;
|
||||||
this.describeData = GameData.getMonsterDescribeDataMap().get(this.getDescribeId());
|
}
|
||||||
|
|
||||||
if (this.describeData == null){
|
GadgetData gadget = GameData.getGadgetDataMap().get(id);
|
||||||
return;
|
if (gadget == null) {
|
||||||
}
|
continue;
|
||||||
for(Entry<Integer, MonsterSpecialNameData> entry: GameData.getMonsterSpecialNameDataMap().entrySet()) {
|
}
|
||||||
if (entry.getValue().getSpecialNameLabId() == this.getDescribeData().getSpecialNameLabId()){
|
|
||||||
this.specialNameId = entry.getKey();
|
if (gadget.getItemJsonName().equals("Default_MonsterWeapon")) {
|
||||||
break;
|
this.weaponId = id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
this.describeData = GameData.getMonsterDescribeDataMap().get(this.getDescribeId());
|
||||||
public float getFightProperty(FightProperty prop) {
|
|
||||||
return switch (prop) {
|
if (this.describeData == null) {
|
||||||
case FIGHT_PROP_BASE_HP -> this.baseHp;
|
return;
|
||||||
case FIGHT_PROP_BASE_ATTACK -> this.baseAttack;
|
}
|
||||||
case FIGHT_PROP_BASE_DEFENSE -> this.baseDefense;
|
for (Entry<Integer, MonsterSpecialNameData> entry :
|
||||||
case FIGHT_PROP_PHYSICAL_SUB_HURT -> this.physicalSubHurt;
|
GameData.getMonsterSpecialNameDataMap().entrySet()) {
|
||||||
case FIGHT_PROP_FIRE_SUB_HURT -> this.fireSubHurt;
|
if (entry.getValue().getSpecialNameLabId() == this.getDescribeData().getSpecialNameLabId()) {
|
||||||
case FIGHT_PROP_ELEC_SUB_HURT -> this.elecSubHurt;
|
this.specialNameId = entry.getKey();
|
||||||
case FIGHT_PROP_WATER_SUB_HURT -> this.waterSubHurt;
|
break;
|
||||||
case FIGHT_PROP_GRASS_SUB_HURT -> this.grassSubHurt;
|
}
|
||||||
case FIGHT_PROP_WIND_SUB_HURT -> this.windSubHurt;
|
}
|
||||||
case FIGHT_PROP_ROCK_SUB_HURT -> this.rockSubHurt;
|
}
|
||||||
case FIGHT_PROP_ICE_SUB_HURT -> this.iceSubHurt;
|
|
||||||
default -> 0f;
|
public float getFightProperty(FightProperty prop) {
|
||||||
};
|
return switch (prop) {
|
||||||
}
|
case FIGHT_PROP_BASE_HP -> this.baseHp;
|
||||||
|
case FIGHT_PROP_BASE_ATTACK -> this.baseAttack;
|
||||||
@Getter
|
case FIGHT_PROP_BASE_DEFENSE -> this.baseDefense;
|
||||||
public class HpDrops {
|
case FIGHT_PROP_PHYSICAL_SUB_HURT -> this.physicalSubHurt;
|
||||||
private int DropId;
|
case FIGHT_PROP_FIRE_SUB_HURT -> this.fireSubHurt;
|
||||||
private int HpPercent;
|
case FIGHT_PROP_ELEC_SUB_HURT -> this.elecSubHurt;
|
||||||
}
|
case FIGHT_PROP_WATER_SUB_HURT -> this.waterSubHurt;
|
||||||
}
|
case FIGHT_PROP_GRASS_SUB_HURT -> this.grassSubHurt;
|
||||||
|
case FIGHT_PROP_WIND_SUB_HURT -> this.windSubHurt;
|
||||||
|
case FIGHT_PROP_ROCK_SUB_HURT -> this.rockSubHurt;
|
||||||
|
case FIGHT_PROP_ICE_SUB_HURT -> this.iceSubHurt;
|
||||||
|
default -> 0f;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class HpDrops {
|
||||||
|
private int DropId;
|
||||||
|
private int HpPercent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,21 +1,28 @@
|
|||||||
package emu.grasscutter.data.excels.monster;
|
package emu.grasscutter.data.excels.monster;
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
import emu.grasscutter.data.GameResource;
|
import emu.grasscutter.data.GameResource;
|
||||||
import emu.grasscutter.data.ResourceType;
|
import emu.grasscutter.data.ResourceType;
|
||||||
import emu.grasscutter.data.ResourceType.LoadPriority;
|
import emu.grasscutter.data.ResourceType.LoadPriority;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@ResourceType(name = "MonsterDescribeExcelConfigData.json", loadPriority = LoadPriority.HIGH)
|
@ResourceType(name = "MonsterDescribeExcelConfigData.json", loadPriority = LoadPriority.HIGH)
|
||||||
@Getter
|
@Getter
|
||||||
public class MonsterDescribeData extends GameResource {
|
public class MonsterDescribeData extends GameResource {
|
||||||
@Getter(onMethod_ = @Override)
|
@Getter(onMethod_ = @Override)
|
||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
private long nameTextMapHash;
|
private long nameTextMapHash;
|
||||||
@SerializedName(value = "titleId", alternate={"titleID"})
|
|
||||||
private int titleId;
|
@SerializedName(
|
||||||
@SerializedName(value = "specialNameLabId", alternate={"specialNameLabID"})
|
value = "titleId",
|
||||||
private int specialNameLabId;
|
alternate = {"titleID"})
|
||||||
private MonsterSpecialNameData specialNameData;
|
private int titleId;
|
||||||
}
|
|
||||||
|
@SerializedName(
|
||||||
|
value = "specialNameLabId",
|
||||||
|
alternate = {"specialNameLabID"})
|
||||||
|
private int specialNameLabId;
|
||||||
|
|
||||||
|
private MonsterSpecialNameData specialNameData;
|
||||||
|
}
|
||||||
|
@ -1,464 +1,464 @@
|
|||||||
package emu.grasscutter.database;
|
package emu.grasscutter.database;
|
||||||
|
|
||||||
import static com.mongodb.client.model.Filters.eq;
|
import static com.mongodb.client.model.Filters.eq;
|
||||||
|
|
||||||
import com.mongodb.client.result.DeleteResult;
|
import com.mongodb.client.result.DeleteResult;
|
||||||
import dev.morphia.query.FindOptions;
|
import dev.morphia.query.FindOptions;
|
||||||
import dev.morphia.query.Sort;
|
import dev.morphia.query.Sort;
|
||||||
import dev.morphia.query.experimental.filters.Filters;
|
import dev.morphia.query.experimental.filters.Filters;
|
||||||
import emu.grasscutter.GameConstants;
|
import emu.grasscutter.GameConstants;
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.game.Account;
|
import emu.grasscutter.game.Account;
|
||||||
import emu.grasscutter.game.achievement.Achievements;
|
import emu.grasscutter.game.achievement.Achievements;
|
||||||
import emu.grasscutter.game.activity.PlayerActivityData;
|
import emu.grasscutter.game.activity.PlayerActivityData;
|
||||||
import emu.grasscutter.game.activity.musicgame.MusicGameBeatmap;
|
import emu.grasscutter.game.activity.musicgame.MusicGameBeatmap;
|
||||||
import emu.grasscutter.game.avatar.Avatar;
|
import emu.grasscutter.game.avatar.Avatar;
|
||||||
import emu.grasscutter.game.battlepass.BattlePassManager;
|
import emu.grasscutter.game.battlepass.BattlePassManager;
|
||||||
import emu.grasscutter.game.friends.Friendship;
|
import emu.grasscutter.game.friends.Friendship;
|
||||||
import emu.grasscutter.game.gacha.GachaRecord;
|
import emu.grasscutter.game.gacha.GachaRecord;
|
||||||
import emu.grasscutter.game.home.GameHome;
|
import emu.grasscutter.game.home.GameHome;
|
||||||
import emu.grasscutter.game.inventory.GameItem;
|
import emu.grasscutter.game.inventory.GameItem;
|
||||||
import emu.grasscutter.game.mail.Mail;
|
import emu.grasscutter.game.mail.Mail;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.quest.GameMainQuest;
|
import emu.grasscutter.game.quest.GameMainQuest;
|
||||||
import emu.grasscutter.game.world.SceneGroupInstance;
|
import emu.grasscutter.game.world.SceneGroupInstance;
|
||||||
|
import java.util.List;
|
||||||
import java.util.List;
|
import java.util.stream.Stream;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
public final class DatabaseHelper {
|
||||||
public final class DatabaseHelper {
|
public static Account createAccount(String username) {
|
||||||
public static Account createAccount(String username) {
|
return createAccountWithUid(username, 0);
|
||||||
return createAccountWithUid(username, 0);
|
}
|
||||||
}
|
|
||||||
|
public static Account createAccountWithUid(String username, int reservedUid) {
|
||||||
public static Account createAccountWithUid(String username, int reservedUid) {
|
// Unique names only
|
||||||
// Unique names only
|
if (DatabaseHelper.checkIfAccountExists(username)) {
|
||||||
if (DatabaseHelper.checkIfAccountExists(username)) {
|
return null;
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
// Make sure there are no id collisions
|
||||||
// Make sure there are no id collisions
|
if (reservedUid > 0) {
|
||||||
if (reservedUid > 0) {
|
// Cannot make account with the same uid as the server console
|
||||||
// Cannot make account with the same uid as the server console
|
if (reservedUid == GameConstants.SERVER_CONSOLE_UID) {
|
||||||
if (reservedUid == GameConstants.SERVER_CONSOLE_UID) {
|
return null;
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
if (DatabaseHelper.checkIfAccountExists(reservedUid)) {
|
||||||
if (DatabaseHelper.checkIfAccountExists(reservedUid)) {
|
return null;
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
// Make sure no existing player already has this id.
|
||||||
// Make sure no existing player already has this id.
|
if (DatabaseHelper.checkIfPlayerExists(reservedUid)) {
|
||||||
if (DatabaseHelper.checkIfPlayerExists(reservedUid)) {
|
return null;
|
||||||
return null;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Account
|
||||||
// Account
|
Account account = new Account();
|
||||||
Account account = new Account();
|
account.setUsername(username);
|
||||||
account.setUsername(username);
|
account.setId(Integer.toString(DatabaseManager.getNextId(account)));
|
||||||
account.setId(Integer.toString(DatabaseManager.getNextId(account)));
|
|
||||||
|
if (reservedUid > 0) {
|
||||||
if (reservedUid > 0) {
|
account.setReservedPlayerUid(reservedUid);
|
||||||
account.setReservedPlayerUid(reservedUid);
|
}
|
||||||
}
|
|
||||||
|
DatabaseHelper.saveAccount(account);
|
||||||
DatabaseHelper.saveAccount(account);
|
return account;
|
||||||
return account;
|
}
|
||||||
}
|
|
||||||
|
@Deprecated
|
||||||
@Deprecated
|
public static Account createAccountWithPassword(String username, String password) {
|
||||||
public static Account createAccountWithPassword(String username, String password) {
|
// Unique names only
|
||||||
// Unique names only
|
Account exists = DatabaseHelper.getAccountByName(username);
|
||||||
Account exists = DatabaseHelper.getAccountByName(username);
|
if (exists != null) {
|
||||||
if (exists != null) {
|
return null;
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
// Account
|
||||||
// Account
|
Account account = new Account();
|
||||||
Account account = new Account();
|
account.setId(Integer.toString(DatabaseManager.getNextId(account)));
|
||||||
account.setId(Integer.toString(DatabaseManager.getNextId(account)));
|
account.setUsername(username);
|
||||||
account.setUsername(username);
|
account.setPassword(password);
|
||||||
account.setPassword(password);
|
DatabaseHelper.saveAccount(account);
|
||||||
DatabaseHelper.saveAccount(account);
|
return account;
|
||||||
return account;
|
}
|
||||||
}
|
|
||||||
|
public static void saveAccount(Account account) {
|
||||||
public static void saveAccount(Account account) {
|
DatabaseManager.getAccountDatastore().save(account);
|
||||||
DatabaseManager.getAccountDatastore().save(account);
|
}
|
||||||
}
|
|
||||||
|
public static Account getAccountByName(String username) {
|
||||||
public static Account getAccountByName(String username) {
|
return DatabaseManager.getAccountDatastore()
|
||||||
return DatabaseManager.getAccountDatastore()
|
.find(Account.class)
|
||||||
.find(Account.class)
|
.filter(Filters.eq("username", username))
|
||||||
.filter(Filters.eq("username", username))
|
.first();
|
||||||
.first();
|
}
|
||||||
}
|
|
||||||
|
public static Account getAccountByToken(String token) {
|
||||||
public static Account getAccountByToken(String token) {
|
if (token == null) return null;
|
||||||
if (token == null) return null;
|
return DatabaseManager.getAccountDatastore()
|
||||||
return DatabaseManager.getAccountDatastore()
|
.find(Account.class)
|
||||||
.find(Account.class)
|
.filter(Filters.eq("token", token))
|
||||||
.filter(Filters.eq("token", token))
|
.first();
|
||||||
.first();
|
}
|
||||||
}
|
|
||||||
|
public static Account getAccountBySessionKey(String sessionKey) {
|
||||||
public static Account getAccountBySessionKey(String sessionKey) {
|
if (sessionKey == null) return null;
|
||||||
if (sessionKey == null) return null;
|
return DatabaseManager.getAccountDatastore()
|
||||||
return DatabaseManager.getAccountDatastore()
|
.find(Account.class)
|
||||||
.find(Account.class)
|
.filter(Filters.eq("sessionKey", sessionKey))
|
||||||
.filter(Filters.eq("sessionKey", sessionKey))
|
.first();
|
||||||
.first();
|
}
|
||||||
}
|
|
||||||
|
public static Account getAccountById(String uid) {
|
||||||
public static Account getAccountById(String uid) {
|
return DatabaseManager.getAccountDatastore()
|
||||||
return DatabaseManager.getAccountDatastore()
|
.find(Account.class)
|
||||||
.find(Account.class)
|
.filter(Filters.eq("_id", uid))
|
||||||
.filter(Filters.eq("_id", uid))
|
.first();
|
||||||
.first();
|
}
|
||||||
}
|
|
||||||
|
public static Account getAccountByPlayerId(int playerId) {
|
||||||
public static Account getAccountByPlayerId(int playerId) {
|
return DatabaseManager.getAccountDatastore()
|
||||||
return DatabaseManager.getAccountDatastore()
|
.find(Account.class)
|
||||||
.find(Account.class)
|
.filter(Filters.eq("reservedPlayerId", playerId))
|
||||||
.filter(Filters.eq("reservedPlayerId", playerId))
|
.first();
|
||||||
.first();
|
}
|
||||||
}
|
|
||||||
|
public static boolean checkIfAccountExists(String name) {
|
||||||
public static boolean checkIfAccountExists(String name) {
|
return DatabaseManager.getAccountDatastore()
|
||||||
return DatabaseManager.getAccountDatastore()
|
.find(Account.class)
|
||||||
.find(Account.class)
|
.filter(Filters.eq("username", name))
|
||||||
.filter(Filters.eq("username", name))
|
.count()
|
||||||
.count()
|
> 0;
|
||||||
> 0;
|
}
|
||||||
}
|
|
||||||
|
public static boolean checkIfAccountExists(int reservedUid) {
|
||||||
public static boolean checkIfAccountExists(int reservedUid) {
|
return DatabaseManager.getAccountDatastore()
|
||||||
return DatabaseManager.getAccountDatastore()
|
.find(Account.class)
|
||||||
.find(Account.class)
|
.filter(Filters.eq("reservedPlayerId", reservedUid))
|
||||||
.filter(Filters.eq("reservedPlayerId", reservedUid))
|
.count()
|
||||||
.count()
|
> 0;
|
||||||
> 0;
|
}
|
||||||
}
|
|
||||||
|
public static synchronized void deleteAccount(Account target) {
|
||||||
public static synchronized void deleteAccount(Account target) {
|
// To delete an account, we need to also delete all the other documents in the database that
|
||||||
// To delete an account, we need to also delete all the other documents in the database that
|
// reference the account.
|
||||||
// reference the account.
|
// This should optimally be wrapped inside a transaction, to make sure an error thrown mid-way
|
||||||
// This should optimally be wrapped inside a transaction, to make sure an error thrown mid-way
|
// does not leave the
|
||||||
// does not leave the
|
// database in an inconsistent state, but unfortunately Mongo only supports that when we have a
|
||||||
// database in an inconsistent state, but unfortunately Mongo only supports that when we have a
|
// replica set ...
|
||||||
// replica set ...
|
|
||||||
|
Player player = Grasscutter.getGameServer().getPlayerByAccountId(target.getId());
|
||||||
Player player = Grasscutter.getGameServer().getPlayerByAccountId(target.getId());
|
|
||||||
|
// Close session first
|
||||||
// Close session first
|
if (player != null) {
|
||||||
if (player != null) {
|
player.getSession().close();
|
||||||
player.getSession().close();
|
} else {
|
||||||
} else {
|
player = getPlayerByAccount(target);
|
||||||
player = getPlayerByAccount(target);
|
if (player == null) return;
|
||||||
if (player == null) return;
|
}
|
||||||
}
|
int uid = player.getUid();
|
||||||
int uid = player.getUid();
|
// Delete data from collections
|
||||||
// Delete data from collections
|
DatabaseManager.getGameDatabase().getCollection("achievements").deleteMany(eq("uid", uid));
|
||||||
DatabaseManager.getGameDatabase().getCollection("achievements").deleteMany(eq("uid", uid));
|
DatabaseManager.getGameDatabase().getCollection("activities").deleteMany(eq("uid", uid));
|
||||||
DatabaseManager.getGameDatabase().getCollection("activities").deleteMany(eq("uid", uid));
|
DatabaseManager.getGameDatabase().getCollection("homes").deleteMany(eq("ownerUid", uid));
|
||||||
DatabaseManager.getGameDatabase().getCollection("homes").deleteMany(eq("ownerUid", uid));
|
DatabaseManager.getGameDatabase().getCollection("mail").deleteMany(eq("ownerUid", uid));
|
||||||
DatabaseManager.getGameDatabase().getCollection("mail").deleteMany(eq("ownerUid", uid));
|
DatabaseManager.getGameDatabase().getCollection("avatars").deleteMany(eq("ownerId", uid));
|
||||||
DatabaseManager.getGameDatabase().getCollection("avatars").deleteMany(eq("ownerId", uid));
|
DatabaseManager.getGameDatabase().getCollection("gachas").deleteMany(eq("ownerId", uid));
|
||||||
DatabaseManager.getGameDatabase().getCollection("gachas").deleteMany(eq("ownerId", uid));
|
DatabaseManager.getGameDatabase().getCollection("items").deleteMany(eq("ownerId", uid));
|
||||||
DatabaseManager.getGameDatabase().getCollection("items").deleteMany(eq("ownerId", uid));
|
DatabaseManager.getGameDatabase().getCollection("quests").deleteMany(eq("ownerUid", uid));
|
||||||
DatabaseManager.getGameDatabase().getCollection("quests").deleteMany(eq("ownerUid", uid));
|
DatabaseManager.getGameDatabase().getCollection("battlepass").deleteMany(eq("ownerUid", uid));
|
||||||
DatabaseManager.getGameDatabase().getCollection("battlepass").deleteMany(eq("ownerUid", uid));
|
|
||||||
|
// Delete friendships.
|
||||||
// Delete friendships.
|
// Here, we need to make sure to not only delete the deleted account's friendships,
|
||||||
// Here, we need to make sure to not only delete the deleted account's friendships,
|
// but also all friendship entries for that account's friends.
|
||||||
// but also all friendship entries for that account's friends.
|
DatabaseManager.getGameDatabase().getCollection("friendships").deleteMany(eq("ownerId", uid));
|
||||||
DatabaseManager.getGameDatabase().getCollection("friendships").deleteMany(eq("ownerId", uid));
|
DatabaseManager.getGameDatabase().getCollection("friendships").deleteMany(eq("friendId", uid));
|
||||||
DatabaseManager.getGameDatabase().getCollection("friendships").deleteMany(eq("friendId", uid));
|
|
||||||
|
// Delete the player last.
|
||||||
// Delete the player last.
|
DatabaseManager.getGameDatastore().find(Player.class).filter(Filters.eq("id", uid)).delete();
|
||||||
DatabaseManager.getGameDatastore().find(Player.class).filter(Filters.eq("id", uid)).delete();
|
|
||||||
|
// Finally, delete the account itself.
|
||||||
// Finally, delete the account itself.
|
DatabaseManager.getAccountDatastore()
|
||||||
DatabaseManager.getAccountDatastore()
|
.find(Account.class)
|
||||||
.find(Account.class)
|
.filter(Filters.eq("id", target.getId()))
|
||||||
.filter(Filters.eq("id", target.getId()))
|
.delete();
|
||||||
.delete();
|
}
|
||||||
}
|
|
||||||
|
public static <T> Stream<T> getByGameClass(Class<T> classType) {
|
||||||
public static <T> Stream<T> getByGameClass(Class<T> classType) {
|
return DatabaseManager.getGameDatastore().find(classType).stream();
|
||||||
return DatabaseManager.getGameDatastore().find(classType).stream();
|
}
|
||||||
}
|
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
@Deprecated(forRemoval = true)
|
public static List<Player> getAllPlayers() {
|
||||||
public static List<Player> getAllPlayers() {
|
return DatabaseManager.getGameDatastore().find(Player.class).stream().toList();
|
||||||
return DatabaseManager.getGameDatastore().find(Player.class).stream().toList();
|
}
|
||||||
}
|
|
||||||
|
public static Player getPlayerByUid(int id) {
|
||||||
public static Player getPlayerByUid(int id) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore()
|
.find(Player.class)
|
||||||
.find(Player.class)
|
.filter(Filters.eq("_id", id))
|
||||||
.filter(Filters.eq("_id", id))
|
.first();
|
||||||
.first();
|
}
|
||||||
}
|
|
||||||
|
@Deprecated
|
||||||
@Deprecated
|
public static Player getPlayerByAccount(Account account) {
|
||||||
public static Player getPlayerByAccount(Account account) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore()
|
.find(Player.class)
|
||||||
.find(Player.class)
|
.filter(Filters.eq("accountId", account.getId()))
|
||||||
.filter(Filters.eq("accountId", account.getId()))
|
.first();
|
||||||
.first();
|
}
|
||||||
}
|
|
||||||
|
public static Player getPlayerByAccount(Account account, Class<? extends Player> playerClass) {
|
||||||
public static Player getPlayerByAccount(Account account, Class<? extends Player> playerClass) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore()
|
.find(playerClass)
|
||||||
.find(playerClass)
|
.filter(Filters.eq("accountId", account.getId()))
|
||||||
.filter(Filters.eq("accountId", account.getId()))
|
.first();
|
||||||
.first();
|
}
|
||||||
}
|
|
||||||
|
public static boolean checkIfPlayerExists(int uid) {
|
||||||
public static boolean checkIfPlayerExists(int uid) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore()
|
.find(Player.class)
|
||||||
.find(Player.class)
|
.filter(Filters.eq("_id", uid))
|
||||||
.filter(Filters.eq("_id", uid))
|
.count()
|
||||||
.count()
|
> 0;
|
||||||
> 0;
|
}
|
||||||
}
|
|
||||||
|
public static synchronized Player generatePlayerUid(Player character, int reservedId) {
|
||||||
public static synchronized Player generatePlayerUid(Player character, int reservedId) {
|
// Check if reserved id
|
||||||
// Check if reserved id
|
int id;
|
||||||
int id;
|
if (reservedId > 0 && !checkIfPlayerExists(reservedId)) {
|
||||||
if (reservedId > 0 && !checkIfPlayerExists(reservedId)) {
|
id = reservedId;
|
||||||
id = reservedId;
|
character.setUid(id);
|
||||||
character.setUid(id);
|
} else {
|
||||||
} else {
|
do {
|
||||||
do {
|
id = DatabaseManager.getNextId(character);
|
||||||
id = DatabaseManager.getNextId(character);
|
} while (checkIfPlayerExists(id));
|
||||||
} while (checkIfPlayerExists(id));
|
character.setUid(id);
|
||||||
character.setUid(id);
|
}
|
||||||
}
|
// Save to database
|
||||||
// Save to database
|
DatabaseManager.getGameDatastore().save(character);
|
||||||
DatabaseManager.getGameDatastore().save(character);
|
return character;
|
||||||
return character;
|
}
|
||||||
}
|
|
||||||
|
public static synchronized int getNextPlayerId(int reservedId) {
|
||||||
public static synchronized int getNextPlayerId(int reservedId) {
|
// Check if reserved id
|
||||||
// Check if reserved id
|
int id;
|
||||||
int id;
|
if (reservedId > 0 && !checkIfPlayerExists(reservedId)) {
|
||||||
if (reservedId > 0 && !checkIfPlayerExists(reservedId)) {
|
id = reservedId;
|
||||||
id = reservedId;
|
} else {
|
||||||
} else {
|
do {
|
||||||
do {
|
id = DatabaseManager.getNextId(Player.class);
|
||||||
id = DatabaseManager.getNextId(Player.class);
|
} while (checkIfPlayerExists(id));
|
||||||
} while (checkIfPlayerExists(id));
|
}
|
||||||
}
|
return id;
|
||||||
return id;
|
}
|
||||||
}
|
|
||||||
|
public static void savePlayer(Player character) {
|
||||||
public static void savePlayer(Player character) {
|
DatabaseManager.getGameDatastore().save(character);
|
||||||
DatabaseManager.getGameDatastore().save(character);
|
}
|
||||||
}
|
|
||||||
|
public static void saveAvatar(Avatar avatar) {
|
||||||
public static void saveAvatar(Avatar avatar) {
|
DatabaseManager.getGameDatastore().save(avatar);
|
||||||
DatabaseManager.getGameDatastore().save(avatar);
|
}
|
||||||
}
|
|
||||||
|
public static List<Avatar> getAvatars(Player player) {
|
||||||
public static List<Avatar> getAvatars(Player player) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore()
|
.find(Avatar.class)
|
||||||
.find(Avatar.class)
|
.filter(Filters.eq("ownerId", player.getUid()))
|
||||||
.filter(Filters.eq("ownerId", player.getUid()))
|
.stream()
|
||||||
.stream()
|
.toList();
|
||||||
.toList();
|
}
|
||||||
}
|
|
||||||
|
public static void saveItem(GameItem item) {
|
||||||
public static void saveItem(GameItem item) {
|
DatabaseManager.getGameDatastore().save(item);
|
||||||
DatabaseManager.getGameDatastore().save(item);
|
}
|
||||||
}
|
|
||||||
|
public static boolean deleteItem(GameItem item) {
|
||||||
public static boolean deleteItem(GameItem item) {
|
DeleteResult result = DatabaseManager.getGameDatastore().delete(item);
|
||||||
DeleteResult result = DatabaseManager.getGameDatastore().delete(item);
|
return result.wasAcknowledged();
|
||||||
return result.wasAcknowledged();
|
}
|
||||||
}
|
|
||||||
|
public static List<GameItem> getInventoryItems(Player player) {
|
||||||
public static List<GameItem> getInventoryItems(Player player) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore()
|
.find(GameItem.class)
|
||||||
.find(GameItem.class)
|
.filter(Filters.eq("ownerId", player.getUid()))
|
||||||
.filter(Filters.eq("ownerId", player.getUid()))
|
.stream()
|
||||||
.stream()
|
.toList();
|
||||||
.toList();
|
}
|
||||||
}
|
|
||||||
|
public static List<Friendship> getFriends(Player player) {
|
||||||
public static List<Friendship> getFriends(Player player) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore()
|
.find(Friendship.class)
|
||||||
.find(Friendship.class)
|
.filter(Filters.eq("ownerId", player.getUid()))
|
||||||
.filter(Filters.eq("ownerId", player.getUid()))
|
.stream()
|
||||||
.stream()
|
.toList();
|
||||||
.toList();
|
}
|
||||||
}
|
|
||||||
|
public static List<Friendship> getReverseFriends(Player player) {
|
||||||
public static List<Friendship> getReverseFriends(Player player) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore()
|
.find(Friendship.class)
|
||||||
.find(Friendship.class)
|
.filter(Filters.eq("friendId", player.getUid()))
|
||||||
.filter(Filters.eq("friendId", player.getUid()))
|
.stream()
|
||||||
.stream()
|
.toList();
|
||||||
.toList();
|
}
|
||||||
}
|
|
||||||
|
public static void saveFriendship(Friendship friendship) {
|
||||||
public static void saveFriendship(Friendship friendship) {
|
DatabaseManager.getGameDatastore().save(friendship);
|
||||||
DatabaseManager.getGameDatastore().save(friendship);
|
}
|
||||||
}
|
|
||||||
|
public static void deleteFriendship(Friendship friendship) {
|
||||||
public static void deleteFriendship(Friendship friendship) {
|
DatabaseManager.getGameDatastore().delete(friendship);
|
||||||
DatabaseManager.getGameDatastore().delete(friendship);
|
}
|
||||||
}
|
|
||||||
|
public static Friendship getReverseFriendship(Friendship friendship) {
|
||||||
public static Friendship getReverseFriendship(Friendship friendship) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore()
|
.find(Friendship.class)
|
||||||
.find(Friendship.class)
|
.filter(
|
||||||
.filter(
|
Filters.and(
|
||||||
Filters.and(
|
Filters.eq("ownerId", friendship.getFriendId()),
|
||||||
Filters.eq("ownerId", friendship.getFriendId()),
|
Filters.eq("friendId", friendship.getOwnerId())))
|
||||||
Filters.eq("friendId", friendship.getOwnerId())))
|
.first();
|
||||||
.first();
|
}
|
||||||
}
|
|
||||||
|
public static List<GachaRecord> getGachaRecords(int ownerId, int page, int gachaType) {
|
||||||
public static List<GachaRecord> getGachaRecords(int ownerId, int page, int gachaType) {
|
return getGachaRecords(ownerId, page, gachaType, 10);
|
||||||
return getGachaRecords(ownerId, page, gachaType, 10);
|
}
|
||||||
}
|
|
||||||
|
public static List<GachaRecord> getGachaRecords(
|
||||||
public static List<GachaRecord> getGachaRecords(
|
int ownerId, int page, int gachaType, int pageSize) {
|
||||||
int ownerId, int page, int gachaType, int pageSize) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore()
|
.find(GachaRecord.class)
|
||||||
.find(GachaRecord.class)
|
.filter(Filters.eq("ownerId", ownerId), Filters.eq("gachaType", gachaType))
|
||||||
.filter(Filters.eq("ownerId", ownerId), Filters.eq("gachaType", gachaType))
|
.iterator(
|
||||||
.iterator(
|
new FindOptions()
|
||||||
new FindOptions()
|
.sort(Sort.descending("transactionDate"))
|
||||||
.sort(Sort.descending("transactionDate"))
|
.skip(pageSize * page)
|
||||||
.skip(pageSize * page)
|
.limit(pageSize))
|
||||||
.limit(pageSize))
|
.toList();
|
||||||
.toList();
|
}
|
||||||
}
|
|
||||||
|
public static long getGachaRecordsMaxPage(int ownerId, int page, int gachaType) {
|
||||||
public static long getGachaRecordsMaxPage(int ownerId, int page, int gachaType) {
|
return getGachaRecordsMaxPage(ownerId, page, gachaType, 10);
|
||||||
return getGachaRecordsMaxPage(ownerId, page, gachaType, 10);
|
}
|
||||||
}
|
|
||||||
|
public static long getGachaRecordsMaxPage(int ownerId, int page, int gachaType, int pageSize) {
|
||||||
public static long getGachaRecordsMaxPage(int ownerId, int page, int gachaType, int pageSize) {
|
long count =
|
||||||
long count =
|
DatabaseManager.getGameDatastore()
|
||||||
DatabaseManager.getGameDatastore()
|
.find(GachaRecord.class)
|
||||||
.find(GachaRecord.class)
|
.filter(Filters.eq("ownerId", ownerId), Filters.eq("gachaType", gachaType))
|
||||||
.filter(Filters.eq("ownerId", ownerId), Filters.eq("gachaType", gachaType))
|
.count();
|
||||||
.count();
|
return count / 10 + (count % 10 > 0 ? 1 : 0);
|
||||||
return count / 10 + (count % 10 > 0 ? 1 : 0);
|
}
|
||||||
}
|
|
||||||
|
public static void saveGachaRecord(GachaRecord gachaRecord) {
|
||||||
public static void saveGachaRecord(GachaRecord gachaRecord) {
|
DatabaseManager.getGameDatastore().save(gachaRecord);
|
||||||
DatabaseManager.getGameDatastore().save(gachaRecord);
|
}
|
||||||
}
|
|
||||||
|
public static List<Mail> getAllMail(Player player) {
|
||||||
public static List<Mail> getAllMail(Player player) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore()
|
.find(Mail.class)
|
||||||
.find(Mail.class)
|
.filter(Filters.eq("ownerUid", player.getUid()))
|
||||||
.filter(Filters.eq("ownerUid", player.getUid()))
|
.stream()
|
||||||
.stream()
|
.toList();
|
||||||
.toList();
|
}
|
||||||
}
|
|
||||||
|
public static void saveMail(Mail mail) {
|
||||||
public static void saveMail(Mail mail) {
|
DatabaseManager.getGameDatastore().save(mail);
|
||||||
DatabaseManager.getGameDatastore().save(mail);
|
}
|
||||||
}
|
|
||||||
|
public static boolean deleteMail(Mail mail) {
|
||||||
public static boolean deleteMail(Mail mail) {
|
DeleteResult result = DatabaseManager.getGameDatastore().delete(mail);
|
||||||
DeleteResult result = DatabaseManager.getGameDatastore().delete(mail);
|
return result.wasAcknowledged();
|
||||||
return result.wasAcknowledged();
|
}
|
||||||
}
|
|
||||||
|
public static List<GameMainQuest> getAllQuests(Player player) {
|
||||||
public static List<GameMainQuest> getAllQuests(Player player) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore()
|
.find(GameMainQuest.class)
|
||||||
.find(GameMainQuest.class)
|
.filter(Filters.eq("ownerUid", player.getUid()))
|
||||||
.filter(Filters.eq("ownerUid", player.getUid()))
|
.stream()
|
||||||
.stream()
|
.toList();
|
||||||
.toList();
|
}
|
||||||
}
|
|
||||||
|
public static void saveQuest(GameMainQuest quest) {
|
||||||
public static void saveQuest(GameMainQuest quest) {
|
DatabaseManager.getGameDatastore().save(quest);
|
||||||
DatabaseManager.getGameDatastore().save(quest);
|
}
|
||||||
}
|
|
||||||
|
public static boolean deleteQuest(GameMainQuest quest) {
|
||||||
public static boolean deleteQuest(GameMainQuest quest) {
|
return DatabaseManager.getGameDatastore().delete(quest).wasAcknowledged();
|
||||||
return DatabaseManager.getGameDatastore().delete(quest).wasAcknowledged();
|
}
|
||||||
}
|
|
||||||
|
public static GameHome getHomeByUid(int id) {
|
||||||
public static GameHome getHomeByUid(int id) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore()
|
.find(GameHome.class)
|
||||||
.find(GameHome.class)
|
.filter(Filters.eq("ownerUid", id))
|
||||||
.filter(Filters.eq("ownerUid", id))
|
.first();
|
||||||
.first();
|
}
|
||||||
}
|
|
||||||
|
public static void saveHome(GameHome gameHome) {
|
||||||
public static void saveHome(GameHome gameHome) {
|
DatabaseManager.getGameDatastore().save(gameHome);
|
||||||
DatabaseManager.getGameDatastore().save(gameHome);
|
}
|
||||||
}
|
|
||||||
|
public static BattlePassManager loadBattlePass(Player player) {
|
||||||
public static BattlePassManager loadBattlePass(Player player) {
|
BattlePassManager manager =
|
||||||
BattlePassManager manager =
|
DatabaseManager.getGameDatastore()
|
||||||
DatabaseManager.getGameDatastore()
|
.find(BattlePassManager.class)
|
||||||
.find(BattlePassManager.class)
|
.filter(Filters.eq("ownerUid", player.getUid()))
|
||||||
.filter(Filters.eq("ownerUid", player.getUid()))
|
.first();
|
||||||
.first();
|
if (manager == null) {
|
||||||
if (manager == null) {
|
manager = new BattlePassManager(player);
|
||||||
manager = new BattlePassManager(player);
|
manager.save();
|
||||||
manager.save();
|
} else {
|
||||||
} else {
|
manager.setPlayer(player);
|
||||||
manager.setPlayer(player);
|
}
|
||||||
}
|
return manager;
|
||||||
return manager;
|
}
|
||||||
}
|
|
||||||
|
public static void saveBattlePass(BattlePassManager manager) {
|
||||||
public static void saveBattlePass(BattlePassManager manager) {
|
DatabaseManager.getGameDatastore().save(manager);
|
||||||
DatabaseManager.getGameDatastore().save(manager);
|
}
|
||||||
}
|
|
||||||
|
public static PlayerActivityData getPlayerActivityData(int uid, int activityId) {
|
||||||
public static PlayerActivityData getPlayerActivityData(int uid, int activityId) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore()
|
.find(PlayerActivityData.class)
|
||||||
.find(PlayerActivityData.class)
|
.filter(Filters.and(Filters.eq("uid", uid), Filters.eq("activityId", activityId)))
|
||||||
.filter(Filters.and(Filters.eq("uid", uid), Filters.eq("activityId", activityId)))
|
.first();
|
||||||
.first();
|
}
|
||||||
}
|
|
||||||
|
public static void savePlayerActivityData(PlayerActivityData playerActivityData) {
|
||||||
public static void savePlayerActivityData(PlayerActivityData playerActivityData) {
|
DatabaseManager.getGameDatastore().save(playerActivityData);
|
||||||
DatabaseManager.getGameDatastore().save(playerActivityData);
|
}
|
||||||
}
|
|
||||||
|
public static MusicGameBeatmap getMusicGameBeatmap(long musicShareId) {
|
||||||
public static MusicGameBeatmap getMusicGameBeatmap(long musicShareId) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore()
|
.find(MusicGameBeatmap.class)
|
||||||
.find(MusicGameBeatmap.class)
|
.filter(Filters.eq("musicShareId", musicShareId))
|
||||||
.filter(Filters.eq("musicShareId", musicShareId))
|
.first();
|
||||||
.first();
|
}
|
||||||
}
|
|
||||||
|
public static void saveMusicGameBeatmap(MusicGameBeatmap musicGameBeatmap) {
|
||||||
public static void saveMusicGameBeatmap(MusicGameBeatmap musicGameBeatmap) {
|
DatabaseManager.getGameDatastore().save(musicGameBeatmap);
|
||||||
DatabaseManager.getGameDatastore().save(musicGameBeatmap);
|
}
|
||||||
}
|
|
||||||
|
public static Achievements getAchievementData(int uid) {
|
||||||
public static Achievements getAchievementData(int uid) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore()
|
.find(Achievements.class)
|
||||||
.find(Achievements.class)
|
.filter(Filters.and(Filters.eq("uid", uid)))
|
||||||
.filter(Filters.and(Filters.eq("uid", uid)))
|
.first();
|
||||||
.first();
|
}
|
||||||
}
|
|
||||||
|
public static void saveAchievementData(Achievements achievements) {
|
||||||
public static void saveAchievementData(Achievements achievements) {
|
DatabaseManager.getGameDatastore().save(achievements);
|
||||||
DatabaseManager.getGameDatastore().save(achievements);
|
}
|
||||||
}
|
|
||||||
|
public static void saveGroupInstance(SceneGroupInstance instance) {
|
||||||
public static void saveGroupInstance(SceneGroupInstance instance) {
|
DatabaseManager.getGameDatastore().save(instance);
|
||||||
DatabaseManager.getGameDatastore().save(instance);
|
}
|
||||||
}
|
|
||||||
|
public static SceneGroupInstance loadGroupInstance(int groupId, Player owner) {
|
||||||
public static SceneGroupInstance loadGroupInstance(int groupId, Player owner) {
|
return DatabaseManager.getGameDatastore()
|
||||||
return DatabaseManager.getGameDatastore().find(SceneGroupInstance.class)
|
.find(SceneGroupInstance.class)
|
||||||
.filter(Filters.and(Filters.eq("ownerUid", owner.getUid()),
|
.filter(Filters.and(Filters.eq("ownerUid", owner.getUid()), Filters.eq("groupId", groupId)))
|
||||||
Filters.eq("groupId", groupId))).first();
|
.first();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,134 +1,134 @@
|
|||||||
package emu.grasscutter.game.activity;
|
package emu.grasscutter.game.activity;
|
||||||
|
|
||||||
import dev.morphia.annotations.Entity;
|
import dev.morphia.annotations.Entity;
|
||||||
import dev.morphia.annotations.Id;
|
import dev.morphia.annotations.Id;
|
||||||
import dev.morphia.annotations.Transient;
|
import dev.morphia.annotations.Transient;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.common.ItemParamData;
|
import emu.grasscutter.data.common.ItemParamData;
|
||||||
import emu.grasscutter.data.excels.activity.ActivityWatcherData;
|
import emu.grasscutter.data.excels.activity.ActivityWatcherData;
|
||||||
import emu.grasscutter.database.DatabaseHelper;
|
import emu.grasscutter.database.DatabaseHelper;
|
||||||
import emu.grasscutter.game.inventory.GameItem;
|
import emu.grasscutter.game.inventory.GameItem;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.ActionReason;
|
import emu.grasscutter.game.props.ActionReason;
|
||||||
import emu.grasscutter.net.proto.ActivityWatcherInfoOuterClass;
|
import emu.grasscutter.net.proto.ActivityWatcherInfoOuterClass;
|
||||||
import emu.grasscutter.server.packet.send.PacketActivityUpdateWatcherNotify;
|
import emu.grasscutter.server.packet.send.PacketActivityUpdateWatcherNotify;
|
||||||
import emu.grasscutter.utils.JsonUtils;
|
import emu.grasscutter.utils.JsonUtils;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.experimental.FieldDefaults;
|
import lombok.experimental.FieldDefaults;
|
||||||
|
|
||||||
@Entity("activities")
|
@Entity("activities")
|
||||||
@Data
|
@Data
|
||||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||||
@Builder(builderMethodName = "of")
|
@Builder(builderMethodName = "of")
|
||||||
public class PlayerActivityData {
|
public class PlayerActivityData {
|
||||||
@Id String id;
|
@Id String id;
|
||||||
int uid;
|
int uid;
|
||||||
int activityId;
|
int activityId;
|
||||||
Map<Integer, WatcherInfo> watcherInfoMap;
|
Map<Integer, WatcherInfo> watcherInfoMap;
|
||||||
/** the detail data of each type of activity (Json format) */
|
/** the detail data of each type of activity (Json format) */
|
||||||
String detail;
|
String detail;
|
||||||
|
|
||||||
@Transient Player player;
|
@Transient Player player;
|
||||||
@Transient ActivityHandler activityHandler;
|
@Transient ActivityHandler activityHandler;
|
||||||
|
|
||||||
public static PlayerActivityData getByPlayer(Player player, int activityId) {
|
public static PlayerActivityData getByPlayer(Player player, int activityId) {
|
||||||
return DatabaseHelper.getPlayerActivityData(player.getUid(), activityId);
|
return DatabaseHelper.getPlayerActivityData(player.getUid(), activityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save() {
|
public void save() {
|
||||||
DatabaseHelper.savePlayerActivityData(this);
|
DatabaseHelper.savePlayerActivityData(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void addWatcherProgress(int watcherId) {
|
public synchronized void addWatcherProgress(int watcherId) {
|
||||||
var watcherInfo = watcherInfoMap.get(watcherId);
|
var watcherInfo = watcherInfoMap.get(watcherId);
|
||||||
if (watcherInfo == null) {
|
if (watcherInfo == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (watcherInfo.curProgress >= watcherInfo.totalProgress) {
|
if (watcherInfo.curProgress >= watcherInfo.totalProgress) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
watcherInfo.curProgress++;
|
watcherInfo.curProgress++;
|
||||||
getPlayer().sendPacket(new PacketActivityUpdateWatcherNotify(activityId, watcherInfo));
|
getPlayer().sendPacket(new PacketActivityUpdateWatcherNotify(activityId, watcherInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ActivityWatcherInfoOuterClass.ActivityWatcherInfo> getAllWatcherInfoList() {
|
public List<ActivityWatcherInfoOuterClass.ActivityWatcherInfo> getAllWatcherInfoList() {
|
||||||
return watcherInfoMap.values().stream().map(WatcherInfo::toProto).toList();
|
return watcherInfoMap.values().stream().map(WatcherInfo::toProto).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDetail(Object detail) {
|
public void setDetail(Object detail) {
|
||||||
this.detail = JsonUtils.encode(detail);
|
this.detail = JsonUtils.encode(detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void takeWatcherReward(int watcherId) {
|
public void takeWatcherReward(int watcherId) {
|
||||||
var watcher = watcherInfoMap.get(watcherId);
|
var watcher = watcherInfoMap.get(watcherId);
|
||||||
if (watcher == null || watcher.isTakenReward()) {
|
if (watcher == null || watcher.isTakenReward()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var reward =
|
var reward =
|
||||||
Optional.of(watcher)
|
Optional.of(watcher)
|
||||||
.map(WatcherInfo::getMetadata)
|
.map(WatcherInfo::getMetadata)
|
||||||
.map(ActivityWatcherData::getRewardID)
|
.map(ActivityWatcherData::getRewardID)
|
||||||
.map(id -> GameData.getRewardDataMap().get(id.intValue()));
|
.map(id -> GameData.getRewardDataMap().get(id.intValue()));
|
||||||
|
|
||||||
if (reward.isEmpty()) {
|
if (reward.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<GameItem> rewards = new ArrayList<>();
|
List<GameItem> rewards = new ArrayList<>();
|
||||||
for (ItemParamData param : reward.get().getRewardItemList()) {
|
for (ItemParamData param : reward.get().getRewardItemList()) {
|
||||||
rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1)));
|
rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
player.getInventory().addItems(rewards, ActionReason.ActivityWatcher);
|
player.getInventory().addItems(rewards, ActionReason.ActivityWatcher);
|
||||||
watcher.setTakenReward(true);
|
watcher.setTakenReward(true);
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Data
|
@Data
|
||||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||||
@Builder(builderMethodName = "of")
|
@Builder(builderMethodName = "of")
|
||||||
public static class WatcherInfo {
|
public static class WatcherInfo {
|
||||||
int watcherId;
|
int watcherId;
|
||||||
int totalProgress;
|
int totalProgress;
|
||||||
int curProgress;
|
int curProgress;
|
||||||
boolean isTakenReward;
|
boolean isTakenReward;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return True when the progress of this watcher has reached the total progress.
|
* @return True when the progress of this watcher has reached the total progress.
|
||||||
*/
|
*/
|
||||||
public boolean isFinished(){
|
public boolean isFinished() {
|
||||||
return this.curProgress >= this.totalProgress;
|
return this.curProgress >= this.totalProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WatcherInfo init(ActivityWatcher watcher) {
|
public static WatcherInfo init(ActivityWatcher watcher) {
|
||||||
return WatcherInfo.of()
|
return WatcherInfo.of()
|
||||||
.watcherId(watcher.getWatcherId())
|
.watcherId(watcher.getWatcherId())
|
||||||
.totalProgress(watcher.getActivityWatcherData().getProgress())
|
.totalProgress(watcher.getActivityWatcherData().getProgress())
|
||||||
.isTakenReward(false)
|
.isTakenReward(false)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActivityWatcherData getMetadata() {
|
public ActivityWatcherData getMetadata() {
|
||||||
return GameData.getActivityWatcherDataMap().get(watcherId);
|
return GameData.getActivityWatcherDataMap().get(watcherId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActivityWatcherInfoOuterClass.ActivityWatcherInfo toProto() {
|
public ActivityWatcherInfoOuterClass.ActivityWatcherInfo toProto() {
|
||||||
return ActivityWatcherInfoOuterClass.ActivityWatcherInfo.newBuilder()
|
return ActivityWatcherInfoOuterClass.ActivityWatcherInfo.newBuilder()
|
||||||
.setWatcherId(watcherId)
|
.setWatcherId(watcherId)
|
||||||
.setCurProgress(curProgress)
|
.setCurProgress(curProgress)
|
||||||
.setTotalProgress(totalProgress)
|
.setTotalProgress(totalProgress)
|
||||||
.setIsTakenReward(isTakenReward)
|
.setIsTakenReward(isTakenReward)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,18 +1,19 @@
|
|||||||
package emu.grasscutter.game.dungeons;
|
package emu.grasscutter.game.dungeons;
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
|
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
|
||||||
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
|
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
|
||||||
|
|
||||||
public class BasicDungeonSettleListener implements DungeonSettleListener {
|
public class BasicDungeonSettleListener implements DungeonSettleListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDungeonSettle(DungeonManager dungeonManager, BaseDungeonResult.DungeonEndReason endReason) {
|
public void onDungeonSettle(
|
||||||
var scene = dungeonManager.getScene();
|
DungeonManager dungeonManager, BaseDungeonResult.DungeonEndReason endReason) {
|
||||||
var dungeonData = dungeonManager.getDungeonData();
|
var scene = dungeonManager.getScene();
|
||||||
var time = scene.getSceneTimeSeconds() - dungeonManager.getStartSceneTime() ;
|
var dungeonData = dungeonManager.getDungeonData();
|
||||||
// TODO time taken and chests handling
|
var time = scene.getSceneTimeSeconds() - dungeonManager.getStartSceneTime();
|
||||||
DungeonEndStats stats = new DungeonEndStats(scene.getKilledMonsterCount(), time, 0, endReason);
|
// TODO time taken and chests handling
|
||||||
|
DungeonEndStats stats = new DungeonEndStats(scene.getKilledMonsterCount(), time, 0, endReason);
|
||||||
scene.broadcastPacket(new PacketDungeonSettleNotify(new BaseDungeonResult(dungeonData, stats)));
|
|
||||||
}
|
scene.broadcastPacket(new PacketDungeonSettleNotify(new BaseDungeonResult(dungeonData, stats)));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -1,314 +1,331 @@
|
|||||||
package emu.grasscutter.game.dungeons;
|
package emu.grasscutter.game.dungeons;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.common.ItemParamData;
|
import emu.grasscutter.data.common.ItemParamData;
|
||||||
import emu.grasscutter.data.excels.dungeon.DungeonData;
|
import emu.grasscutter.data.excels.dungeon.DungeonData;
|
||||||
import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData;
|
import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData;
|
||||||
import emu.grasscutter.game.activity.trialavatar.TrialAvatarActivityHandler;
|
import emu.grasscutter.game.activity.trialavatar.TrialAvatarActivityHandler;
|
||||||
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
|
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
|
||||||
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
|
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
|
||||||
import emu.grasscutter.game.inventory.GameItem;
|
import emu.grasscutter.game.inventory.GameItem;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.ActionReason;
|
import emu.grasscutter.game.props.ActionReason;
|
||||||
import emu.grasscutter.game.props.ActivityType;
|
import emu.grasscutter.game.props.ActivityType;
|
||||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||||
import emu.grasscutter.game.quest.enums.LogicType;
|
import emu.grasscutter.game.quest.enums.LogicType;
|
||||||
import emu.grasscutter.game.quest.enums.QuestContent;
|
import emu.grasscutter.game.quest.enums.QuestContent;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.constants.EventType;
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||||
import emu.grasscutter.server.packet.send.PacketDungeonWayPointNotify;
|
import emu.grasscutter.server.packet.send.PacketDungeonWayPointNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify;
|
import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
import lombok.Getter;
|
import java.util.*;
|
||||||
import lombok.NonNull;
|
import java.util.stream.Collectors;
|
||||||
import lombok.val;
|
import java.util.stream.IntStream;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.Nullable;
|
import lombok.Getter;
|
||||||
import java.util.*;
|
import lombok.NonNull;
|
||||||
import java.util.stream.Collectors;
|
import lombok.val;
|
||||||
import java.util.stream.IntStream;
|
|
||||||
|
/**
|
||||||
/**
|
* TODO handle time limits TODO handle respawn points TODO handle team wipes and respawns TODO check
|
||||||
* TODO handle time limits
|
* monster level and levelConfigMap
|
||||||
* TODO handle respawn points
|
*/
|
||||||
* TODO handle team wipes and respawns
|
public final class DungeonManager {
|
||||||
* TODO check monster level and levelConfigMap
|
@Getter private final Scene scene;
|
||||||
*/
|
@Getter private final DungeonData dungeonData;
|
||||||
public final class DungeonManager {
|
@Getter private final DungeonPassConfigData passConfigData;
|
||||||
@Getter private final Scene scene;
|
|
||||||
@Getter private final DungeonData dungeonData;
|
@Getter private final int[] finishedConditions;
|
||||||
@Getter private final DungeonPassConfigData passConfigData;
|
private final IntSet rewardedPlayers = new IntOpenHashSet();
|
||||||
|
private final Set<Integer> activeDungeonWayPoints = new HashSet<>();
|
||||||
@Getter private final int[] finishedConditions;
|
private boolean ended = false;
|
||||||
private final IntSet rewardedPlayers = new IntOpenHashSet();
|
private int newestWayPoint = 0;
|
||||||
private final Set<Integer> activeDungeonWayPoints = new HashSet<>();
|
@Getter private int startSceneTime = 0;
|
||||||
private boolean ended = false;
|
|
||||||
private int newestWayPoint = 0;
|
DungeonTrialTeam trialTeam = null;
|
||||||
@Getter private int startSceneTime = 0;
|
|
||||||
|
public DungeonManager(@NonNull Scene scene, @NonNull DungeonData dungeonData) {
|
||||||
DungeonTrialTeam trialTeam = null;
|
this.scene = scene;
|
||||||
|
this.dungeonData = dungeonData;
|
||||||
public DungeonManager(@NonNull Scene scene, @NonNull DungeonData dungeonData) {
|
this.passConfigData = GameData.getDungeonPassConfigDataMap().get(dungeonData.getPassCond());
|
||||||
this.scene = scene;
|
this.finishedConditions = new int[passConfigData.getConds().size()];
|
||||||
this.dungeonData = dungeonData;
|
this.scene.setDungeonManager(this);
|
||||||
this.passConfigData = GameData.getDungeonPassConfigDataMap().get(dungeonData.getPassCond());
|
}
|
||||||
this.finishedConditions = new int[passConfigData.getConds().size()];
|
|
||||||
this.scene.setDungeonManager(this);
|
public void triggerEvent(DungeonPassConditionType conditionType, int... params) {
|
||||||
}
|
if (ended) {
|
||||||
|
return;
|
||||||
public void triggerEvent(DungeonPassConditionType conditionType, int... params) {
|
}
|
||||||
if (ended) {
|
for (int i = 0; i < passConfigData.getConds().size(); i++) {
|
||||||
return;
|
var cond = passConfigData.getConds().get(i);
|
||||||
}
|
if (conditionType == cond.getCondType()) {
|
||||||
for (int i = 0; i < passConfigData.getConds().size(); i++) {
|
if (getScene().getWorld().getServer().getDungeonSystem().triggerCondition(cond, params)) {
|
||||||
var cond = passConfigData.getConds().get(i);
|
finishedConditions[i] = 1;
|
||||||
if (conditionType == cond.getCondType()) {
|
}
|
||||||
if (getScene().getWorld().getServer().getDungeonSystem().triggerCondition(cond, params)) {
|
}
|
||||||
finishedConditions[i] = 1;
|
}
|
||||||
}
|
|
||||||
|
if (isFinishedSuccessfully()) {
|
||||||
}
|
finishDungeon();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (isFinishedSuccessfully()) {
|
|
||||||
finishDungeon();
|
public boolean isFinishedSuccessfully() {
|
||||||
}
|
return LogicType.calculate(passConfigData.getLogicType(), finishedConditions);
|
||||||
|
}
|
||||||
}
|
|
||||||
|
public int getLevelForMonster(int id) {
|
||||||
public boolean isFinishedSuccessfully() {
|
// TODO should use levelConfigMap? and how?
|
||||||
return LogicType.calculate(passConfigData.getLogicType(), finishedConditions);
|
return dungeonData.getShowLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLevelForMonster(int id) {
|
public boolean activateRespawnPoint(int pointId) {
|
||||||
//TODO should use levelConfigMap? and how?
|
val respawnPoint = GameData.getScenePointEntryById(scene.getId(), pointId);
|
||||||
return dungeonData.getShowLevel();
|
|
||||||
}
|
if (respawnPoint == null) {
|
||||||
|
Grasscutter.getLogger().warn("trying to activate unknown respawn point {}", pointId);
|
||||||
public boolean activateRespawnPoint(int pointId) {
|
return false;
|
||||||
val respawnPoint = GameData.getScenePointEntryById(scene.getId(), pointId);
|
}
|
||||||
|
|
||||||
if (respawnPoint == null) {
|
scene.broadcastPacket(
|
||||||
Grasscutter.getLogger().warn("trying to activate unknown respawn point {}", pointId);
|
new PacketDungeonWayPointNotify(
|
||||||
return false;
|
activeDungeonWayPoints.add(pointId), activeDungeonWayPoints));
|
||||||
}
|
newestWayPoint = pointId;
|
||||||
|
|
||||||
scene.broadcastPacket(new PacketDungeonWayPointNotify(activeDungeonWayPoints.add(pointId), activeDungeonWayPoints));
|
Grasscutter.getLogger().debug("[unimplemented respawn] activated respawn point {}", pointId);
|
||||||
newestWayPoint = pointId;
|
return true;
|
||||||
|
}
|
||||||
Grasscutter.getLogger().debug("[unimplemented respawn] activated respawn point {}", pointId);
|
|
||||||
return true;
|
@Nullable public Position getRespawnLocation() {
|
||||||
}
|
if (newestWayPoint == 0) { // validity is checked before setting it, so if != 0 its always valid
|
||||||
|
return null;
|
||||||
@Nullable
|
}
|
||||||
public Position getRespawnLocation() {
|
var pointData = GameData.getScenePointEntryById(scene.getId(), newestWayPoint).getPointData();
|
||||||
if (newestWayPoint == 0) { // validity is checked before setting it, so if != 0 its always valid
|
return pointData.getTranPos() != null ? pointData.getTranPos() : pointData.getPos();
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
var pointData = GameData.getScenePointEntryById(scene.getId(), newestWayPoint).getPointData();
|
public Position getRespawnRotation() {
|
||||||
return pointData.getTranPos() != null ? pointData.getTranPos() : pointData.getPos();
|
if (newestWayPoint == 0) { // validity is checked before setting it, so if != 0 its always valid
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
public Position getRespawnRotation() {
|
val pointData = GameData.getScenePointEntryById(scene.getId(), newestWayPoint).getPointData();
|
||||||
if (newestWayPoint == 0) { // validity is checked before setting it, so if != 0 its always valid
|
return pointData.getRot() != null ? pointData.getRot() : null;
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
val pointData = GameData.getScenePointEntryById(scene.getId(), newestWayPoint).getPointData();
|
public boolean getStatueDrops(Player player, boolean useCondensed, int groupId) {
|
||||||
return pointData.getRot() != null ? pointData.getRot() : null;
|
if (!isFinishedSuccessfully()
|
||||||
}
|
|| dungeonData.getRewardPreviewData() == null
|
||||||
|
|| dungeonData.getRewardPreviewData().getPreviewItems().length == 0) {
|
||||||
public boolean getStatueDrops(Player player, boolean useCondensed, int groupId) {
|
return false;
|
||||||
if (!isFinishedSuccessfully() || dungeonData.getRewardPreviewData() == null || dungeonData.getRewardPreviewData().getPreviewItems().length == 0) {
|
}
|
||||||
return false;
|
|
||||||
}
|
// Already rewarded
|
||||||
|
if (rewardedPlayers.contains(player.getUid())) {
|
||||||
// Already rewarded
|
return false;
|
||||||
if (rewardedPlayers.contains(player.getUid())) {
|
}
|
||||||
return false;
|
|
||||||
}
|
if (!handleCost(player, useCondensed)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!handleCost(player, useCondensed)) {
|
|
||||||
return false;
|
// Get and roll rewards.
|
||||||
}
|
List<GameItem> rewards = new ArrayList<>(this.rollRewards(useCondensed));
|
||||||
|
// Add rewards to player and send notification.
|
||||||
// Get and roll rewards.
|
player.getInventory().addItems(rewards, ActionReason.DungeonStatueDrop);
|
||||||
List<GameItem> rewards = new ArrayList<>(this.rollRewards(useCondensed));
|
player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(rewards));
|
||||||
// Add rewards to player and send notification.
|
|
||||||
player.getInventory().addItems(rewards, ActionReason.DungeonStatueDrop);
|
rewardedPlayers.add(player.getUid());
|
||||||
player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(rewards));
|
|
||||||
|
scene.getScriptManager().callEvent(new ScriptArgs(groupId, EventType.EVENT_DUNGEON_REWARD_GET));
|
||||||
rewardedPlayers.add(player.getUid());
|
return true;
|
||||||
|
}
|
||||||
scene.getScriptManager().callEvent(new ScriptArgs(groupId, EventType.EVENT_DUNGEON_REWARD_GET));
|
|
||||||
return true;
|
public boolean handleCost(Player player, boolean useCondensed) {
|
||||||
}
|
int resinCost = dungeonData.getStatueCostCount() != 0 ? dungeonData.getStatueCostCount() : 20;
|
||||||
|
if (resinCost == 0) {
|
||||||
public boolean handleCost(Player player, boolean useCondensed) {
|
return true;
|
||||||
int resinCost = dungeonData.getStatueCostCount() != 0 ? dungeonData.getStatueCostCount() : 20;
|
}
|
||||||
if (resinCost == 0) {
|
if (useCondensed) {
|
||||||
return true;
|
// Check if condensed resin is usable here.
|
||||||
}
|
// For this, we use the following logic for now:
|
||||||
if (useCondensed) {
|
// The normal resin cost of the dungeon has to be 20.
|
||||||
// Check if condensed resin is usable here.
|
if (resinCost != 20) {
|
||||||
// For this, we use the following logic for now:
|
return false;
|
||||||
// The normal resin cost of the dungeon has to be 20.
|
}
|
||||||
if (resinCost != 20) {
|
|
||||||
return false;
|
// Spend the condensed resin and only proceed if the transaction succeeds.
|
||||||
}
|
return player.getResinManager().useCondensedResin(1);
|
||||||
|
} else if (dungeonData.getStatueCostID() == 106) {
|
||||||
// Spend the condensed resin and only proceed if the transaction succeeds.
|
// Spend the resin and only proceed if the transaction succeeds.
|
||||||
return player.getResinManager().useCondensedResin(1);
|
return player.getResinManager().useResin(resinCost);
|
||||||
} else if (dungeonData.getStatueCostID() == 106) {
|
}
|
||||||
// Spend the resin and only proceed if the transaction succeeds.
|
return true;
|
||||||
return player.getResinManager().useResin(resinCost);
|
}
|
||||||
}
|
|
||||||
return true;
|
private List<GameItem> rollRewards(boolean useCondensed) {
|
||||||
}
|
List<GameItem> rewards = new ArrayList<>();
|
||||||
|
int dungeonId = this.dungeonData.getId();
|
||||||
private List<GameItem> rollRewards(boolean useCondensed) {
|
// If we have specific drop data for this dungeon, we use it.
|
||||||
List<GameItem> rewards = new ArrayList<>();
|
if (GameData.getDungeonDropDataMap().containsKey(dungeonId)) {
|
||||||
int dungeonId = this.dungeonData.getId();
|
List<DungeonDropEntry> dropEntries = GameData.getDungeonDropDataMap().get(dungeonId);
|
||||||
// If we have specific drop data for this dungeon, we use it.
|
|
||||||
if (GameData.getDungeonDropDataMap().containsKey(dungeonId)) {
|
// Roll for each drop group.
|
||||||
List<DungeonDropEntry> dropEntries = GameData.getDungeonDropDataMap().get(dungeonId);
|
for (var entry : dropEntries) {
|
||||||
|
// Determine the number of drops we get for this entry.
|
||||||
// Roll for each drop group.
|
int start = entry.getCounts().get(0);
|
||||||
for (var entry : dropEntries) {
|
int end = entry.getCounts().get(entry.getCounts().size() - 1);
|
||||||
// Determine the number of drops we get for this entry.
|
var candidateAmounts = IntStream.range(start, end + 1).boxed().collect(Collectors.toList());
|
||||||
int start = entry.getCounts().get(0);
|
|
||||||
int end = entry.getCounts().get(entry.getCounts().size() - 1);
|
int amount = Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities());
|
||||||
var candidateAmounts = IntStream.range(start, end + 1).boxed().collect(Collectors.toList());
|
|
||||||
|
if (useCondensed) {
|
||||||
int amount = Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities());
|
amount += Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities());
|
||||||
|
}
|
||||||
if (useCondensed) {
|
|
||||||
amount += Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities());
|
// Double rewards in multiplay mode, if specified.
|
||||||
}
|
if (entry.isMpDouble() && this.getScene().getPlayerCount() > 1) {
|
||||||
|
amount *= 2;
|
||||||
// Double rewards in multiplay mode, if specified.
|
}
|
||||||
if (entry.isMpDouble() && this.getScene().getPlayerCount() > 1) {
|
|
||||||
amount *= 2;
|
// Roll items for this group.
|
||||||
}
|
// Here, we have to handle stacking, or the client will not display results correctly.
|
||||||
|
// For now, we use the following logic: If the possible drop item are a list of multiple
|
||||||
// Roll items for this group.
|
// items,
|
||||||
// Here, we have to handle stacking, or the client will not display results correctly.
|
// we roll them separately. If not, we stack them. This should work out in practice, at
|
||||||
// For now, we use the following logic: If the possible drop item are a list of multiple items,
|
// least
|
||||||
// we roll them separately. If not, we stack them. This should work out in practice, at least
|
// for the currently existing set of dungeons.
|
||||||
// for the currently existing set of dungeons.
|
if (entry.getItems().size() == 1) {
|
||||||
if (entry.getItems().size() == 1) {
|
rewards.add(new GameItem(entry.getItems().get(0), amount));
|
||||||
rewards.add(new GameItem(entry.getItems().get(0), amount));
|
} else {
|
||||||
} else {
|
for (int i = 0; i < amount; i++) {
|
||||||
for (int i = 0; i < amount; i++) {
|
// int itemIndex = ThreadLocalRandom.current().nextInt(0, entry.getItems().size());
|
||||||
// int itemIndex = ThreadLocalRandom.current().nextInt(0, entry.getItems().size());
|
// int itemId = entry.getItems().get(itemIndex);
|
||||||
// int itemId = entry.getItems().get(itemIndex);
|
int itemId =
|
||||||
int itemId = Utils.drawRandomListElement(entry.getItems(), entry.getItemProbabilities());
|
Utils.drawRandomListElement(entry.getItems(), entry.getItemProbabilities());
|
||||||
rewards.add(new GameItem(itemId, 1));
|
rewards.add(new GameItem(itemId, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Otherwise, we fall back to the preview data.
|
// Otherwise, we fall back to the preview data.
|
||||||
else {
|
else {
|
||||||
Grasscutter.getLogger().info("No drop data found or dungeon {}, falling back to preview data ...", dungeonId);
|
Grasscutter.getLogger()
|
||||||
for (ItemParamData param : dungeonData.getRewardPreviewData().getPreviewItems()) {
|
.info("No drop data found or dungeon {}, falling back to preview data ...", dungeonId);
|
||||||
rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1)));
|
for (ItemParamData param : dungeonData.getRewardPreviewData().getPreviewItems()) {
|
||||||
}
|
rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1)));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return rewards;
|
|
||||||
}
|
return rewards;
|
||||||
|
}
|
||||||
public void applyTrialTeam(Player player) {
|
|
||||||
if (getDungeonData() == null) return;
|
public void applyTrialTeam(Player player) {
|
||||||
|
if (getDungeonData() == null) return;
|
||||||
switch (getDungeonData().getType()) {
|
|
||||||
// case DUNGEON_PLOT is handled by quest execs
|
switch (getDungeonData().getType()) {
|
||||||
case DUNGEON_ACTIVITY -> {
|
// case DUNGEON_PLOT is handled by quest execs
|
||||||
switch (getDungeonData().getPlayType()) {
|
case DUNGEON_ACTIVITY -> {
|
||||||
case DUNGEON_PLAY_TYPE_TRIAL_AVATAR -> {
|
switch (getDungeonData().getPlayType()) {
|
||||||
val activityHandler = player.getActivityManager()
|
case DUNGEON_PLAY_TYPE_TRIAL_AVATAR -> {
|
||||||
.getActivityHandlerAs(ActivityType.NEW_ACTIVITY_TRIAL_AVATAR, TrialAvatarActivityHandler.class);
|
val activityHandler =
|
||||||
activityHandler.ifPresent(trialAvatarActivityHandler ->
|
player
|
||||||
this.trialTeam = trialAvatarActivityHandler.getTrialAvatarDungeonTeam());
|
.getActivityManager()
|
||||||
}
|
.getActivityHandlerAs(
|
||||||
}
|
ActivityType.NEW_ACTIVITY_TRIAL_AVATAR, TrialAvatarActivityHandler.class);
|
||||||
}
|
activityHandler.ifPresent(
|
||||||
case DUNGEON_ELEMENT_CHALLENGE -> {} // TODO
|
trialAvatarActivityHandler ->
|
||||||
}
|
this.trialTeam = trialAvatarActivityHandler.getTrialAvatarDungeonTeam());
|
||||||
|
}
|
||||||
if (this.trialTeam != null) {
|
}
|
||||||
player.getTeamManager().addTrialAvatars(trialTeam.trialAvatarIds);
|
}
|
||||||
}
|
case DUNGEON_ELEMENT_CHALLENGE -> {} // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unsetTrialTeam(Player player){
|
if (this.trialTeam != null) {
|
||||||
if (this.trialTeam == null) return;
|
player.getTeamManager().addTrialAvatars(trialTeam.trialAvatarIds);
|
||||||
|
}
|
||||||
player.getTeamManager().removeTrialAvatar();
|
}
|
||||||
this.trialTeam = null;
|
|
||||||
}
|
public void unsetTrialTeam(Player player) {
|
||||||
|
if (this.trialTeam == null) return;
|
||||||
public void startDungeon() {
|
|
||||||
this.startSceneTime = scene.getSceneTimeSeconds();
|
player.getTeamManager().removeTrialAvatar();
|
||||||
scene.getPlayers().forEach(p -> {
|
this.trialTeam = null;
|
||||||
p.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_ENTER_DUNGEON, dungeonData.getId());
|
}
|
||||||
applyTrialTeam(p);
|
|
||||||
});
|
public void startDungeon() {
|
||||||
}
|
this.startSceneTime = scene.getSceneTimeSeconds();
|
||||||
|
scene
|
||||||
public void finishDungeon() {
|
.getPlayers()
|
||||||
notifyEndDungeon(true);
|
.forEach(
|
||||||
endDungeon(BaseDungeonResult.DungeonEndReason.COMPLETED);
|
p -> {
|
||||||
}
|
p.getQuestManager()
|
||||||
|
.queueEvent(QuestContent.QUEST_CONTENT_ENTER_DUNGEON, dungeonData.getId());
|
||||||
public void notifyEndDungeon(boolean successfully) {
|
applyTrialTeam(p);
|
||||||
scene.getPlayers().forEach(p -> {
|
});
|
||||||
// Quest trigger
|
}
|
||||||
p.getQuestManager().queueEvent(successfully ?
|
|
||||||
QuestContent.QUEST_CONTENT_FINISH_DUNGEON : QuestContent.QUEST_CONTENT_FAIL_DUNGEON,
|
public void finishDungeon() {
|
||||||
dungeonData.getId());
|
notifyEndDungeon(true);
|
||||||
|
endDungeon(BaseDungeonResult.DungeonEndReason.COMPLETED);
|
||||||
// Battle pass trigger
|
}
|
||||||
if (dungeonData.getType().isCountsToBattlepass() && successfully) {
|
|
||||||
p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON);
|
public void notifyEndDungeon(boolean successfully) {
|
||||||
}
|
scene
|
||||||
});
|
.getPlayers()
|
||||||
scene.getScriptManager().callEvent(new ScriptArgs(0, EventType.EVENT_DUNGEON_SETTLE, successfully ? 1 : 0));
|
.forEach(
|
||||||
}
|
p -> {
|
||||||
|
// Quest trigger
|
||||||
public void quitDungeon() {
|
p.getQuestManager()
|
||||||
notifyEndDungeon(false);
|
.queueEvent(
|
||||||
endDungeon(BaseDungeonResult.DungeonEndReason.QUIT);
|
successfully
|
||||||
}
|
? QuestContent.QUEST_CONTENT_FINISH_DUNGEON
|
||||||
|
: QuestContent.QUEST_CONTENT_FAIL_DUNGEON,
|
||||||
public void failDungeon() {
|
dungeonData.getId());
|
||||||
notifyEndDungeon(false);
|
|
||||||
endDungeon(BaseDungeonResult.DungeonEndReason.FAILED);
|
// Battle pass trigger
|
||||||
}
|
if (dungeonData.getType().isCountsToBattlepass() && successfully) {
|
||||||
|
p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON);
|
||||||
public void endDungeon(BaseDungeonResult.DungeonEndReason endReason) {
|
}
|
||||||
if (scene.getDungeonSettleListeners() != null) {
|
});
|
||||||
scene.getDungeonSettleListeners().forEach(o -> o.onDungeonSettle(this, endReason));
|
scene
|
||||||
}
|
.getScriptManager()
|
||||||
ended = true;
|
.callEvent(new ScriptArgs(0, EventType.EVENT_DUNGEON_SETTLE, successfully ? 1 : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void restartDungeon() {
|
public void quitDungeon() {
|
||||||
this.scene.setKilledMonsterCount(0);
|
notifyEndDungeon(false);
|
||||||
this.rewardedPlayers.clear();
|
endDungeon(BaseDungeonResult.DungeonEndReason.QUIT);
|
||||||
Arrays.fill(finishedConditions, 0);
|
}
|
||||||
this.ended = false;
|
|
||||||
this.activeDungeonWayPoints.clear();
|
public void failDungeon() {
|
||||||
}
|
notifyEndDungeon(false);
|
||||||
|
endDungeon(BaseDungeonResult.DungeonEndReason.FAILED);
|
||||||
public void cleanUpScene() {
|
}
|
||||||
this.scene.setDungeonManager(null);
|
|
||||||
this.scene.setKilledMonsterCount(0);
|
public void endDungeon(BaseDungeonResult.DungeonEndReason endReason) {
|
||||||
}
|
if (scene.getDungeonSettleListeners() != null) {
|
||||||
}
|
scene.getDungeonSettleListeners().forEach(o -> o.onDungeonSettle(this, endReason));
|
||||||
|
}
|
||||||
|
ended = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restartDungeon() {
|
||||||
|
this.scene.setKilledMonsterCount(0);
|
||||||
|
this.rewardedPlayers.clear();
|
||||||
|
Arrays.fill(finishedConditions, 0);
|
||||||
|
this.ended = false;
|
||||||
|
this.activeDungeonWayPoints.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanUpScene() {
|
||||||
|
this.scene.setDungeonManager(null);
|
||||||
|
this.scene.setKilledMonsterCount(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package emu.grasscutter.game.dungeons;
|
package emu.grasscutter.game.dungeons;
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
|
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
|
||||||
|
|
||||||
public interface DungeonSettleListener {
|
public interface DungeonSettleListener {
|
||||||
void onDungeonSettle(DungeonManager dungeonManager, BaseDungeonResult.DungeonEndReason endReason);
|
void onDungeonSettle(DungeonManager dungeonManager, BaseDungeonResult.DungeonEndReason endReason);
|
||||||
}
|
}
|
||||||
|
@ -1,157 +1,170 @@
|
|||||||
package emu.grasscutter.game.dungeons;
|
package emu.grasscutter.game.dungeons;
|
||||||
|
|
||||||
import emu.grasscutter.GameConstants;
|
import emu.grasscutter.GameConstants;
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.binout.ScenePointEntry;
|
import emu.grasscutter.data.binout.ScenePointEntry;
|
||||||
import emu.grasscutter.data.excels.dungeon.DungeonData;
|
import emu.grasscutter.data.excels.dungeon.DungeonData;
|
||||||
import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData;
|
import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData;
|
||||||
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
|
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.SceneType;
|
import emu.grasscutter.game.props.SceneType;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.server.game.BaseGameSystem;
|
import emu.grasscutter.server.game.BaseGameSystem;
|
||||||
import emu.grasscutter.server.game.GameServer;
|
import emu.grasscutter.server.game.GameServer;
|
||||||
import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp;
|
import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import lombok.val;
|
import java.util.List;
|
||||||
import org.reflections.Reflections;
|
import lombok.val;
|
||||||
|
import org.reflections.Reflections;
|
||||||
import java.util.List;
|
|
||||||
|
public class DungeonSystem extends BaseGameSystem {
|
||||||
public class DungeonSystem extends BaseGameSystem {
|
private static final BasicDungeonSettleListener basicDungeonSettleObserver =
|
||||||
private static final BasicDungeonSettleListener basicDungeonSettleObserver = new BasicDungeonSettleListener();
|
new BasicDungeonSettleListener();
|
||||||
private final Int2ObjectMap<DungeonBaseHandler> passCondHandlers;
|
private final Int2ObjectMap<DungeonBaseHandler> passCondHandlers;
|
||||||
|
|
||||||
public DungeonSystem(GameServer server) {
|
public DungeonSystem(GameServer server) {
|
||||||
super(server);
|
super(server);
|
||||||
this.passCondHandlers = new Int2ObjectOpenHashMap<>();
|
this.passCondHandlers = new Int2ObjectOpenHashMap<>();
|
||||||
registerHandlers();
|
registerHandlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerHandlers() {
|
public void registerHandlers() {
|
||||||
this.registerHandlers(this.passCondHandlers, "emu.grasscutter.game.dungeons.pass_condition", DungeonBaseHandler.class);
|
this.registerHandlers(
|
||||||
}
|
this.passCondHandlers,
|
||||||
|
"emu.grasscutter.game.dungeons.pass_condition",
|
||||||
public <T> void registerHandlers(Int2ObjectMap<T> map, String packageName, Class<T> clazz) {
|
DungeonBaseHandler.class);
|
||||||
Reflections reflections = new Reflections(packageName);
|
}
|
||||||
var handlerClasses = reflections.getSubTypesOf(clazz);
|
|
||||||
|
public <T> void registerHandlers(Int2ObjectMap<T> map, String packageName, Class<T> clazz) {
|
||||||
for (var obj : handlerClasses) {
|
Reflections reflections = new Reflections(packageName);
|
||||||
this.registerPacketHandler(map, obj);
|
var handlerClasses = reflections.getSubTypesOf(clazz);
|
||||||
}
|
|
||||||
}
|
for (var obj : handlerClasses) {
|
||||||
|
this.registerPacketHandler(map, obj);
|
||||||
public <T> void registerPacketHandler(Int2ObjectMap<T> map, Class<? extends T> handlerClass) {
|
}
|
||||||
try {
|
}
|
||||||
DungeonValue opcode = handlerClass.getAnnotation(DungeonValue.class);
|
|
||||||
|
public <T> void registerPacketHandler(Int2ObjectMap<T> map, Class<? extends T> handlerClass) {
|
||||||
if (opcode == null || opcode.value() == null) {
|
try {
|
||||||
return;
|
DungeonValue opcode = handlerClass.getAnnotation(DungeonValue.class);
|
||||||
}
|
|
||||||
|
if (opcode == null || opcode.value() == null) {
|
||||||
map.put(opcode.value().ordinal(), handlerClass.getDeclaredConstructor().newInstance());
|
return;
|
||||||
} catch (Exception e) {
|
}
|
||||||
e.printStackTrace();
|
|
||||||
}
|
map.put(opcode.value().ordinal(), handlerClass.getDeclaredConstructor().newInstance());
|
||||||
}
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
public void getEntryInfo(Player player, int pointId) {
|
}
|
||||||
ScenePointEntry entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId);
|
}
|
||||||
|
|
||||||
if (entry == null) {
|
public void getEntryInfo(Player player, int pointId) {
|
||||||
// Error
|
ScenePointEntry entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId);
|
||||||
player.sendPacket(new PacketDungeonEntryInfoRsp());
|
|
||||||
return;
|
if (entry == null) {
|
||||||
}
|
// Error
|
||||||
|
player.sendPacket(new PacketDungeonEntryInfoRsp());
|
||||||
player.sendPacket(new PacketDungeonEntryInfoRsp(player, entry.getPointData()));
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean triggerCondition(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
|
player.sendPacket(new PacketDungeonEntryInfoRsp(player, entry.getPointData()));
|
||||||
var handler = passCondHandlers.get(condition.getCondType().ordinal());
|
}
|
||||||
|
|
||||||
if (handler == null) {
|
public boolean triggerCondition(
|
||||||
Grasscutter.getLogger().debug("Could not trigger condition {} at {}", condition.getCondType(), params);
|
DungeonPassConfigData.DungeonPassCondition condition, int... params) {
|
||||||
return false;
|
var handler = passCondHandlers.get(condition.getCondType().ordinal());
|
||||||
}
|
|
||||||
|
if (handler == null) {
|
||||||
return handler.execute(condition, params);
|
Grasscutter.getLogger()
|
||||||
}
|
.debug("Could not trigger condition {} at {}", condition.getCondType(), params);
|
||||||
|
return false;
|
||||||
public boolean enterDungeon(Player player, int pointId, int dungeonId) {
|
}
|
||||||
DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
|
|
||||||
|
return handler.execute(condition, params);
|
||||||
if (data == null) {
|
}
|
||||||
return false;
|
|
||||||
}
|
public boolean enterDungeon(Player player, int pointId, int dungeonId) {
|
||||||
Grasscutter.getLogger().info("{}({}) is trying to enter dungeon {}" ,player.getNickname(),player.getUid(),dungeonId);
|
DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
|
||||||
|
|
||||||
int sceneId = data.getSceneId();
|
if (data == null) {
|
||||||
var scene = player.getScene();
|
return false;
|
||||||
scene.setPrevScene(sceneId);
|
}
|
||||||
|
Grasscutter.getLogger()
|
||||||
if (player.getWorld().transferPlayerToScene(player, sceneId, data)) {
|
.info(
|
||||||
scene = player.getScene();
|
"{}({}) is trying to enter dungeon {}",
|
||||||
scene.addDungeonSettleObserver(basicDungeonSettleObserver);
|
player.getNickname(),
|
||||||
}
|
player.getUid(),
|
||||||
|
dungeonId);
|
||||||
scene.setPrevScenePoint(pointId);
|
|
||||||
return true;
|
int sceneId = data.getSceneId();
|
||||||
}
|
var scene = player.getScene();
|
||||||
|
scene.setPrevScene(sceneId);
|
||||||
/**
|
|
||||||
* used in tower dungeons handoff
|
if (player.getWorld().transferPlayerToScene(player, sceneId, data)) {
|
||||||
*/
|
scene = player.getScene();
|
||||||
public boolean handoffDungeon(Player player, int dungeonId, List<DungeonSettleListener> dungeonSettleListeners) {
|
scene.addDungeonSettleObserver(basicDungeonSettleObserver);
|
||||||
DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
|
}
|
||||||
|
|
||||||
if (data == null) {
|
scene.setPrevScenePoint(pointId);
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
Grasscutter.getLogger().info("{}({}) is trying to enter tower dungeon {}" ,player.getNickname(),player.getUid(),dungeonId);
|
|
||||||
|
/** used in tower dungeons handoff */
|
||||||
if (player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)) {
|
public boolean handoffDungeon(
|
||||||
dungeonSettleListeners.forEach(player.getScene()::addDungeonSettleObserver);
|
Player player, int dungeonId, List<DungeonSettleListener> dungeonSettleListeners) {
|
||||||
}
|
DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
|
||||||
return true;
|
|
||||||
}
|
if (data == null) {
|
||||||
|
return false;
|
||||||
public void exitDungeon(Player player) {
|
}
|
||||||
Scene scene = player.getScene();
|
Grasscutter.getLogger()
|
||||||
|
.info(
|
||||||
if (scene==null || scene.getSceneType() != SceneType.SCENE_DUNGEON) {
|
"{}({}) is trying to enter tower dungeon {}",
|
||||||
return;
|
player.getNickname(),
|
||||||
}
|
player.getUid(),
|
||||||
|
dungeonId);
|
||||||
// Get previous scene
|
|
||||||
int prevScene = scene.getPrevScene() > 0 ? scene.getPrevScene() : 3;
|
if (player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)) {
|
||||||
|
dungeonSettleListeners.forEach(player.getScene()::addDungeonSettleObserver);
|
||||||
// Get previous position
|
}
|
||||||
val dungeonManager = scene.getDungeonManager();
|
return true;
|
||||||
DungeonData dungeonData = dungeonManager != null ? dungeonManager.getDungeonData() : null;
|
}
|
||||||
Position prevPos = new Position(GameConstants.START_POSITION);
|
|
||||||
|
public void exitDungeon(Player player) {
|
||||||
if (dungeonData != null) {
|
Scene scene = player.getScene();
|
||||||
ScenePointEntry entry = GameData.getScenePointEntryById(prevScene, scene.getPrevScenePoint());
|
|
||||||
|
if (scene == null || scene.getSceneType() != SceneType.SCENE_DUNGEON) {
|
||||||
if (entry != null) {
|
return;
|
||||||
prevPos.set(entry.getPointData().getTranPos());
|
}
|
||||||
}
|
|
||||||
if(!dungeonManager.isFinishedSuccessfully()){
|
// Get previous scene
|
||||||
dungeonManager.quitDungeon();
|
int prevScene = scene.getPrevScene() > 0 ? scene.getPrevScene() : 3;
|
||||||
}
|
|
||||||
|
// Get previous position
|
||||||
dungeonManager.unsetTrialTeam(player);
|
val dungeonManager = scene.getDungeonManager();
|
||||||
}
|
DungeonData dungeonData = dungeonManager != null ? dungeonManager.getDungeonData() : null;
|
||||||
// clean temp team if it has
|
Position prevPos = new Position(GameConstants.START_POSITION);
|
||||||
player.getTeamManager().cleanTemporaryTeam();
|
|
||||||
player.getTowerManager().clearEntry();
|
if (dungeonData != null) {
|
||||||
|
ScenePointEntry entry = GameData.getScenePointEntryById(prevScene, scene.getPrevScenePoint());
|
||||||
|
|
||||||
// Transfer player back to world
|
if (entry != null) {
|
||||||
player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
|
prevPos.set(entry.getPointData().getTranPos());
|
||||||
}
|
}
|
||||||
}
|
if (!dungeonManager.isFinishedSuccessfully()) {
|
||||||
|
dungeonManager.quitDungeon();
|
||||||
|
}
|
||||||
|
|
||||||
|
dungeonManager.unsetTrialTeam(player);
|
||||||
|
}
|
||||||
|
// clean temp team if it has
|
||||||
|
player.getTeamManager().cleanTemporaryTeam();
|
||||||
|
player.getTowerManager().clearEntry();
|
||||||
|
|
||||||
|
// Transfer player back to world
|
||||||
|
player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,38 +1,40 @@
|
|||||||
package emu.grasscutter.game.dungeons;
|
package emu.grasscutter.game.dungeons;
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult.DungeonEndReason;
|
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult.DungeonEndReason;
|
||||||
import emu.grasscutter.game.world.SceneGroupInstance;
|
import emu.grasscutter.game.dungeons.dungeon_results.TowerResult;
|
||||||
import emu.grasscutter.game.dungeons.dungeon_results.TowerResult;
|
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
|
import emu.grasscutter.server.packet.send.PacketTowerFloorRecordChangeNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketTowerFloorRecordChangeNotify;
|
|
||||||
|
public class TowerDungeonSettleListener implements DungeonSettleListener {
|
||||||
public class TowerDungeonSettleListener implements DungeonSettleListener {
|
|
||||||
|
@Override
|
||||||
@Override
|
public void onDungeonSettle(DungeonManager dungeonManager, DungeonEndReason endReason) {
|
||||||
public void onDungeonSettle(DungeonManager dungeonManager, DungeonEndReason endReason) {
|
var scene = dungeonManager.getScene();
|
||||||
var scene = dungeonManager.getScene();
|
var dungeonData = dungeonManager.getDungeonData();
|
||||||
var dungeonData = dungeonManager.getDungeonData();
|
if (scene.getLoadedGroups().stream()
|
||||||
if (scene.getLoadedGroups().stream().anyMatch(g -> {
|
.anyMatch(
|
||||||
var variables = scene.getScriptManager().getVariables(g.id);
|
g -> {
|
||||||
return variables != null && variables.containsKey("stage") && variables.get("stage") == 1;
|
var variables = scene.getScriptManager().getVariables(g.id);
|
||||||
})) {
|
return variables != null
|
||||||
return;
|
&& variables.containsKey("stage")
|
||||||
}
|
&& variables.get("stage") == 1;
|
||||||
|
})) {
|
||||||
var towerManager = scene.getPlayers().get(0).getTowerManager();
|
return;
|
||||||
|
}
|
||||||
towerManager.notifyCurLevelRecordChangeWhenDone(3);
|
|
||||||
scene.broadcastPacket(new PacketTowerFloorRecordChangeNotify(
|
var towerManager = scene.getPlayers().get(0).getTowerManager();
|
||||||
towerManager.getCurrentFloorId(),
|
|
||||||
3,
|
towerManager.notifyCurLevelRecordChangeWhenDone(3);
|
||||||
towerManager.canEnterScheduleFloor()
|
scene.broadcastPacket(
|
||||||
));
|
new PacketTowerFloorRecordChangeNotify(
|
||||||
|
towerManager.getCurrentFloorId(), 3, towerManager.canEnterScheduleFloor()));
|
||||||
var challenge = scene.getChallenge();
|
|
||||||
var dungeonStats = new DungeonEndStats(scene.getKilledMonsterCount(), challenge.getFinishedTime(), 0, endReason);
|
var challenge = scene.getChallenge();
|
||||||
var result = new TowerResult(dungeonData, dungeonStats, towerManager, challenge);
|
var dungeonStats =
|
||||||
|
new DungeonEndStats(
|
||||||
scene.broadcastPacket(new PacketDungeonSettleNotify(result));
|
scene.getKilledMonsterCount(), challenge.getFinishedTime(), 0, endReason);
|
||||||
|
var result = new TowerResult(dungeonData, dungeonStats, towerManager, challenge);
|
||||||
}
|
|
||||||
}
|
scene.broadcastPacket(new PacketDungeonSettleNotify(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,167 +1,178 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge;
|
package emu.grasscutter.game.dungeons.challenge;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
|
||||||
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
|
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
import emu.grasscutter.game.entity.EntityMonster;
|
import emu.grasscutter.game.entity.EntityMonster;
|
||||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.constants.EventType;
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
import emu.grasscutter.scripts.data.SceneTrigger;
|
import emu.grasscutter.scripts.data.SceneTrigger;
|
||||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||||
import emu.grasscutter.server.packet.send.PacketDungeonChallengeBeginNotify;
|
import emu.grasscutter.server.packet.send.PacketDungeonChallengeBeginNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify;
|
import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.val;
|
|
||||||
|
@Getter
|
||||||
@Getter
|
@Setter
|
||||||
@Setter
|
public class WorldChallenge {
|
||||||
public class WorldChallenge {
|
private final Scene scene;
|
||||||
private final Scene scene;
|
private final SceneGroup group;
|
||||||
private final SceneGroup group;
|
private final int challengeId;
|
||||||
private final int challengeId;
|
private final int challengeIndex;
|
||||||
private final int challengeIndex;
|
private final List<Integer> paramList;
|
||||||
private final List<Integer> paramList;
|
private final int timeLimit;
|
||||||
private final int timeLimit;
|
private final List<ChallengeTrigger> challengeTriggers;
|
||||||
private final List<ChallengeTrigger> challengeTriggers;
|
private final int goal;
|
||||||
private final int goal;
|
private final AtomicInteger score;
|
||||||
private final AtomicInteger score;
|
private boolean progress;
|
||||||
private boolean progress;
|
private boolean success;
|
||||||
private boolean success;
|
private long startedAt;
|
||||||
private long startedAt;
|
private int finishedTime;
|
||||||
private int finishedTime;
|
|
||||||
|
public WorldChallenge(
|
||||||
public WorldChallenge(
|
Scene scene,
|
||||||
Scene scene,
|
SceneGroup group,
|
||||||
SceneGroup group,
|
int challengeId,
|
||||||
int challengeId,
|
int challengeIndex,
|
||||||
int challengeIndex,
|
List<Integer> paramList,
|
||||||
List<Integer> paramList,
|
int timeLimit,
|
||||||
int timeLimit,
|
int goal,
|
||||||
int goal,
|
List<ChallengeTrigger> challengeTriggers) {
|
||||||
List<ChallengeTrigger> challengeTriggers) {
|
this.scene = scene;
|
||||||
this.scene = scene;
|
this.group = group;
|
||||||
this.group = group;
|
this.challengeId = challengeId;
|
||||||
this.challengeId = challengeId;
|
this.challengeIndex = challengeIndex;
|
||||||
this.challengeIndex = challengeIndex;
|
this.paramList = paramList;
|
||||||
this.paramList = paramList;
|
this.timeLimit = timeLimit;
|
||||||
this.timeLimit = timeLimit;
|
this.challengeTriggers = challengeTriggers;
|
||||||
this.challengeTriggers = challengeTriggers;
|
this.goal = goal;
|
||||||
this.goal = goal;
|
this.score = new AtomicInteger(0);
|
||||||
this.score = new AtomicInteger(0);
|
}
|
||||||
}
|
|
||||||
|
public boolean inProgress() {
|
||||||
public boolean inProgress() {
|
return this.progress;
|
||||||
return this.progress;
|
}
|
||||||
}
|
|
||||||
|
public void onCheckTimeOut() {
|
||||||
public void onCheckTimeOut() {
|
if (!inProgress()) {
|
||||||
if (!inProgress()) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
if (timeLimit <= 0) {
|
||||||
if (timeLimit <= 0) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
challengeTriggers.forEach(t -> t.onCheckTimeout(this));
|
||||||
challengeTriggers.forEach(t -> t.onCheckTimeout(this));
|
}
|
||||||
}
|
|
||||||
|
public void start() {
|
||||||
public void start() {
|
if (inProgress()) {
|
||||||
if (inProgress()) {
|
Grasscutter.getLogger().info("Could not start a in progress challenge.");
|
||||||
Grasscutter.getLogger().info("Could not start a in progress challenge.");
|
return;
|
||||||
return;
|
}
|
||||||
}
|
this.progress = true;
|
||||||
this.progress = true;
|
this.startedAt = System.currentTimeMillis();
|
||||||
this.startedAt = System.currentTimeMillis();
|
getScene().broadcastPacket(new PacketDungeonChallengeBeginNotify(this));
|
||||||
getScene().broadcastPacket(new PacketDungeonChallengeBeginNotify(this));
|
challengeTriggers.forEach(t -> t.onBegin(this));
|
||||||
challengeTriggers.forEach(t -> t.onBegin(this));
|
}
|
||||||
}
|
|
||||||
|
public void done() {
|
||||||
public void done() {
|
if (!this.inProgress()) return;
|
||||||
if (!this.inProgress()) return;
|
this.finish(true);
|
||||||
this.finish(true);
|
|
||||||
|
var scene = this.getScene();
|
||||||
var scene = this.getScene();
|
var dungeonManager = scene.getDungeonManager();
|
||||||
var dungeonManager = scene.getDungeonManager();
|
if (dungeonManager != null && dungeonManager.getDungeonData() != null) {
|
||||||
if (dungeonManager != null && dungeonManager.getDungeonData() != null) {
|
scene
|
||||||
scene.getPlayers().forEach(p -> p.getActivityManager().triggerWatcher(
|
.getPlayers()
|
||||||
WatcherTriggerType.TRIGGER_FINISH_CHALLENGE,
|
.forEach(
|
||||||
String.valueOf(dungeonManager.getDungeonData().getId()),
|
p ->
|
||||||
String.valueOf(this.getGroup().id),
|
p.getActivityManager()
|
||||||
String.valueOf(this.getChallengeId())
|
.triggerWatcher(
|
||||||
));
|
WatcherTriggerType.TRIGGER_FINISH_CHALLENGE,
|
||||||
}
|
String.valueOf(dungeonManager.getDungeonData().getId()),
|
||||||
|
String.valueOf(this.getGroup().id),
|
||||||
scene.getScriptManager().callEvent(
|
String.valueOf(this.getChallengeId())));
|
||||||
// TODO record the time in PARAM2 and used in action
|
}
|
||||||
new ScriptArgs(this.getGroup().id, EventType.EVENT_CHALLENGE_SUCCESS).setParam2(finishedTime));
|
|
||||||
this.getScene().triggerDungeonEvent(DungeonPassConditionType.DUNGEON_COND_FINISH_CHALLENGE, getChallengeId(), getChallengeIndex());
|
scene
|
||||||
|
.getScriptManager()
|
||||||
this.challengeTriggers.forEach(t -> t.onFinish(this));
|
.callEvent(
|
||||||
}
|
// TODO record the time in PARAM2 and used in action
|
||||||
|
new ScriptArgs(this.getGroup().id, EventType.EVENT_CHALLENGE_SUCCESS)
|
||||||
public void fail(){
|
.setParam2(finishedTime));
|
||||||
if (!this.inProgress()) return;
|
this.getScene()
|
||||||
this.finish(true);
|
.triggerDungeonEvent(
|
||||||
|
DungeonPassConditionType.DUNGEON_COND_FINISH_CHALLENGE,
|
||||||
this.getScene().getScriptManager().callEvent(new ScriptArgs(this.getGroup().id, EventType.EVENT_CHALLENGE_FAIL));
|
getChallengeId(),
|
||||||
challengeTriggers.forEach(t -> t.onFinish(this));
|
getChallengeIndex());
|
||||||
}
|
|
||||||
|
this.challengeTriggers.forEach(t -> t.onFinish(this));
|
||||||
private void finish(boolean success) {
|
}
|
||||||
this.progress = false;
|
|
||||||
this.success = success;
|
public void fail() {
|
||||||
this.finishedTime = (int) ((System.currentTimeMillis() - this.startedAt) / 1000L);
|
if (!this.inProgress()) return;
|
||||||
getScene().broadcastPacket(new PacketDungeonChallengeFinishNotify(this));
|
this.finish(true);
|
||||||
}
|
|
||||||
|
this.getScene()
|
||||||
public int increaseScore() {
|
.getScriptManager()
|
||||||
return score.incrementAndGet();
|
.callEvent(new ScriptArgs(this.getGroup().id, EventType.EVENT_CHALLENGE_FAIL));
|
||||||
}
|
challengeTriggers.forEach(t -> t.onFinish(this));
|
||||||
|
}
|
||||||
public void onMonsterDeath(EntityMonster monster) {
|
|
||||||
if (!inProgress()) {
|
private void finish(boolean success) {
|
||||||
return;
|
this.progress = false;
|
||||||
}
|
this.success = success;
|
||||||
if (monster.getGroupId() != getGroup().id) {
|
this.finishedTime = (int) ((System.currentTimeMillis() - this.startedAt) / 1000L);
|
||||||
return;
|
getScene().broadcastPacket(new PacketDungeonChallengeFinishNotify(this));
|
||||||
}
|
}
|
||||||
this.challengeTriggers.forEach(t -> t.onMonsterDeath(this, monster));
|
|
||||||
}
|
public int increaseScore() {
|
||||||
|
return score.incrementAndGet();
|
||||||
public void onGadgetDeath(EntityGadget gadget) {
|
}
|
||||||
if (!inProgress()) {
|
|
||||||
return;
|
public void onMonsterDeath(EntityMonster monster) {
|
||||||
}
|
if (!inProgress()) {
|
||||||
if (gadget.getGroupId() != getGroup().id) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
if (monster.getGroupId() != getGroup().id) {
|
||||||
this.challengeTriggers.forEach(t -> t.onGadgetDeath(this, gadget));
|
return;
|
||||||
}
|
}
|
||||||
|
this.challengeTriggers.forEach(t -> t.onMonsterDeath(this, monster));
|
||||||
public void onGroupTriggerDeath(SceneTrigger trigger) {
|
}
|
||||||
if(!this.inProgress()) return;
|
|
||||||
|
public void onGadgetDeath(EntityGadget gadget) {
|
||||||
var triggerGroup = trigger.getCurrentGroup();
|
if (!inProgress()) {
|
||||||
if (triggerGroup == null ||
|
return;
|
||||||
triggerGroup.id != getGroup().id) {
|
}
|
||||||
return;
|
if (gadget.getGroupId() != getGroup().id) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
this.challengeTriggers.forEach(t -> t.onGroupTrigger(this, trigger));
|
this.challengeTriggers.forEach(t -> t.onGadgetDeath(this, gadget));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onGadgetDamage(EntityGadget gadget) {
|
public void onGroupTriggerDeath(SceneTrigger trigger) {
|
||||||
if (!inProgress()) {
|
if (!this.inProgress()) return;
|
||||||
return;
|
|
||||||
}
|
var triggerGroup = trigger.getCurrentGroup();
|
||||||
if (gadget.getGroupId() != getGroup().id) {
|
if (triggerGroup == null || triggerGroup.id != getGroup().id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.challengeTriggers.forEach(t -> t.onGadgetDamage(this, gadget));
|
|
||||||
}
|
this.challengeTriggers.forEach(t -> t.onGroupTrigger(this, trigger));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onGadgetDamage(EntityGadget gadget) {
|
||||||
|
if (!inProgress()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (gadget.getGroupId() != getGroup().id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.challengeTriggers.forEach(t -> t.onGadgetDamage(this, gadget));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,36 +1,44 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.factory;
|
package emu.grasscutter.game.dungeons.challenge.factory;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
import lombok.val;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.ArrayList;
|
import lombok.val;
|
||||||
import java.util.List;
|
|
||||||
|
public abstract class ChallengeFactory {
|
||||||
public abstract class ChallengeFactory {
|
private static final List<ChallengeFactoryHandler> challengeFactoryHandlers = new ArrayList<>();
|
||||||
private static final List<ChallengeFactoryHandler> challengeFactoryHandlers = new ArrayList<>();
|
|
||||||
|
static {
|
||||||
static {
|
challengeFactoryHandlers.add(new KillAndGuardChallengeFactoryHandler());
|
||||||
challengeFactoryHandlers.add(new KillAndGuardChallengeFactoryHandler());
|
challengeFactoryHandlers.add(new KillMonsterCountChallengeFactoryHandler());
|
||||||
challengeFactoryHandlers.add(new KillMonsterCountChallengeFactoryHandler());
|
challengeFactoryHandlers.add(new KillMonsterInTimeChallengeFactoryHandler());
|
||||||
challengeFactoryHandlers.add(new KillMonsterInTimeChallengeFactoryHandler());
|
challengeFactoryHandlers.add(new KillMonsterTimeChallengeFactoryHandler());
|
||||||
challengeFactoryHandlers.add(new KillMonsterTimeChallengeFactoryHandler());
|
challengeFactoryHandlers.add(new SurviveChallengeFactoryHandler());
|
||||||
challengeFactoryHandlers.add(new SurviveChallengeFactoryHandler());
|
challengeFactoryHandlers.add(new TriggerInTimeChallengeFactoryHandler());
|
||||||
challengeFactoryHandlers.add(new TriggerInTimeChallengeFactoryHandler());
|
}
|
||||||
}
|
|
||||||
|
public static WorldChallenge getChallenge(
|
||||||
public static WorldChallenge getChallenge(int localChallengeId, int challengeDataId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group){
|
int localChallengeId,
|
||||||
val challengeData = GameData.getDungeonChallengeConfigDataMap().get(challengeDataId);
|
int challengeDataId,
|
||||||
val challengeType = challengeData.getChallengeType();
|
int param3,
|
||||||
|
int param4,
|
||||||
for(var handler : challengeFactoryHandlers){
|
int param5,
|
||||||
if(!handler.isThisType(challengeType)){
|
int param6,
|
||||||
continue;
|
Scene scene,
|
||||||
}
|
SceneGroup group) {
|
||||||
return handler.build(localChallengeId, challengeDataId, param3, param4, param5, param6, scene, group);
|
val challengeData = GameData.getDungeonChallengeConfigDataMap().get(challengeDataId);
|
||||||
}
|
val challengeType = challengeData.getChallengeType();
|
||||||
return null;
|
|
||||||
}
|
for (var handler : challengeFactoryHandlers) {
|
||||||
}
|
if (!handler.isThisType(challengeType)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return handler.build(
|
||||||
|
localChallengeId, challengeDataId, param3, param4, param5, param6, scene, group);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,5 +7,14 @@ import emu.grasscutter.scripts.data.SceneGroup;
|
|||||||
|
|
||||||
public interface ChallengeFactoryHandler {
|
public interface ChallengeFactoryHandler {
|
||||||
boolean isThisType(ChallengeType challengeType);
|
boolean isThisType(ChallengeType challengeType);
|
||||||
WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group);
|
|
||||||
|
WorldChallenge build(
|
||||||
|
int challengeIndex,
|
||||||
|
int challengeId,
|
||||||
|
int param3,
|
||||||
|
int param4,
|
||||||
|
int param5,
|
||||||
|
int param6,
|
||||||
|
Scene scene,
|
||||||
|
SceneGroup group);
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.factory;
|
package emu.grasscutter.game.dungeons.challenge.factory;
|
||||||
|
|
||||||
|
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_KILL_COUNT_GUARD_HP;
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.GuardTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.GuardTrigger;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
|
import java.util.List;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
import java.util.List;
|
public class KillAndGuardChallengeFactoryHandler implements ChallengeFactoryHandler {
|
||||||
|
|
||||||
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_KILL_COUNT_GUARD_HP;
|
|
||||||
|
|
||||||
public class KillAndGuardChallengeFactoryHandler implements ChallengeFactoryHandler{
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isThisType(ChallengeType challengeType) {
|
public boolean isThisType(ChallengeType challengeType) {
|
||||||
// ActiveChallenge with 1,188,234101003,12,3030,0
|
// ActiveChallenge with 1,188,234101003,12,3030,0
|
||||||
@ -20,15 +19,24 @@ public class KillAndGuardChallengeFactoryHandler implements ChallengeFactoryHand
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override /*TODO check param4 == monstesToKill*/
|
@Override /*TODO check param4 == monstesToKill*/
|
||||||
public WorldChallenge build(int challengeIndex, int challengeId, int groupId, int monstersToKill, int gadgetCFGId, int unused, Scene scene, SceneGroup group) {
|
public WorldChallenge build(
|
||||||
|
int challengeIndex,
|
||||||
|
int challengeId,
|
||||||
|
int groupId,
|
||||||
|
int monstersToKill,
|
||||||
|
int gadgetCFGId,
|
||||||
|
int unused,
|
||||||
|
Scene scene,
|
||||||
|
SceneGroup group) {
|
||||||
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
||||||
return new WorldChallenge(
|
return new WorldChallenge(
|
||||||
scene, realGroup,
|
scene,
|
||||||
|
realGroup,
|
||||||
challengeId, // Id
|
challengeId, // Id
|
||||||
challengeIndex, // Index
|
challengeIndex, // Index
|
||||||
List.of(monstersToKill, 0),
|
List.of(monstersToKill, 0),
|
||||||
0, // Limit
|
0, // Limit
|
||||||
monstersToKill, // Goal
|
monstersToKill, // Goal
|
||||||
List.of(new KillMonsterCountTrigger(), new GuardTrigger(gadgetCFGId)));
|
List.of(new KillMonsterCountTrigger(), new GuardTrigger(gadgetCFGId)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,10 @@ import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
|||||||
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
|
import java.util.List;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
import java.util.List;
|
public class KillMonsterCountChallengeFactoryHandler implements ChallengeFactoryHandler {
|
||||||
|
|
||||||
public class KillMonsterCountChallengeFactoryHandler implements ChallengeFactoryHandler{
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isThisType(ChallengeType challengeType) {
|
public boolean isThisType(ChallengeType challengeType) {
|
||||||
// ActiveChallenge with 1, 1, 241033003, 15, 0, 0
|
// ActiveChallenge with 1, 1, 241033003, 15, 0, 0
|
||||||
@ -17,16 +16,24 @@ public class KillMonsterCountChallengeFactoryHandler implements ChallengeFactory
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorldChallenge build(int challengeIndex, int challengeId, int groupId, int goal, int param5, int param6, Scene scene, SceneGroup group) {
|
public WorldChallenge build(
|
||||||
|
int challengeIndex,
|
||||||
|
int challengeId,
|
||||||
|
int groupId,
|
||||||
|
int goal,
|
||||||
|
int param5,
|
||||||
|
int param6,
|
||||||
|
Scene scene,
|
||||||
|
SceneGroup group) {
|
||||||
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
||||||
return new WorldChallenge(
|
return new WorldChallenge(
|
||||||
scene, realGroup,
|
scene,
|
||||||
|
realGroup,
|
||||||
challengeId, // Id
|
challengeId, // Id
|
||||||
challengeIndex, // Index
|
challengeIndex, // Index
|
||||||
List.of(goal, groupId),
|
List.of(goal, groupId),
|
||||||
0, // Limit
|
0, // Limit
|
||||||
goal, // Goal
|
goal, // Goal
|
||||||
List.of(new KillMonsterCountTrigger())
|
List.of(new KillMonsterCountTrigger()));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,40 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.factory;
|
package emu.grasscutter.game.dungeons.challenge.factory;
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTrigger;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
import lombok.val;
|
import java.util.List;
|
||||||
|
import lombok.val;
|
||||||
import java.util.List;
|
|
||||||
|
public class KillMonsterInTimeChallengeFactoryHandler implements ChallengeFactoryHandler {
|
||||||
public class KillMonsterInTimeChallengeFactoryHandler implements ChallengeFactoryHandler{
|
@Override
|
||||||
@Override
|
public boolean isThisType(ChallengeType challengeType) {
|
||||||
public boolean isThisType(ChallengeType challengeType) {
|
// ActiveChallenge with 180, 72, 240, 133220161, 133220161, 0
|
||||||
// ActiveChallenge with 180, 72, 240, 133220161, 133220161, 0
|
return challengeType == ChallengeType.CHALLENGE_KILL_MONSTER_IN_TIME;
|
||||||
return challengeType == ChallengeType.CHALLENGE_KILL_MONSTER_IN_TIME;
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public WorldChallenge build(
|
||||||
public WorldChallenge build(int challengeIndex, int challengeId, int timeLimit, int groupId, int targetCfgId, int param6, Scene scene, SceneGroup group) {
|
int challengeIndex,
|
||||||
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
int challengeId,
|
||||||
return new WorldChallenge(
|
int timeLimit,
|
||||||
scene, realGroup,
|
int groupId,
|
||||||
challengeId, // Id
|
int targetCfgId,
|
||||||
challengeIndex, // Index
|
int param6,
|
||||||
List.of(timeLimit),
|
Scene scene,
|
||||||
timeLimit, // Limit
|
SceneGroup group) {
|
||||||
0, // Goal
|
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
||||||
List.of(new KillMonsterTrigger(targetCfgId), new InTimeTrigger())
|
return new WorldChallenge(
|
||||||
);
|
scene,
|
||||||
}
|
realGroup,
|
||||||
}
|
challengeId, // Id
|
||||||
|
challengeIndex, // Index
|
||||||
|
List.of(timeLimit),
|
||||||
|
timeLimit, // Limit
|
||||||
|
0, // Goal
|
||||||
|
List.of(new KillMonsterTrigger(targetCfgId), new InTimeTrigger()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,30 +6,37 @@ import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
|
|||||||
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
|
import java.util.List;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
import java.util.List;
|
public class KillMonsterTimeChallengeFactoryHandler implements ChallengeFactoryHandler {
|
||||||
|
|
||||||
public class KillMonsterTimeChallengeFactoryHandler implements ChallengeFactoryHandler{
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isThisType(ChallengeType challengeType) {
|
public boolean isThisType(ChallengeType challengeType) {
|
||||||
// ActiveChallenge with 180,180,45,133108061,1,0
|
// ActiveChallenge with 180,180,45,133108061,1,0
|
||||||
// ActiveChallenge Fast with 1001, 5, 15, 240004005, 10, 0
|
// ActiveChallenge Fast with 1001, 5, 15, 240004005, 10, 0
|
||||||
return challengeType == ChallengeType.CHALLENGE_KILL_COUNT_IN_TIME ||
|
return challengeType == ChallengeType.CHALLENGE_KILL_COUNT_IN_TIME
|
||||||
challengeType == ChallengeType.CHALLENGE_KILL_COUNT_FAST;
|
|| challengeType == ChallengeType.CHALLENGE_KILL_COUNT_FAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorldChallenge build(int challengeIndex, int challengeId, int timeLimit, int groupId, int targetCount, int param6, Scene scene, SceneGroup group) {
|
public WorldChallenge build(
|
||||||
|
int challengeIndex,
|
||||||
|
int challengeId,
|
||||||
|
int timeLimit,
|
||||||
|
int groupId,
|
||||||
|
int targetCount,
|
||||||
|
int param6,
|
||||||
|
Scene scene,
|
||||||
|
SceneGroup group) {
|
||||||
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
||||||
return new WorldChallenge(
|
return new WorldChallenge(
|
||||||
scene, realGroup,
|
scene,
|
||||||
|
realGroup,
|
||||||
challengeId, // Id
|
challengeId, // Id
|
||||||
challengeIndex, // Index
|
challengeIndex, // Index
|
||||||
List.of(targetCount, timeLimit),
|
List.of(targetCount, timeLimit),
|
||||||
timeLimit, // Limit
|
timeLimit, // Limit
|
||||||
targetCount, // Goal
|
targetCount, // Goal
|
||||||
List.of(new KillMonsterCountTrigger(), new InTimeTrigger())
|
List.of(new KillMonsterCountTrigger(), new InTimeTrigger()));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.factory;
|
package emu.grasscutter.game.dungeons.challenge.factory;
|
||||||
|
|
||||||
|
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_SURVIVE;
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.ForTimeTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.ForTimeTrigger;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_SURVIVE;
|
|
||||||
|
|
||||||
public class SurviveChallengeFactoryHandler implements ChallengeFactoryHandler {
|
public class SurviveChallengeFactoryHandler implements ChallengeFactoryHandler {
|
||||||
@Override
|
@Override
|
||||||
public boolean isThisType(ChallengeType challengeType) {
|
public boolean isThisType(ChallengeType challengeType) {
|
||||||
@ -19,15 +18,23 @@ public class SurviveChallengeFactoryHandler implements ChallengeFactoryHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorldChallenge build(int challengeIndex, int challengeId, int timeToSurvive, int unused4, int unused5, int unused6, Scene scene, SceneGroup group) {
|
public WorldChallenge build(
|
||||||
|
int challengeIndex,
|
||||||
|
int challengeId,
|
||||||
|
int timeToSurvive,
|
||||||
|
int unused4,
|
||||||
|
int unused5,
|
||||||
|
int unused6,
|
||||||
|
Scene scene,
|
||||||
|
SceneGroup group) {
|
||||||
return new WorldChallenge(
|
return new WorldChallenge(
|
||||||
scene, group,
|
scene,
|
||||||
challengeId, // Id
|
group,
|
||||||
challengeIndex, // Index
|
challengeId, // Id
|
||||||
List.of(timeToSurvive),
|
challengeIndex, // Index
|
||||||
timeToSurvive, // Limit
|
List.of(timeToSurvive),
|
||||||
0, // Goal
|
timeToSurvive, // Limit
|
||||||
List.of(new ForTimeTrigger())
|
0, // Goal
|
||||||
);
|
List.of(new ForTimeTrigger()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.factory;
|
package emu.grasscutter.game.dungeons.challenge.factory;
|
||||||
|
|
||||||
|
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_TRIGGER_IN_TIME;
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.TriggerGroupTriggerTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.TriggerGroupTriggerTrigger;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_TRIGGER_IN_TIME;
|
|
||||||
|
|
||||||
public class TriggerInTimeChallengeFactoryHandler implements ChallengeFactoryHandler {
|
public class TriggerInTimeChallengeFactoryHandler implements ChallengeFactoryHandler {
|
||||||
@Override
|
@Override
|
||||||
public boolean isThisType(ChallengeType challengeType) {
|
public boolean isThisType(ChallengeType challengeType) {
|
||||||
@ -22,15 +21,23 @@ public class TriggerInTimeChallengeFactoryHandler implements ChallengeFactoryHan
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorldChallenge build(int challengeIndex, int challengeId, int timeLimit, int param4, int triggerTag, int triggerCount, Scene scene, SceneGroup group) {
|
public WorldChallenge build(
|
||||||
|
int challengeIndex,
|
||||||
|
int challengeId,
|
||||||
|
int timeLimit,
|
||||||
|
int param4,
|
||||||
|
int triggerTag,
|
||||||
|
int triggerCount,
|
||||||
|
Scene scene,
|
||||||
|
SceneGroup group) {
|
||||||
return new WorldChallenge(
|
return new WorldChallenge(
|
||||||
scene, group,
|
scene,
|
||||||
|
group,
|
||||||
challengeId, // Id
|
challengeId, // Id
|
||||||
challengeIndex, // Index
|
challengeIndex, // Index
|
||||||
List.of(timeLimit, triggerCount),
|
List.of(timeLimit, triggerCount),
|
||||||
timeLimit, // Limit
|
timeLimit, // Limit
|
||||||
triggerCount, // Goal
|
triggerCount, // Goal
|
||||||
List.of(new InTimeTrigger(), new TriggerGroupTriggerTrigger(Integer.toString(triggerTag)))
|
List.of(new InTimeTrigger(), new TriggerGroupTriggerTrigger(Integer.toString(triggerTag))));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,22 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.trigger;
|
package emu.grasscutter.game.dungeons.challenge.trigger;
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
import emu.grasscutter.game.entity.EntityMonster;
|
import emu.grasscutter.game.entity.EntityMonster;
|
||||||
import emu.grasscutter.scripts.data.SceneTrigger;
|
import emu.grasscutter.scripts.data.SceneTrigger;
|
||||||
|
|
||||||
public abstract class ChallengeTrigger {
|
public abstract class ChallengeTrigger {
|
||||||
public void onBegin(WorldChallenge challenge) { }
|
public void onBegin(WorldChallenge challenge) {}
|
||||||
public void onFinish(WorldChallenge challenge) { }
|
|
||||||
public void onMonsterDeath(WorldChallenge challenge, EntityMonster monster) { }
|
public void onFinish(WorldChallenge challenge) {}
|
||||||
public void onGadgetDeath(WorldChallenge challenge, EntityGadget gadget) { }
|
|
||||||
public void onCheckTimeout(WorldChallenge challenge) { }
|
public void onMonsterDeath(WorldChallenge challenge, EntityMonster monster) {}
|
||||||
public void onGadgetDamage(WorldChallenge challenge, EntityGadget gadget) { }
|
|
||||||
public void onGroupTrigger(WorldChallenge challenge, SceneTrigger trigger) { }
|
public void onGadgetDeath(WorldChallenge challenge, EntityGadget gadget) {}
|
||||||
}
|
|
||||||
|
public void onCheckTimeout(WorldChallenge challenge) {}
|
||||||
|
|
||||||
|
public void onGadgetDamage(WorldChallenge challenge, EntityGadget gadget) {}
|
||||||
|
|
||||||
|
public void onGroupTrigger(WorldChallenge challenge, SceneTrigger trigger) {}
|
||||||
|
}
|
||||||
|
@ -1,38 +1,38 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.trigger;
|
package emu.grasscutter.game.dungeons.challenge.trigger;
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
import emu.grasscutter.game.entity.EntityMonster;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
|
|
||||||
|
public class GuardTrigger extends ChallengeTrigger {
|
||||||
public class GuardTrigger extends ChallengeTrigger {
|
private final int entityToProtectCFGId;
|
||||||
private final int entityToProtectCFGId;
|
private int lastSendPercent = 100;
|
||||||
private int lastSendPercent = 100;
|
|
||||||
public GuardTrigger(int entityToProtectCFGId){
|
public GuardTrigger(int entityToProtectCFGId) {
|
||||||
this.entityToProtectCFGId = entityToProtectCFGId;
|
this.entityToProtectCFGId = entityToProtectCFGId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onBegin(WorldChallenge challenge) {
|
public void onBegin(WorldChallenge challenge) {
|
||||||
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, 100));
|
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGadgetDamage(WorldChallenge challenge, EntityGadget gadget) {
|
public void onGadgetDamage(WorldChallenge challenge, EntityGadget gadget) {
|
||||||
if(gadget.getConfigId() != entityToProtectCFGId){
|
if (gadget.getConfigId() != entityToProtectCFGId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var curHp = gadget.getFightProperties().get(FightProperty.FIGHT_PROP_CUR_HP.getId());
|
var curHp = gadget.getFightProperties().get(FightProperty.FIGHT_PROP_CUR_HP.getId());
|
||||||
var maxHp = gadget.getFightProperties().get(FightProperty.FIGHT_PROP_BASE_HP.getId());
|
var maxHp = gadget.getFightProperties().get(FightProperty.FIGHT_PROP_BASE_HP.getId());
|
||||||
int percent = (int) (curHp / maxHp);
|
int percent = (int) (curHp / maxHp);
|
||||||
|
|
||||||
if(percent!=lastSendPercent) {
|
if (percent != lastSendPercent) {
|
||||||
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, percent));
|
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, percent));
|
||||||
lastSendPercent = percent;
|
lastSendPercent = percent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(percent <= 0){
|
if (percent <= 0) {
|
||||||
challenge.fail();
|
challenge.fail();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,25 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.trigger;
|
package emu.grasscutter.game.dungeons.challenge.trigger;
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.entity.EntityMonster;
|
import emu.grasscutter.game.entity.EntityMonster;
|
||||||
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
|
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class KillMonsterTrigger extends ChallengeTrigger{
|
public class KillMonsterTrigger extends ChallengeTrigger {
|
||||||
private int monsterCfgId;
|
private int monsterCfgId;
|
||||||
@Override
|
|
||||||
public void onBegin(WorldChallenge challenge) {
|
@Override
|
||||||
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 1, challenge.getScore().get()));
|
public void onBegin(WorldChallenge challenge) {
|
||||||
}
|
challenge
|
||||||
|
.getScene()
|
||||||
@Override
|
.broadcastPacket(new PacketChallengeDataNotify(challenge, 1, challenge.getScore().get()));
|
||||||
public void onMonsterDeath(WorldChallenge challenge, EntityMonster monster) {
|
}
|
||||||
if(monster.getConfigId() == monsterCfgId){
|
|
||||||
challenge.done();
|
@Override
|
||||||
}
|
public void onMonsterDeath(WorldChallenge challenge, EntityMonster monster) {
|
||||||
}
|
if (monster.getConfigId() == monsterCfgId) {
|
||||||
}
|
challenge.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,370 +1,370 @@
|
|||||||
package emu.grasscutter.game.entity;
|
package emu.grasscutter.game.entity;
|
||||||
|
|
||||||
import emu.grasscutter.GameConstants;
|
import emu.grasscutter.GameConstants;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.excels.avatar.AvatarData;
|
import emu.grasscutter.data.excels.avatar.AvatarData;
|
||||||
import emu.grasscutter.data.excels.avatar.AvatarSkillDepotData;
|
import emu.grasscutter.data.excels.avatar.AvatarSkillDepotData;
|
||||||
import emu.grasscutter.game.avatar.Avatar;
|
import emu.grasscutter.game.avatar.Avatar;
|
||||||
import emu.grasscutter.game.inventory.EquipType;
|
import emu.grasscutter.game.inventory.EquipType;
|
||||||
import emu.grasscutter.game.inventory.GameItem;
|
import emu.grasscutter.game.inventory.GameItem;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.EntityIdType;
|
import emu.grasscutter.game.props.EntityIdType;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.game.props.PlayerProperty;
|
import emu.grasscutter.game.props.PlayerProperty;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.net.proto.AbilityControlBlockOuterClass.AbilityControlBlock;
|
import emu.grasscutter.net.proto.AbilityControlBlockOuterClass.AbilityControlBlock;
|
||||||
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.ChangeEnergyReasonOuterClass.ChangeEnergyReason;
|
import emu.grasscutter.net.proto.ChangeEnergyReasonOuterClass.ChangeEnergyReason;
|
||||||
import emu.grasscutter.net.proto.ChangeHpReasonOuterClass.ChangeHpReason;
|
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.PlayerDieTypeOuterClass.PlayerDieType;
|
import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType;
|
||||||
import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
|
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.event.player.PlayerMoveEvent;
|
import emu.grasscutter.server.event.player.PlayerMoveEvent;
|
||||||
import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify;
|
import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify;
|
import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
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;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
public class EntityAvatar extends GameEntity {
|
public class EntityAvatar extends GameEntity {
|
||||||
@Getter private final Avatar avatar;
|
@Getter private final Avatar avatar;
|
||||||
|
|
||||||
@Getter private PlayerDieType killedType;
|
@Getter private PlayerDieType killedType;
|
||||||
@Getter private int killedBy;
|
@Getter private int killedBy;
|
||||||
|
|
||||||
public EntityAvatar(Avatar avatar) {
|
public EntityAvatar(Avatar avatar) {
|
||||||
this(null, avatar);
|
this(null, avatar);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityAvatar(Scene scene, Avatar avatar) {
|
public EntityAvatar(Scene scene, Avatar avatar) {
|
||||||
super(scene);
|
super(scene);
|
||||||
|
|
||||||
this.avatar = avatar;
|
this.avatar = avatar;
|
||||||
this.avatar.setCurrentEnergy();
|
this.avatar.setCurrentEnergy();
|
||||||
|
|
||||||
if (getScene() != null) {
|
if (getScene() != null) {
|
||||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.AVATAR);
|
this.id = getScene().getWorld().getNextEntityId(EntityIdType.AVATAR);
|
||||||
|
|
||||||
var weapon = getAvatar().getWeapon();
|
var weapon = getAvatar().getWeapon();
|
||||||
if (weapon != null) {
|
if (weapon != null) {
|
||||||
weapon.setWeaponEntityId(getScene().getWorld().getNextEntityId(EntityIdType.WEAPON));
|
weapon.setWeaponEntityId(getScene().getWorld().getNextEntityId(EntityIdType.WEAPON));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getEntityTypeId() {
|
public int getEntityTypeId() {
|
||||||
return this.getAvatar().getAvatarId();
|
return this.getAvatar().getAvatarId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player getPlayer() {
|
public Player getPlayer() {
|
||||||
return this.avatar.getPlayer();
|
return this.avatar.getPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Position getPosition() {
|
public Position getPosition() {
|
||||||
return getPlayer().getPosition();
|
return getPlayer().getPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Position getRotation() {
|
public Position getRotation() {
|
||||||
return getPlayer().getRotation();
|
return getPlayer().getRotation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAlive() {
|
public boolean isAlive() {
|
||||||
return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f;
|
return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Int2FloatMap getFightProperties() {
|
public Int2FloatMap getFightProperties() {
|
||||||
return getAvatar().getFightProperties();
|
return getAvatar().getFightProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getWeaponEntityId() {
|
public int getWeaponEntityId() {
|
||||||
if (getAvatar().getWeapon() != null) {
|
if (getAvatar().getWeapon() != null) {
|
||||||
return getAvatar().getWeapon().getWeaponEntityId();
|
return getAvatar().getWeapon().getWeaponEntityId();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeath(int killerId) {
|
public void onDeath(int killerId) {
|
||||||
super.onDeath(killerId); // Invoke super class's onDeath() method.
|
super.onDeath(killerId); // Invoke super class's onDeath() method.
|
||||||
|
|
||||||
this.killedType = PlayerDieType.PLAYER_DIE_TYPE_KILL_BY_MONSTER;
|
this.killedType = PlayerDieType.PLAYER_DIE_TYPE_KILL_BY_MONSTER;
|
||||||
this.killedBy = killerId;
|
this.killedBy = killerId;
|
||||||
clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE);
|
clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onDeath(PlayerDieType dieType, int killerId) {
|
public void onDeath(PlayerDieType dieType, int killerId) {
|
||||||
super.onDeath(killerId); // Invoke super class's onDeath() method.
|
super.onDeath(killerId); // Invoke super class's onDeath() method.
|
||||||
|
|
||||||
this.killedType = dieType;
|
this.killedType = dieType;
|
||||||
this.killedBy = killerId;
|
this.killedBy = killerId;
|
||||||
clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE);
|
clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float heal(float amount) {
|
public float heal(float amount) {
|
||||||
// Do not heal character if they are dead
|
// Do not heal character if they are dead
|
||||||
if (!this.isAlive()) {
|
if (!this.isAlive()) {
|
||||||
return 0f;
|
return 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
float healed = super.heal(amount);
|
float healed = super.heal(amount);
|
||||||
|
|
||||||
if (healed > 0f) {
|
if (healed > 0f) {
|
||||||
getScene()
|
getScene()
|
||||||
.broadcastPacket(
|
.broadcastPacket(
|
||||||
new PacketEntityFightPropChangeReasonNotify(
|
new PacketEntityFightPropChangeReasonNotify(
|
||||||
this,
|
this,
|
||||||
FightProperty.FIGHT_PROP_CUR_HP,
|
FightProperty.FIGHT_PROP_CUR_HP,
|
||||||
healed,
|
healed,
|
||||||
PropChangeReason.PROP_CHANGE_REASON_ABILITY,
|
PropChangeReason.PROP_CHANGE_REASON_ABILITY,
|
||||||
ChangeHpReason.CHANGE_HP_REASON_ADD_ABILITY));
|
ChangeHpReason.CHANGE_HP_REASON_ADD_ABILITY));
|
||||||
}
|
}
|
||||||
|
|
||||||
return healed;
|
return healed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearEnergy(ChangeEnergyReason reason) {
|
public void clearEnergy(ChangeEnergyReason reason) {
|
||||||
// Fight props.
|
// Fight props.
|
||||||
val curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
val curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
||||||
float curEnergy = this.getFightProperty(curEnergyProp);
|
float curEnergy = this.getFightProperty(curEnergyProp);
|
||||||
|
|
||||||
// Set energy to zero.
|
// Set energy to zero.
|
||||||
this.avatar.setCurrentEnergy(curEnergyProp, 0);
|
this.avatar.setCurrentEnergy(curEnergyProp, 0);
|
||||||
|
|
||||||
// Send packets.
|
// Send packets.
|
||||||
this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, curEnergyProp));
|
this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, curEnergyProp));
|
||||||
|
|
||||||
if (reason == ChangeEnergyReason.CHANGE_ENERGY_REASON_SKILL_START) {
|
if (reason == ChangeEnergyReason.CHANGE_ENERGY_REASON_SKILL_START) {
|
||||||
this.getScene()
|
this.getScene()
|
||||||
.broadcastPacket(
|
.broadcastPacket(
|
||||||
new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, -curEnergy, reason));
|
new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, -curEnergy, reason));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a fixed amount of energy to the current avatar.
|
* Adds a fixed amount of energy to the current avatar.
|
||||||
*
|
*
|
||||||
* @param amount The amount of energy to add.
|
* @param amount The amount of energy to add.
|
||||||
* @return True if the energy was added, false if the energy was not added.
|
* @return True if the energy was added, false if the energy was not added.
|
||||||
*/
|
*/
|
||||||
public boolean addEnergy(float amount) {
|
public boolean addEnergy(float amount) {
|
||||||
var curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
var curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
||||||
var curEnergy = this.getFightProperty(curEnergyProp);
|
var curEnergy = this.getFightProperty(curEnergyProp);
|
||||||
if (curEnergy == amount) return false;
|
if (curEnergy == amount) return false;
|
||||||
|
|
||||||
this.getAvatar().setCurrentEnergy(curEnergyProp, amount);
|
this.getAvatar().setCurrentEnergy(curEnergyProp, amount);
|
||||||
this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, curEnergyProp));
|
this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, curEnergyProp));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEnergy(float amount, PropChangeReason reason) {
|
public void addEnergy(float amount, PropChangeReason reason) {
|
||||||
this.addEnergy(amount, reason, false);
|
this.addEnergy(amount, reason, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEnergy(float amount, PropChangeReason reason, boolean isFlat) {
|
public void addEnergy(float amount, PropChangeReason reason, boolean isFlat) {
|
||||||
// Get current and maximum energy for this avatar.
|
// Get current and maximum energy for this avatar.
|
||||||
val elementType = this.getAvatar().getSkillDepot().getElementType();
|
val elementType = this.getAvatar().getSkillDepot().getElementType();
|
||||||
val curEnergyProp = elementType.getCurEnergyProp();
|
val curEnergyProp = elementType.getCurEnergyProp();
|
||||||
val maxEnergyProp = elementType.getMaxEnergyProp();
|
val maxEnergyProp = elementType.getMaxEnergyProp();
|
||||||
|
|
||||||
float curEnergy = this.getFightProperty(curEnergyProp);
|
float curEnergy = this.getFightProperty(curEnergyProp);
|
||||||
float maxEnergy = this.getFightProperty(maxEnergyProp);
|
float maxEnergy = this.getFightProperty(maxEnergyProp);
|
||||||
|
|
||||||
// Scale amount by energy recharge, if the amount is not flat.
|
// Scale amount by energy recharge, if the amount is not flat.
|
||||||
if (!isFlat) {
|
if (!isFlat) {
|
||||||
amount *= this.getFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY);
|
amount *= this.getFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the new energy value.
|
// Determine the new energy value.
|
||||||
float newEnergy = Math.min(curEnergy + amount, maxEnergy);
|
float newEnergy = Math.min(curEnergy + amount, maxEnergy);
|
||||||
|
|
||||||
// Set energy and notify.
|
// Set energy and notify.
|
||||||
if (newEnergy != curEnergy) {
|
if (newEnergy != curEnergy) {
|
||||||
this.avatar.setCurrentEnergy(curEnergyProp, newEnergy);
|
this.avatar.setCurrentEnergy(curEnergyProp, newEnergy);
|
||||||
|
|
||||||
this.getScene()
|
this.getScene()
|
||||||
.broadcastPacket(new PacketAvatarFightPropUpdateNotify(this.getAvatar(), curEnergyProp));
|
.broadcastPacket(new PacketAvatarFightPropUpdateNotify(this.getAvatar(), curEnergyProp));
|
||||||
this.getScene()
|
this.getScene()
|
||||||
.broadcastPacket(
|
.broadcastPacket(
|
||||||
new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, newEnergy, reason));
|
new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, newEnergy, reason));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SceneAvatarInfo getSceneAvatarInfo() {
|
public SceneAvatarInfo getSceneAvatarInfo() {
|
||||||
val avatar = this.getAvatar();
|
val avatar = this.getAvatar();
|
||||||
val player = this.getPlayer();
|
val player = this.getPlayer();
|
||||||
SceneAvatarInfo.Builder avatarInfo =
|
SceneAvatarInfo.Builder avatarInfo =
|
||||||
SceneAvatarInfo.newBuilder()
|
SceneAvatarInfo.newBuilder()
|
||||||
.setUid(player.getUid())
|
.setUid(player.getUid())
|
||||||
.setAvatarId(avatar.getAvatarId())
|
.setAvatarId(avatar.getAvatarId())
|
||||||
.setGuid(avatar.getGuid())
|
.setGuid(avatar.getGuid())
|
||||||
.setPeerId(player.getPeerId())
|
.setPeerId(player.getPeerId())
|
||||||
.addAllTalentIdList(avatar.getTalentIdList())
|
.addAllTalentIdList(avatar.getTalentIdList())
|
||||||
.setCoreProudSkillLevel(avatar.getCoreProudSkillLevel())
|
.setCoreProudSkillLevel(avatar.getCoreProudSkillLevel())
|
||||||
.putAllSkillLevelMap(avatar.getSkillLevelMap())
|
.putAllSkillLevelMap(avatar.getSkillLevelMap())
|
||||||
.setSkillDepotId(avatar.getSkillDepotId())
|
.setSkillDepotId(avatar.getSkillDepotId())
|
||||||
.addAllInherentProudSkillList(avatar.getProudSkillList())
|
.addAllInherentProudSkillList(avatar.getProudSkillList())
|
||||||
.putAllProudSkillExtraLevelMap(avatar.getProudSkillBonusMap())
|
.putAllProudSkillExtraLevelMap(avatar.getProudSkillBonusMap())
|
||||||
.addAllTeamResonanceList(player.getTeamManager().getTeamResonances())
|
.addAllTeamResonanceList(player.getTeamManager().getTeamResonances())
|
||||||
.setWearingFlycloakId(avatar.getFlyCloak())
|
.setWearingFlycloakId(avatar.getFlyCloak())
|
||||||
.setCostumeId(avatar.getCostume())
|
.setCostumeId(avatar.getCostume())
|
||||||
.setBornTime(avatar.getBornTime());
|
.setBornTime(avatar.getBornTime());
|
||||||
|
|
||||||
for (GameItem item : avatar.getEquips().values()) {
|
for (GameItem item : avatar.getEquips().values()) {
|
||||||
if (item.getItemData().getEquipType() == EquipType.EQUIP_WEAPON) {
|
if (item.getItemData().getEquipType() == EquipType.EQUIP_WEAPON) {
|
||||||
avatarInfo.setWeapon(item.createSceneWeaponInfo());
|
avatarInfo.setWeapon(item.createSceneWeaponInfo());
|
||||||
} else {
|
} else {
|
||||||
avatarInfo.addReliquaryList(item.createSceneReliquaryInfo());
|
avatarInfo.addReliquaryList(item.createSceneReliquaryInfo());
|
||||||
}
|
}
|
||||||
avatarInfo.addEquipIdList(item.getItemId());
|
avatarInfo.addEquipIdList(item.getItemId());
|
||||||
}
|
}
|
||||||
|
|
||||||
return avatarInfo.build();
|
return avatarInfo.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SceneEntityInfo toProto() {
|
public SceneEntityInfo toProto() {
|
||||||
EntityAuthorityInfo authority =
|
EntityAuthorityInfo authority =
|
||||||
EntityAuthorityInfo.newBuilder()
|
EntityAuthorityInfo.newBuilder()
|
||||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||||
.setAiInfo(
|
.setAiInfo(
|
||||||
SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
|
SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
|
||||||
.setBornPos(Vector.newBuilder())
|
.setBornPos(Vector.newBuilder())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
SceneEntityInfo.Builder entityInfo =
|
SceneEntityInfo.Builder entityInfo =
|
||||||
SceneEntityInfo.newBuilder()
|
SceneEntityInfo.newBuilder()
|
||||||
.setEntityId(getId())
|
.setEntityId(getId())
|
||||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_AVATAR)
|
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_AVATAR)
|
||||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||||
.setEntityClientData(EntityClientData.newBuilder())
|
.setEntityClientData(EntityClientData.newBuilder())
|
||||||
.setEntityAuthorityInfo(authority)
|
.setEntityAuthorityInfo(authority)
|
||||||
.setLastMoveSceneTimeMs(this.getLastMoveSceneTimeMs())
|
.setLastMoveSceneTimeMs(this.getLastMoveSceneTimeMs())
|
||||||
.setLastMoveReliableSeq(this.getLastMoveReliableSeq())
|
.setLastMoveReliableSeq(this.getLastMoveReliableSeq())
|
||||||
.setLifeState(this.getLifeState().getValue());
|
.setLifeState(this.getLifeState().getValue());
|
||||||
|
|
||||||
if (this.getScene() != null) {
|
if (this.getScene() != null) {
|
||||||
entityInfo.setMotionInfo(this.getMotionInfo());
|
entityInfo.setMotionInfo(this.getMotionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addAllFightPropsToEntityInfo(entityInfo);
|
this.addAllFightPropsToEntityInfo(entityInfo);
|
||||||
|
|
||||||
PropPair pair =
|
PropPair pair =
|
||||||
PropPair.newBuilder()
|
PropPair.newBuilder()
|
||||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||||
.setPropValue(
|
.setPropValue(
|
||||||
ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getAvatar().getLevel()))
|
ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getAvatar().getLevel()))
|
||||||
.build();
|
.build();
|
||||||
entityInfo.addPropList(pair);
|
entityInfo.addPropList(pair);
|
||||||
|
|
||||||
entityInfo.setAvatar(this.getSceneAvatarInfo());
|
entityInfo.setAvatar(this.getSceneAvatarInfo());
|
||||||
|
|
||||||
return entityInfo.build();
|
return entityInfo.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public AbilityControlBlock getAbilityControlBlock() {
|
public AbilityControlBlock getAbilityControlBlock() {
|
||||||
AvatarData data = this.getAvatar().getAvatarData();
|
AvatarData data = this.getAvatar().getAvatarData();
|
||||||
AbilityControlBlock.Builder abilityControlBlock = AbilityControlBlock.newBuilder();
|
AbilityControlBlock.Builder abilityControlBlock = AbilityControlBlock.newBuilder();
|
||||||
int embryoId = 0;
|
int embryoId = 0;
|
||||||
|
|
||||||
// Add avatar abilities
|
// Add avatar abilities
|
||||||
if (data.getAbilities() != null) {
|
if (data.getAbilities() != null) {
|
||||||
for (int id : data.getAbilities()) {
|
for (int id : data.getAbilities()) {
|
||||||
AbilityEmbryo emb =
|
AbilityEmbryo emb =
|
||||||
AbilityEmbryo.newBuilder()
|
AbilityEmbryo.newBuilder()
|
||||||
.setAbilityId(++embryoId)
|
.setAbilityId(++embryoId)
|
||||||
.setAbilityNameHash(id)
|
.setAbilityNameHash(id)
|
||||||
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
||||||
.build();
|
.build();
|
||||||
abilityControlBlock.addAbilityEmbryoList(emb);
|
abilityControlBlock.addAbilityEmbryoList(emb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add default abilities
|
// Add default abilities
|
||||||
for (int id : GameConstants.DEFAULT_ABILITY_HASHES) {
|
for (int id : GameConstants.DEFAULT_ABILITY_HASHES) {
|
||||||
AbilityEmbryo emb =
|
AbilityEmbryo emb =
|
||||||
AbilityEmbryo.newBuilder()
|
AbilityEmbryo.newBuilder()
|
||||||
.setAbilityId(++embryoId)
|
.setAbilityId(++embryoId)
|
||||||
.setAbilityNameHash(id)
|
.setAbilityNameHash(id)
|
||||||
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
||||||
.build();
|
.build();
|
||||||
abilityControlBlock.addAbilityEmbryoList(emb);
|
abilityControlBlock.addAbilityEmbryoList(emb);
|
||||||
}
|
}
|
||||||
// Add team resonances
|
// Add team resonances
|
||||||
for (int id : this.getPlayer().getTeamManager().getTeamResonancesConfig()) {
|
for (int id : this.getPlayer().getTeamManager().getTeamResonancesConfig()) {
|
||||||
AbilityEmbryo emb =
|
AbilityEmbryo emb =
|
||||||
AbilityEmbryo.newBuilder()
|
AbilityEmbryo.newBuilder()
|
||||||
.setAbilityId(++embryoId)
|
.setAbilityId(++embryoId)
|
||||||
.setAbilityNameHash(id)
|
.setAbilityNameHash(id)
|
||||||
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
||||||
.build();
|
.build();
|
||||||
abilityControlBlock.addAbilityEmbryoList(emb);
|
abilityControlBlock.addAbilityEmbryoList(emb);
|
||||||
}
|
}
|
||||||
// Add skill depot abilities
|
// Add skill depot abilities
|
||||||
AvatarSkillDepotData skillDepot =
|
AvatarSkillDepotData skillDepot =
|
||||||
GameData.getAvatarSkillDepotDataMap().get(this.getAvatar().getSkillDepotId());
|
GameData.getAvatarSkillDepotDataMap().get(this.getAvatar().getSkillDepotId());
|
||||||
if (skillDepot != null && skillDepot.getAbilities() != null) {
|
if (skillDepot != null && skillDepot.getAbilities() != null) {
|
||||||
for (int id : skillDepot.getAbilities()) {
|
for (int id : skillDepot.getAbilities()) {
|
||||||
AbilityEmbryo emb =
|
AbilityEmbryo emb =
|
||||||
AbilityEmbryo.newBuilder()
|
AbilityEmbryo.newBuilder()
|
||||||
.setAbilityId(++embryoId)
|
.setAbilityId(++embryoId)
|
||||||
.setAbilityNameHash(id)
|
.setAbilityNameHash(id)
|
||||||
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
||||||
.build();
|
.build();
|
||||||
abilityControlBlock.addAbilityEmbryoList(emb);
|
abilityControlBlock.addAbilityEmbryoList(emb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add equip abilities
|
// Add equip abilities
|
||||||
if (this.getAvatar().getExtraAbilityEmbryos().size() > 0) {
|
if (this.getAvatar().getExtraAbilityEmbryos().size() > 0) {
|
||||||
for (String skill : this.getAvatar().getExtraAbilityEmbryos()) {
|
for (String skill : this.getAvatar().getExtraAbilityEmbryos()) {
|
||||||
AbilityEmbryo emb =
|
AbilityEmbryo emb =
|
||||||
AbilityEmbryo.newBuilder()
|
AbilityEmbryo.newBuilder()
|
||||||
.setAbilityId(++embryoId)
|
.setAbilityId(++embryoId)
|
||||||
.setAbilityNameHash(Utils.abilityHash(skill))
|
.setAbilityNameHash(Utils.abilityHash(skill))
|
||||||
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
.setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME)
|
||||||
.build();
|
.build();
|
||||||
abilityControlBlock.addAbilityEmbryoList(emb);
|
abilityControlBlock.addAbilityEmbryoList(emb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
return abilityControlBlock.build();
|
return abilityControlBlock.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move this entity to a new position. Additionally invoke player move event.
|
* Move this entity to a new position. Additionally invoke player move event.
|
||||||
*
|
*
|
||||||
* @param newPosition The new position.
|
* @param newPosition The new position.
|
||||||
* @param rotation The new rotation.
|
* @param rotation The new rotation.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void move(Position newPosition, Position rotation) {
|
public void move(Position newPosition, Position rotation) {
|
||||||
// Invoke player move event.
|
// Invoke player move event.
|
||||||
PlayerMoveEvent event =
|
PlayerMoveEvent event =
|
||||||
new PlayerMoveEvent(
|
new PlayerMoveEvent(
|
||||||
this.getPlayer(), PlayerMoveEvent.MoveType.PLAYER, this.getPosition(), newPosition);
|
this.getPlayer(), PlayerMoveEvent.MoveType.PLAYER, this.getPosition(), newPosition);
|
||||||
event.call();
|
event.call();
|
||||||
|
|
||||||
// Set position and rotation.
|
// Set position and rotation.
|
||||||
super.move(event.getDestination(), rotation);
|
super.move(event.getDestination(), rotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,63 +1,63 @@
|
|||||||
package emu.grasscutter.game.entity;
|
package emu.grasscutter.game.entity;
|
||||||
|
|
||||||
import emu.grasscutter.data.binout.config.ConfigEntityGadget;
|
import emu.grasscutter.data.binout.config.ConfigEntityGadget;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
public abstract class EntityBaseGadget extends GameEntity {
|
public abstract class EntityBaseGadget extends GameEntity {
|
||||||
@Getter(onMethod_ = @Override)
|
@Getter(onMethod_ = @Override)
|
||||||
protected final Position position;
|
protected final Position position;
|
||||||
|
|
||||||
@Getter(onMethod_ = @Override)
|
@Getter(onMethod_ = @Override)
|
||||||
protected final Position rotation;
|
protected final Position rotation;
|
||||||
|
|
||||||
public EntityBaseGadget(Scene scene) {
|
public EntityBaseGadget(Scene scene) {
|
||||||
this(scene, null, null);
|
this(scene, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityBaseGadget(Scene scene, Position position, Position rotation) {
|
public EntityBaseGadget(Scene scene, Position position, Position rotation) {
|
||||||
super(scene);
|
super(scene);
|
||||||
this.position = position != null ? position.clone() : new Position();
|
this.position = position != null ? position.clone() : new Position();
|
||||||
this.rotation = rotation != null ? rotation.clone() : new Position();
|
this.rotation = rotation != null ? rotation.clone() : new Position();
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract int getGadgetId();
|
public abstract int getGadgetId();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getEntityTypeId() {
|
public int getEntityTypeId() {
|
||||||
return this.getGadgetId();
|
return this.getGadgetId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeath(int killerId) {
|
public void onDeath(int killerId) {
|
||||||
super.onDeath(killerId); // Invoke super class's onDeath() method.
|
super.onDeath(killerId); // Invoke super class's onDeath() method.
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void fillFightProps(ConfigEntityGadget configGadget) {
|
protected void fillFightProps(ConfigEntityGadget configGadget) {
|
||||||
if (configGadget == null || configGadget.getCombat() == null) {
|
if (configGadget == null || configGadget.getCombat() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var combatData = configGadget.getCombat();
|
var combatData = configGadget.getCombat();
|
||||||
var combatProperties = combatData.getProperty();
|
var combatProperties = combatData.getProperty();
|
||||||
|
|
||||||
var targetHp = combatProperties.getHP();
|
var targetHp = combatProperties.getHP();
|
||||||
setFightProperty(FightProperty.FIGHT_PROP_MAX_HP, targetHp);
|
setFightProperty(FightProperty.FIGHT_PROP_MAX_HP, targetHp);
|
||||||
setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, targetHp);
|
setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, targetHp);
|
||||||
if (combatProperties.isInvincible()) {
|
if (combatProperties.isInvincible()) {
|
||||||
targetHp = Float.POSITIVE_INFINITY;
|
targetHp = Float.POSITIVE_INFINITY;
|
||||||
}
|
}
|
||||||
setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, targetHp);
|
setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, targetHp);
|
||||||
|
|
||||||
var atk = combatProperties.getAttack();
|
var atk = combatProperties.getAttack();
|
||||||
setFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK, atk);
|
setFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK, atk);
|
||||||
setFightProperty(FightProperty.FIGHT_PROP_CUR_ATTACK, atk);
|
setFightProperty(FightProperty.FIGHT_PROP_CUR_ATTACK, atk);
|
||||||
|
|
||||||
var def = combatProperties.getDefence();
|
var def = combatProperties.getDefence();
|
||||||
setFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE, def);
|
setFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE, def);
|
||||||
setFightProperty(FightProperty.FIGHT_PROP_CUR_DEFENSE, def);
|
setFightProperty(FightProperty.FIGHT_PROP_CUR_DEFENSE, def);
|
||||||
|
|
||||||
setLockHP(combatProperties.isLockHP());
|
setLockHP(combatProperties.isLockHP());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,281 +1,308 @@
|
|||||||
package emu.grasscutter.game.entity;
|
package emu.grasscutter.game.entity;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.binout.config.ConfigEntityGadget;
|
import emu.grasscutter.data.binout.config.ConfigEntityGadget;
|
||||||
import emu.grasscutter.data.excels.GadgetData;
|
import emu.grasscutter.data.excels.GadgetData;
|
||||||
import emu.grasscutter.game.entity.gadget.*;
|
import emu.grasscutter.game.entity.gadget.*;
|
||||||
import emu.grasscutter.game.entity.gadget.platform.BaseRoute;
|
import emu.grasscutter.game.entity.gadget.platform.BaseRoute;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.EntityIdType;
|
import emu.grasscutter.game.props.EntityIdType;
|
||||||
import emu.grasscutter.game.props.PlayerProperty;
|
import emu.grasscutter.game.props.PlayerProperty;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.game.world.SceneGroupInstance;
|
import emu.grasscutter.game.world.SceneGroupInstance;
|
||||||
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.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.GadgetInteractReqOuterClass.GadgetInteractReq;
|
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
||||||
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
||||||
import emu.grasscutter.net.proto.PlatformInfoOuterClass;
|
import emu.grasscutter.net.proto.PlatformInfoOuterClass;
|
||||||
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.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.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||||
import emu.grasscutter.net.proto.VisionTypeOuterClass;
|
import emu.grasscutter.net.proto.VisionTypeOuterClass;
|
||||||
import emu.grasscutter.scripts.EntityControllerScriptManager;
|
import emu.grasscutter.scripts.EntityControllerScriptManager;
|
||||||
import emu.grasscutter.scripts.constants.EventType;
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
import emu.grasscutter.scripts.data.SceneGadget;
|
import emu.grasscutter.scripts.data.SceneGadget;
|
||||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||||
import emu.grasscutter.server.packet.send.PacketGadgetStateNotify;
|
import emu.grasscutter.server.packet.send.PacketGadgetStateNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketPlatformStartRouteNotify;
|
import emu.grasscutter.server.packet.send.PacketPlatformStartRouteNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketPlatformStopRouteNotify;
|
import emu.grasscutter.server.packet.send.PacketPlatformStopRouteNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketSceneTimeNotify;
|
import emu.grasscutter.server.packet.send.PacketSceneTimeNotify;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import emu.grasscutter.utils.ProtoHelper;
|
import emu.grasscutter.utils.ProtoHelper;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||||
import lombok.Getter;
|
import java.util.ArrayList;
|
||||||
import lombok.Setter;
|
import java.util.List;
|
||||||
import lombok.ToString;
|
import javax.annotation.Nullable;
|
||||||
|
import lombok.Getter;
|
||||||
import javax.annotation.Nullable;
|
import lombok.Setter;
|
||||||
import java.util.ArrayList;
|
import lombok.ToString;
|
||||||
import java.util.List;
|
|
||||||
|
@ToString(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
public class EntityGadget extends EntityBaseGadget {
|
||||||
public class EntityGadget extends EntityBaseGadget {
|
@Getter private final GadgetData gadgetData;
|
||||||
@Getter private final GadgetData gadgetData;
|
|
||||||
@Getter(onMethod = @__(@Override)) @Setter
|
@Getter(onMethod = @__(@Override))
|
||||||
private int gadgetId;
|
@Setter
|
||||||
@Getter private final Position bornPos;
|
private int gadgetId;
|
||||||
@Getter private final Position bornRot;
|
|
||||||
@Getter @Setter private GameEntity owner = null;
|
@Getter private final Position bornPos;
|
||||||
@Getter @Setter private List<GameEntity> children = new ArrayList<>();
|
@Getter private final Position bornRot;
|
||||||
|
@Getter @Setter private GameEntity owner = null;
|
||||||
@Getter private int state;
|
@Getter @Setter private List<GameEntity> children = new ArrayList<>();
|
||||||
@Getter @Setter private int pointType;
|
|
||||||
@Getter private GadgetContent content;
|
@Getter private int state;
|
||||||
@Getter(onMethod = @__(@Override), lazy = true)
|
@Getter @Setter private int pointType;
|
||||||
private final Int2FloatMap fightProperties = new Int2FloatOpenHashMap();
|
@Getter private GadgetContent content;
|
||||||
@Getter @Setter private SceneGadget metaGadget;
|
|
||||||
@Nullable @Getter
|
@Getter(onMethod = @__(@Override), lazy = true)
|
||||||
private ConfigEntityGadget configGadget;
|
private final Int2FloatMap fightProperties = new Int2FloatOpenHashMap();
|
||||||
@Getter @Setter private BaseRoute routeConfig;
|
|
||||||
|
@Getter @Setter private SceneGadget metaGadget;
|
||||||
@Getter @Setter private int stopValue = 0; //Controller related, inited to zero
|
@Nullable @Getter private ConfigEntityGadget configGadget;
|
||||||
@Getter @Setter private int startValue = 0; //Controller related, inited to zero
|
@Getter @Setter private BaseRoute routeConfig;
|
||||||
@Getter @Setter private int ticksSinceChange;
|
|
||||||
|
@Getter @Setter private int stopValue = 0; // Controller related, inited to zero
|
||||||
|
@Getter @Setter private int startValue = 0; // Controller related, inited to zero
|
||||||
public EntityGadget(Scene scene, int gadgetId, Position pos) {
|
@Getter @Setter private int ticksSinceChange;
|
||||||
this(scene, gadgetId, pos, null, null);
|
|
||||||
}
|
public EntityGadget(Scene scene, int gadgetId, Position pos) {
|
||||||
|
this(scene, gadgetId, pos, null, null);
|
||||||
public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot) {
|
}
|
||||||
this(scene, gadgetId, pos, rot, null);
|
|
||||||
}
|
public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot) {
|
||||||
|
this(scene, gadgetId, pos, rot, null);
|
||||||
public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot, GadgetContent content) {
|
}
|
||||||
super(scene, pos, rot);
|
|
||||||
|
public EntityGadget(
|
||||||
this.gadgetData = GameData.getGadgetDataMap().get(gadgetId);
|
Scene scene, int gadgetId, Position pos, Position rot, GadgetContent content) {
|
||||||
if (gadgetData != null && gadgetData.getJsonName() != null) {
|
super(scene, pos, rot);
|
||||||
this.configGadget = GameData.getGadgetConfigData().get(gadgetData.getJsonName());
|
|
||||||
}
|
this.gadgetData = GameData.getGadgetDataMap().get(gadgetId);
|
||||||
|
if (gadgetData != null && gadgetData.getJsonName() != null) {
|
||||||
this.id = this.getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
this.configGadget = GameData.getGadgetConfigData().get(gadgetData.getJsonName());
|
||||||
this.gadgetId = gadgetId;
|
}
|
||||||
this.content = content;
|
|
||||||
this.bornPos = this.getPosition().clone();
|
this.id = this.getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||||
this.bornRot = this.getRotation().clone();
|
this.gadgetId = gadgetId;
|
||||||
this.fillFightProps(configGadget);
|
this.content = content;
|
||||||
|
this.bornPos = this.getPosition().clone();
|
||||||
if(GameData.getGadgetMappingMap().containsKey(gadgetId)) {
|
this.bornRot = this.getRotation().clone();
|
||||||
String controllerName = GameData.getGadgetMappingMap().get(gadgetId).getServerController();
|
this.fillFightProps(configGadget);
|
||||||
this.setEntityController(EntityControllerScriptManager.getGadgetController(controllerName));
|
|
||||||
}
|
if (GameData.getGadgetMappingMap().containsKey(gadgetId)) {
|
||||||
}
|
String controllerName = GameData.getGadgetMappingMap().get(gadgetId).getServerController();
|
||||||
|
this.setEntityController(EntityControllerScriptManager.getGadgetController(controllerName));
|
||||||
public void setState(int state) {
|
}
|
||||||
this.state = state;
|
}
|
||||||
//Cache the gadget state
|
|
||||||
if(metaGadget != null && metaGadget.group != null) {
|
public void setState(int state) {
|
||||||
var instance = getScene().getScriptManager().getCachedGroupInstanceById(metaGadget.group.id);
|
this.state = state;
|
||||||
if(instance != null) instance.cacheGadgetState(metaGadget, state);
|
// Cache the gadget state
|
||||||
}
|
if (metaGadget != null && metaGadget.group != null) {
|
||||||
}
|
var instance = getScene().getScriptManager().getCachedGroupInstanceById(metaGadget.group.id);
|
||||||
|
if (instance != null) instance.cacheGadgetState(metaGadget, state);
|
||||||
public void updateState(int state) {
|
}
|
||||||
if(state == this.getState()) return; //Don't triggers events
|
}
|
||||||
|
|
||||||
this.setState(state);
|
public void updateState(int state) {
|
||||||
ticksSinceChange = getScene().getSceneTimeSeconds();
|
if (state == this.getState()) return; // Don't triggers events
|
||||||
this.getScene().broadcastPacket(new PacketGadgetStateNotify(this, state));
|
|
||||||
getScene().getScriptManager().callEvent(new ScriptArgs(this.getGroupId(), EventType.EVENT_GADGET_STATE_CHANGE, state, this.getConfigId()));
|
this.setState(state);
|
||||||
}
|
ticksSinceChange = getScene().getSceneTimeSeconds();
|
||||||
|
this.getScene().broadcastPacket(new PacketGadgetStateNotify(this, state));
|
||||||
@Deprecated(forRemoval = true) // Dont use!
|
getScene()
|
||||||
public void setContent(GadgetContent content) {
|
.getScriptManager()
|
||||||
this.content = this.content == null ? content : this.content;
|
.callEvent(
|
||||||
}
|
new ScriptArgs(
|
||||||
|
this.getGroupId(), EventType.EVENT_GADGET_STATE_CHANGE, state, this.getConfigId()));
|
||||||
// TODO refactor
|
}
|
||||||
public void buildContent() {
|
|
||||||
if (this.getContent() != null || this.getGadgetData() == null || this.getGadgetData().getType() == null) {
|
@Deprecated(forRemoval = true) // Dont use!
|
||||||
return;
|
public void setContent(GadgetContent content) {
|
||||||
}
|
this.content = this.content == null ? content : this.content;
|
||||||
|
}
|
||||||
this.content = switch (this.getGadgetData().getType()) {
|
|
||||||
case GatherPoint -> new GadgetGatherPoint(this);
|
// TODO refactor
|
||||||
case GatherObject -> new GadgetGatherObject(this);
|
public void buildContent() {
|
||||||
case Worktop, SealGadget -> new GadgetWorktop(this);
|
if (this.getContent() != null
|
||||||
case RewardStatue -> new GadgetRewardStatue(this);
|
|| this.getGadgetData() == null
|
||||||
case Chest -> new GadgetChest(this);
|
|| this.getGadgetData().getType() == null) {
|
||||||
case Gadget -> new GadgetObject(this);
|
return;
|
||||||
default -> null;
|
}
|
||||||
};
|
|
||||||
}
|
this.content =
|
||||||
|
switch (this.getGadgetData().getType()) {
|
||||||
@Override
|
case GatherPoint -> new GadgetGatherPoint(this);
|
||||||
public void onInteract(Player player, GadgetInteractReq interactReq) {
|
case GatherObject -> new GadgetGatherObject(this);
|
||||||
if (this.getContent() == null) {
|
case Worktop, SealGadget -> new GadgetWorktop(this);
|
||||||
return;
|
case RewardStatue -> new GadgetRewardStatue(this);
|
||||||
}
|
case Chest -> new GadgetChest(this);
|
||||||
|
case Gadget -> new GadgetObject(this);
|
||||||
boolean shouldDelete = this.getContent().onInteract(player, interactReq);
|
default -> null;
|
||||||
|
};
|
||||||
if (shouldDelete) {
|
}
|
||||||
this.getScene().killEntity(this);
|
|
||||||
}
|
@Override
|
||||||
}
|
public void onInteract(Player player, GadgetInteractReq interactReq) {
|
||||||
|
if (this.getContent() == null) {
|
||||||
@Override
|
return;
|
||||||
public void onCreate() {
|
}
|
||||||
// Lua event
|
|
||||||
getScene().getScriptManager().callEvent(new ScriptArgs(this.getGroupId(), EventType.EVENT_GADGET_CREATE, this.getConfigId()));
|
boolean shouldDelete = this.getContent().onInteract(player, interactReq);
|
||||||
}
|
|
||||||
|
if (shouldDelete) {
|
||||||
@Override
|
this.getScene().killEntity(this);
|
||||||
public void onRemoved() {
|
}
|
||||||
super.onRemoved();
|
}
|
||||||
if(!children.isEmpty()) {
|
|
||||||
getScene().removeEntities(children, VisionTypeOuterClass.VisionType.VISION_TYPE_REMOVE);
|
@Override
|
||||||
children.clear();
|
public void onCreate() {
|
||||||
}
|
// Lua event
|
||||||
}
|
getScene()
|
||||||
|
.getScriptManager()
|
||||||
@Override
|
.callEvent(
|
||||||
public void onDeath(int killerId) {
|
new ScriptArgs(this.getGroupId(), EventType.EVENT_GADGET_CREATE, this.getConfigId()));
|
||||||
super.onDeath(killerId); // Invoke super class's onDeath() method.
|
}
|
||||||
|
|
||||||
if (this.getSpawnEntry() != null) {
|
@Override
|
||||||
this.getScene().getDeadSpawnedEntities().add(getSpawnEntry());
|
public void onRemoved() {
|
||||||
}
|
super.onRemoved();
|
||||||
if (getScene().getChallenge() != null) {
|
if (!children.isEmpty()) {
|
||||||
getScene().getChallenge().onGadgetDeath(this);
|
getScene().removeEntities(children, VisionTypeOuterClass.VisionType.VISION_TYPE_REMOVE);
|
||||||
}
|
children.clear();
|
||||||
getScene().getScriptManager().callEvent(new ScriptArgs(this.getGroupId(), EventType.EVENT_ANY_GADGET_DIE, this.getConfigId()));
|
}
|
||||||
|
}
|
||||||
SceneGroupInstance groupInstance = getScene().getScriptManager().getCachedGroupInstanceById(this.getGroupId());
|
|
||||||
if(groupInstance != null && metaGadget != null)
|
@Override
|
||||||
groupInstance.getDeadEntities().add(metaGadget.config_id);
|
public void onDeath(int killerId) {
|
||||||
}
|
super.onDeath(killerId); // Invoke super class's onDeath() method.
|
||||||
|
|
||||||
public boolean startPlatform(){
|
if (this.getSpawnEntry() != null) {
|
||||||
if(routeConfig == null){
|
this.getScene().getDeadSpawnedEntities().add(getSpawnEntry());
|
||||||
return false;
|
}
|
||||||
}
|
if (getScene().getChallenge() != null) {
|
||||||
|
getScene().getChallenge().onGadgetDeath(this);
|
||||||
if(routeConfig.isStarted()){
|
}
|
||||||
return true;
|
getScene()
|
||||||
}
|
.getScriptManager()
|
||||||
getScene().broadcastPacket(new PacketSceneTimeNotify(getScene()));
|
.callEvent(
|
||||||
routeConfig.startRoute(getScene());
|
new ScriptArgs(this.getGroupId(), EventType.EVENT_ANY_GADGET_DIE, this.getConfigId()));
|
||||||
getScene().broadcastPacket(new PacketPlatformStartRouteNotify(this));
|
|
||||||
|
SceneGroupInstance groupInstance =
|
||||||
return true;
|
getScene().getScriptManager().getCachedGroupInstanceById(this.getGroupId());
|
||||||
}
|
if (groupInstance != null && metaGadget != null)
|
||||||
|
groupInstance.getDeadEntities().add(metaGadget.config_id);
|
||||||
public boolean stopPlatform(){
|
}
|
||||||
if(routeConfig == null){
|
|
||||||
return false;
|
public boolean startPlatform() {
|
||||||
}
|
if (routeConfig == null) {
|
||||||
|
return false;
|
||||||
if(!routeConfig.isStarted()){
|
}
|
||||||
return true;
|
|
||||||
}
|
if (routeConfig.isStarted()) {
|
||||||
routeConfig.stopRoute(getScene());
|
return true;
|
||||||
getScene().broadcastPacket(new PacketPlatformStopRouteNotify(this));
|
}
|
||||||
|
getScene().broadcastPacket(new PacketSceneTimeNotify(getScene()));
|
||||||
return true;
|
routeConfig.startRoute(getScene());
|
||||||
}
|
getScene().broadcastPacket(new PacketPlatformStartRouteNotify(this));
|
||||||
|
|
||||||
@Override
|
return true;
|
||||||
public SceneEntityInfo toProto() {
|
}
|
||||||
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
|
||||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
public boolean stopPlatform() {
|
||||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
if (routeConfig == null) {
|
||||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(bornPos.toProto()))
|
return false;
|
||||||
.setBornPos(bornPos.toProto())
|
}
|
||||||
.build();
|
|
||||||
|
if (!routeConfig.isStarted()) {
|
||||||
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
return true;
|
||||||
.setEntityId(getId())
|
}
|
||||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
routeConfig.stopRoute(getScene());
|
||||||
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
|
getScene().broadcastPacket(new PacketPlatformStopRouteNotify(this));
|
||||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
|
||||||
.setEntityClientData(EntityClientData.newBuilder())
|
return true;
|
||||||
.setEntityAuthorityInfo(authority)
|
}
|
||||||
.setLifeState(1);
|
|
||||||
|
@Override
|
||||||
PropPair pair = PropPair.newBuilder()
|
public SceneEntityInfo toProto() {
|
||||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
EntityAuthorityInfo authority =
|
||||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
|
EntityAuthorityInfo.newBuilder()
|
||||||
.build();
|
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||||
entityInfo.addPropList(pair);
|
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||||
|
.setAiInfo(
|
||||||
// We do not use the getter to null check because the getter will create a fight prop map if it is null
|
SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(bornPos.toProto()))
|
||||||
if (this.fightProperties != null) {
|
.setBornPos(bornPos.toProto())
|
||||||
addAllFightPropsToEntityInfo(entityInfo);
|
.build();
|
||||||
}
|
|
||||||
|
SceneEntityInfo.Builder entityInfo =
|
||||||
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
|
SceneEntityInfo.newBuilder()
|
||||||
.setGadgetId(this.getGadgetId())
|
.setEntityId(getId())
|
||||||
.setGroupId(this.getGroupId())
|
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
||||||
.setConfigId(this.getConfigId())
|
.setMotionInfo(
|
||||||
.setGadgetState(this.getState())
|
MotionInfo.newBuilder()
|
||||||
.setIsEnableInteract(true)
|
.setPos(getPosition().toProto())
|
||||||
.setAuthorityPeerId(this.getScene().getWorld().getHostPeerId());
|
.setRot(getRotation().toProto())
|
||||||
|
.setSpeed(Vector.newBuilder()))
|
||||||
if (this.metaGadget != null) {
|
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||||
gadgetInfo.setDraftId(this.metaGadget.draft_id);
|
.setEntityClientData(EntityClientData.newBuilder())
|
||||||
}
|
.setEntityAuthorityInfo(authority)
|
||||||
|
.setLifeState(1);
|
||||||
if(owner != null){
|
|
||||||
gadgetInfo.setOwnerEntityId(owner.getId());
|
PropPair pair =
|
||||||
}
|
PropPair.newBuilder()
|
||||||
|
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||||
if (this.getContent() != null) {
|
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
|
||||||
this.getContent().onBuildProto(gadgetInfo);
|
.build();
|
||||||
}
|
entityInfo.addPropList(pair);
|
||||||
|
|
||||||
if(routeConfig!=null){
|
// We do not use the getter to null check because the getter will create a fight prop map if it
|
||||||
gadgetInfo.setPlatform(getPlatformInfo());
|
// is null
|
||||||
}
|
if (this.fightProperties != null) {
|
||||||
|
addAllFightPropsToEntityInfo(entityInfo);
|
||||||
entityInfo.setGadget(gadgetInfo);
|
}
|
||||||
|
|
||||||
return entityInfo.build();
|
SceneGadgetInfo.Builder gadgetInfo =
|
||||||
}
|
SceneGadgetInfo.newBuilder()
|
||||||
|
.setGadgetId(this.getGadgetId())
|
||||||
public PlatformInfoOuterClass.PlatformInfo.Builder getPlatformInfo(){
|
.setGroupId(this.getGroupId())
|
||||||
if(routeConfig != null){
|
.setConfigId(this.getConfigId())
|
||||||
return routeConfig.toProto();
|
.setGadgetState(this.getState())
|
||||||
}
|
.setIsEnableInteract(true)
|
||||||
|
.setAuthorityPeerId(this.getScene().getWorld().getHostPeerId());
|
||||||
return PlatformInfoOuterClass.PlatformInfo.newBuilder();
|
|
||||||
}
|
if (this.metaGadget != null) {
|
||||||
}
|
gadgetInfo.setDraftId(this.metaGadget.draft_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (owner != null) {
|
||||||
|
gadgetInfo.setOwnerEntityId(owner.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.getContent() != null) {
|
||||||
|
this.getContent().onBuildProto(gadgetInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routeConfig != null) {
|
||||||
|
gadgetInfo.setPlatform(getPlatformInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
entityInfo.setGadget(gadgetInfo);
|
||||||
|
|
||||||
|
return entityInfo.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlatformInfoOuterClass.PlatformInfo.Builder getPlatformInfo() {
|
||||||
|
if (routeConfig != null) {
|
||||||
|
return routeConfig.toProto();
|
||||||
|
}
|
||||||
|
|
||||||
|
return PlatformInfoOuterClass.PlatformInfo.newBuilder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,82 +1,82 @@
|
|||||||
package emu.grasscutter.game.entity;
|
package emu.grasscutter.game.entity;
|
||||||
|
|
||||||
import emu.grasscutter.game.props.EntityIdType;
|
import emu.grasscutter.game.props.EntityIdType;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.net.proto.*;
|
import emu.grasscutter.net.proto.*;
|
||||||
import emu.grasscutter.scripts.data.SceneNPC;
|
import emu.grasscutter.scripts.data.SceneNPC;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
public class EntityNPC extends GameEntity {
|
public class EntityNPC extends GameEntity {
|
||||||
@Getter(onMethod_ = @Override)
|
@Getter(onMethod_ = @Override)
|
||||||
private final Position position;
|
private final Position position;
|
||||||
|
|
||||||
@Getter(onMethod_ = @Override)
|
@Getter(onMethod_ = @Override)
|
||||||
private final Position rotation;
|
private final Position rotation;
|
||||||
|
|
||||||
private final SceneNPC metaNpc;
|
private final SceneNPC metaNpc;
|
||||||
@Getter private final int suiteId;
|
@Getter private final int suiteId;
|
||||||
|
|
||||||
public EntityNPC(Scene scene, SceneNPC metaNPC, int blockId, int suiteId) {
|
public EntityNPC(Scene scene, SceneNPC metaNPC, int blockId, int suiteId) {
|
||||||
super(scene);
|
super(scene);
|
||||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.NPC);
|
this.id = getScene().getWorld().getNextEntityId(EntityIdType.NPC);
|
||||||
setConfigId(metaNPC.config_id);
|
setConfigId(metaNPC.config_id);
|
||||||
setGroupId(metaNPC.group.id);
|
setGroupId(metaNPC.group.id);
|
||||||
setBlockId(blockId);
|
setBlockId(blockId);
|
||||||
this.suiteId = suiteId;
|
this.suiteId = suiteId;
|
||||||
this.position = metaNPC.pos.clone();
|
this.position = metaNPC.pos.clone();
|
||||||
this.rotation = metaNPC.rot.clone();
|
this.rotation = metaNPC.rot.clone();
|
||||||
this.metaNpc = metaNPC;
|
this.metaNpc = metaNPC;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getEntityTypeId() {
|
public int getEntityTypeId() {
|
||||||
return this.metaNpc.npc_id;
|
return this.metaNpc.npc_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Int2FloatMap getFightProperties() {
|
public Int2FloatMap getFightProperties() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SceneEntityInfoOuterClass.SceneEntityInfo toProto() {
|
public SceneEntityInfoOuterClass.SceneEntityInfo toProto() {
|
||||||
|
|
||||||
EntityAuthorityInfoOuterClass.EntityAuthorityInfo authority =
|
EntityAuthorityInfoOuterClass.EntityAuthorityInfo authority =
|
||||||
EntityAuthorityInfoOuterClass.EntityAuthorityInfo.newBuilder()
|
EntityAuthorityInfoOuterClass.EntityAuthorityInfo.newBuilder()
|
||||||
.setAbilityInfo(AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo.newBuilder())
|
.setAbilityInfo(AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo.newBuilder())
|
||||||
.setRendererChangedInfo(
|
.setRendererChangedInfo(
|
||||||
EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo.newBuilder())
|
EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo.newBuilder())
|
||||||
.setAiInfo(
|
.setAiInfo(
|
||||||
SceneEntityAiInfoOuterClass.SceneEntityAiInfo.newBuilder()
|
SceneEntityAiInfoOuterClass.SceneEntityAiInfo.newBuilder()
|
||||||
.setIsAiOpen(true)
|
.setIsAiOpen(true)
|
||||||
.setBornPos(getPosition().toProto()))
|
.setBornPos(getPosition().toProto()))
|
||||||
.setBornPos(getPosition().toProto())
|
.setBornPos(getPosition().toProto())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
SceneEntityInfoOuterClass.SceneEntityInfo.Builder entityInfo =
|
SceneEntityInfoOuterClass.SceneEntityInfo.Builder entityInfo =
|
||||||
SceneEntityInfoOuterClass.SceneEntityInfo.newBuilder()
|
SceneEntityInfoOuterClass.SceneEntityInfo.newBuilder()
|
||||||
.setEntityId(getId())
|
.setEntityId(getId())
|
||||||
.setEntityType(ProtEntityTypeOuterClass.ProtEntityType.PROT_ENTITY_TYPE_NPC)
|
.setEntityType(ProtEntityTypeOuterClass.ProtEntityType.PROT_ENTITY_TYPE_NPC)
|
||||||
.setMotionInfo(
|
.setMotionInfo(
|
||||||
MotionInfoOuterClass.MotionInfo.newBuilder()
|
MotionInfoOuterClass.MotionInfo.newBuilder()
|
||||||
.setPos(getPosition().toProto())
|
.setPos(getPosition().toProto())
|
||||||
.setRot(getRotation().toProto())
|
.setRot(getRotation().toProto())
|
||||||
.setSpeed(VectorOuterClass.Vector.newBuilder()))
|
.setSpeed(VectorOuterClass.Vector.newBuilder()))
|
||||||
.addAnimatorParaList(
|
.addAnimatorParaList(
|
||||||
AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair
|
AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair
|
||||||
.newBuilder())
|
.newBuilder())
|
||||||
.setEntityClientData(EntityClientDataOuterClass.EntityClientData.newBuilder())
|
.setEntityClientData(EntityClientDataOuterClass.EntityClientData.newBuilder())
|
||||||
.setEntityAuthorityInfo(authority)
|
.setEntityAuthorityInfo(authority)
|
||||||
.setLifeState(1);
|
.setLifeState(1);
|
||||||
|
|
||||||
entityInfo.setNpc(
|
entityInfo.setNpc(
|
||||||
SceneNpcInfoOuterClass.SceneNpcInfo.newBuilder()
|
SceneNpcInfoOuterClass.SceneNpcInfo.newBuilder()
|
||||||
.setNpcId(metaNpc.npc_id)
|
.setNpcId(metaNpc.npc_id)
|
||||||
.setBlockId(getBlockId())
|
.setBlockId(getBlockId())
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
return entityInfo.build();
|
return entityInfo.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,96 +1,96 @@
|
|||||||
package emu.grasscutter.game.entity;
|
package emu.grasscutter.game.entity;
|
||||||
|
|
||||||
import emu.grasscutter.game.props.EntityIdType;
|
import emu.grasscutter.game.props.EntityIdType;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass;
|
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass;
|
||||||
import emu.grasscutter.scripts.data.SceneRegion;
|
import emu.grasscutter.scripts.data.SceneRegion;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class EntityRegion extends GameEntity {
|
public class EntityRegion extends GameEntity {
|
||||||
private final Position position;
|
private final Position position;
|
||||||
private final Set<Integer> entities; // Ids of entities inside this region
|
private final Set<Integer> entities; // Ids of entities inside this region
|
||||||
private final SceneRegion metaRegion;
|
private final SceneRegion metaRegion;
|
||||||
private boolean hasNewEntities;
|
private boolean hasNewEntities;
|
||||||
private boolean entityLeave;
|
private boolean entityLeave;
|
||||||
|
|
||||||
public EntityRegion(Scene scene, SceneRegion region) {
|
public EntityRegion(Scene scene, SceneRegion region) {
|
||||||
super(scene);
|
super(scene);
|
||||||
|
|
||||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.REGION);
|
this.id = getScene().getWorld().getNextEntityId(EntityIdType.REGION);
|
||||||
this.setGroupId(region.group.id);
|
this.setGroupId(region.group.id);
|
||||||
this.setBlockId(region.group.block_id);
|
this.setBlockId(region.group.block_id);
|
||||||
this.setConfigId(region.config_id);
|
this.setConfigId(region.config_id);
|
||||||
this.position = region.pos.clone();
|
this.position = region.pos.clone();
|
||||||
this.entities = ConcurrentHashMap.newKeySet();
|
this.entities = ConcurrentHashMap.newKeySet();
|
||||||
this.metaRegion = region;
|
this.metaRegion = region;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getEntityTypeId() {
|
public int getEntityTypeId() {
|
||||||
return this.metaRegion.config_id;
|
return this.metaRegion.config_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEntity(GameEntity entity) {
|
public void addEntity(GameEntity entity) {
|
||||||
if (this.getEntities().contains(entity.getId())) {
|
if (this.getEntities().contains(entity.getId())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.getEntities().add(entity.getId());
|
this.getEntities().add(entity.getId());
|
||||||
this.hasNewEntities = true;
|
this.hasNewEntities = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasNewEntities() {
|
public boolean hasNewEntities() {
|
||||||
return hasNewEntities;
|
return hasNewEntities;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetNewEntities() {
|
public void resetNewEntities() {
|
||||||
hasNewEntities = false;
|
hasNewEntities = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeEntity(int entityId) {
|
public void removeEntity(int entityId) {
|
||||||
this.getEntities().remove(entityId);
|
this.getEntities().remove(entityId);
|
||||||
this.entityLeave = true;
|
this.entityLeave = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeEntity(GameEntity entity) {
|
public void removeEntity(GameEntity entity) {
|
||||||
this.getEntities().remove(entity.getId());
|
this.getEntities().remove(entity.getId());
|
||||||
this.entityLeave = true;
|
this.entityLeave = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean entityLeave() {
|
public boolean entityLeave() {
|
||||||
return this.entityLeave;
|
return this.entityLeave;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetEntityLeave() {
|
public void resetEntityLeave() {
|
||||||
this.entityLeave = false;
|
this.entityLeave = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Int2FloatMap getFightProperties() {
|
public Int2FloatMap getFightProperties() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Position getPosition() {
|
public Position getPosition() {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Position getRotation() {
|
public Position getRotation() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SceneEntityInfoOuterClass.SceneEntityInfo toProto() {
|
public SceneEntityInfoOuterClass.SceneEntityInfo toProto() {
|
||||||
/** The Region Entity would not be sent to client. */
|
/** The Region Entity would not be sent to client. */
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFirstEntityId() {
|
public int getFirstEntityId() {
|
||||||
return entities.stream().findFirst().orElse(0);
|
return entities.stream().findFirst().orElse(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,33 @@
|
|||||||
package emu.grasscutter.game.entity;
|
package emu.grasscutter.game.entity;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.platform.EntitySolarIsotomaElevatorPlatform;
|
import emu.grasscutter.game.entity.platform.EntitySolarIsotomaElevatorPlatform;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.net.proto.EvtCreateGadgetNotifyOuterClass;
|
import emu.grasscutter.net.proto.EvtCreateGadgetNotifyOuterClass;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
public class EntitySolarIsotomaClientGadget extends EntityClientGadget {
|
public class EntitySolarIsotomaClientGadget extends EntityClientGadget {
|
||||||
public static final int GADGET_ID = 41038001;
|
public static final int GADGET_ID = 41038001;
|
||||||
public static final int ELEVATOR_GADGET_ID = 41038002;
|
public static final int ELEVATOR_GADGET_ID = 41038002;
|
||||||
@Getter private EntityGadget platformGadget;
|
@Getter private EntityGadget platformGadget;
|
||||||
|
|
||||||
public EntitySolarIsotomaClientGadget(Scene scene, Player player, EvtCreateGadgetNotifyOuterClass.EvtCreateGadgetNotify notify) {
|
public EntitySolarIsotomaClientGadget(
|
||||||
super(scene, player, notify);
|
Scene scene, Player player, EvtCreateGadgetNotifyOuterClass.EvtCreateGadgetNotify notify) {
|
||||||
}
|
super(scene, player, notify);
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public void onCreate() {
|
@Override
|
||||||
//Create solar isotoma elevator and send to all.
|
public void onCreate() {
|
||||||
this.platformGadget = new EntitySolarIsotomaElevatorPlatform(this, getScene(), ELEVATOR_GADGET_ID, getPosition(), getRotation());
|
// Create solar isotoma elevator and send to all.
|
||||||
getScene().addEntity(this.platformGadget);
|
this.platformGadget =
|
||||||
}
|
new EntitySolarIsotomaElevatorPlatform(
|
||||||
|
this, getScene(), ELEVATOR_GADGET_ID, getPosition(), getRotation());
|
||||||
@Override
|
getScene().addEntity(this.platformGadget);
|
||||||
public void onRemoved() {
|
}
|
||||||
//Remove solar isotoma elevator entity.
|
|
||||||
getScene().removeEntity(this.platformGadget);
|
@Override
|
||||||
}
|
public void onRemoved() {
|
||||||
}
|
// Remove solar isotoma elevator entity.
|
||||||
|
getScene().removeEntity(this.platformGadget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,112 +1,125 @@
|
|||||||
package emu.grasscutter.game.entity;
|
package emu.grasscutter.game.entity;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.binout.config.ConfigEntityGadget;
|
import emu.grasscutter.data.binout.config.ConfigEntityGadget;
|
||||||
import emu.grasscutter.data.excels.GadgetData;
|
import emu.grasscutter.data.excels.GadgetData;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.EntityIdType;
|
import emu.grasscutter.game.props.EntityIdType;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.game.props.PlayerProperty;
|
import emu.grasscutter.game.props.PlayerProperty;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
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.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
|
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
|
||||||
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
|
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
|
||||||
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
||||||
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.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.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||||
import emu.grasscutter.net.proto.VehicleInfoOuterClass.VehicleInfo;
|
import emu.grasscutter.net.proto.VehicleInfoOuterClass.VehicleInfo;
|
||||||
import emu.grasscutter.net.proto.VehicleMemberOuterClass.VehicleMember;
|
import emu.grasscutter.net.proto.VehicleMemberOuterClass.VehicleMember;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import emu.grasscutter.utils.ProtoHelper;
|
import emu.grasscutter.utils.ProtoHelper;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||||
import lombok.Getter;
|
import java.util.ArrayList;
|
||||||
import lombok.Setter;
|
import java.util.List;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.Nullable;
|
import lombok.Getter;
|
||||||
import java.util.ArrayList;
|
import lombok.Setter;
|
||||||
import java.util.List;
|
|
||||||
|
public class EntityVehicle extends EntityBaseGadget {
|
||||||
public class EntityVehicle extends EntityBaseGadget {
|
|
||||||
|
@Getter private final Player owner;
|
||||||
@Getter private final Player owner;
|
|
||||||
@Getter(onMethod = @__(@Override))
|
@Getter(onMethod = @__(@Override))
|
||||||
private final Int2FloatMap fightProperties;
|
private final Int2FloatMap fightProperties;
|
||||||
|
|
||||||
@Getter private final int pointId;
|
@Getter private final int pointId;
|
||||||
@Getter private final int gadgetId;
|
@Getter private final int gadgetId;
|
||||||
|
|
||||||
@Getter @Setter private float curStamina;
|
@Getter @Setter private float curStamina;
|
||||||
@Getter private final List<VehicleMember> vehicleMembers;
|
@Getter private final List<VehicleMember> vehicleMembers;
|
||||||
@Nullable @Getter private ConfigEntityGadget configGadget;
|
@Nullable @Getter private ConfigEntityGadget configGadget;
|
||||||
|
|
||||||
public EntityVehicle(Scene scene, Player player, int gadgetId, int pointId, Position pos, Position rot) {
|
public EntityVehicle(
|
||||||
super(scene, pos, rot);
|
Scene scene, Player player, int gadgetId, int pointId, Position pos, Position rot) {
|
||||||
this.owner = player;
|
super(scene, pos, rot);
|
||||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
this.owner = player;
|
||||||
this.fightProperties = new Int2FloatOpenHashMap();
|
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||||
this.gadgetId = gadgetId;
|
this.fightProperties = new Int2FloatOpenHashMap();
|
||||||
this.pointId = pointId;
|
this.gadgetId = gadgetId;
|
||||||
this.curStamina = 240; // might be in configGadget.GCALKECLLLP.JBAKBEFIMBN.ANBMPHPOALP
|
this.pointId = pointId;
|
||||||
this.vehicleMembers = new ArrayList<>();
|
this.curStamina = 240; // might be in configGadget.GCALKECLLLP.JBAKBEFIMBN.ANBMPHPOALP
|
||||||
GadgetData data = GameData.getGadgetDataMap().get(gadgetId);
|
this.vehicleMembers = new ArrayList<>();
|
||||||
if (data != null && data.getJsonName() != null) {
|
GadgetData data = GameData.getGadgetDataMap().get(gadgetId);
|
||||||
this.configGadget = GameData.getGadgetConfigData().get(data.getJsonName());
|
if (data != null && data.getJsonName() != null) {
|
||||||
}
|
this.configGadget = GameData.getGadgetConfigData().get(data.getJsonName());
|
||||||
|
}
|
||||||
fillFightProps(configGadget);
|
|
||||||
}
|
fillFightProps(configGadget);
|
||||||
|
}
|
||||||
@Override
|
|
||||||
protected void fillFightProps(ConfigEntityGadget configGadget) {
|
@Override
|
||||||
super.fillFightProps(configGadget);
|
protected void fillFightProps(ConfigEntityGadget configGadget) {
|
||||||
this.addFightProperty(FightProperty.FIGHT_PROP_CUR_SPEED, 0);
|
super.fillFightProps(configGadget);
|
||||||
this.addFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, 0);
|
this.addFightProperty(FightProperty.FIGHT_PROP_CUR_SPEED, 0);
|
||||||
}
|
this.addFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, 0);
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public SceneEntityInfo toProto() {
|
@Override
|
||||||
|
public SceneEntityInfo toProto() {
|
||||||
VehicleInfo vehicle = VehicleInfo.newBuilder()
|
|
||||||
.setOwnerUid(this.owner.getUid())
|
VehicleInfo vehicle =
|
||||||
.setCurStamina(getCurStamina())
|
VehicleInfo.newBuilder()
|
||||||
.build();
|
.setOwnerUid(this.owner.getUid())
|
||||||
|
.setCurStamina(getCurStamina())
|
||||||
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
.build();
|
||||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
|
||||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
EntityAuthorityInfo authority =
|
||||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(getPosition().toProto()))
|
EntityAuthorityInfo.newBuilder()
|
||||||
.setBornPos(getPosition().toProto())
|
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||||
.build();
|
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||||
|
.setAiInfo(
|
||||||
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
|
SceneEntityAiInfo.newBuilder()
|
||||||
.setGadgetId(this.getGadgetId())
|
.setIsAiOpen(true)
|
||||||
.setAuthorityPeerId(this.getOwner().getPeerId())
|
.setBornPos(getPosition().toProto()))
|
||||||
.setIsEnableInteract(true)
|
.setBornPos(getPosition().toProto())
|
||||||
.setVehicleInfo(vehicle);
|
.build();
|
||||||
|
|
||||||
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
SceneGadgetInfo.Builder gadgetInfo =
|
||||||
.setEntityId(getId())
|
SceneGadgetInfo.newBuilder()
|
||||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
.setGadgetId(this.getGadgetId())
|
||||||
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
|
.setAuthorityPeerId(this.getOwner().getPeerId())
|
||||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
.setIsEnableInteract(true)
|
||||||
.setGadget(gadgetInfo)
|
.setVehicleInfo(vehicle);
|
||||||
.setEntityAuthorityInfo(authority)
|
|
||||||
.setLifeState(1);
|
SceneEntityInfo.Builder entityInfo =
|
||||||
|
SceneEntityInfo.newBuilder()
|
||||||
PropPair pair = PropPair.newBuilder()
|
.setEntityId(getId())
|
||||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
||||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 47))
|
.setMotionInfo(
|
||||||
.build();
|
MotionInfo.newBuilder()
|
||||||
|
.setPos(getPosition().toProto())
|
||||||
this.addAllFightPropsToEntityInfo(entityInfo);
|
.setRot(getRotation().toProto())
|
||||||
entityInfo.addPropList(pair);
|
.setSpeed(Vector.newBuilder()))
|
||||||
|
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||||
return entityInfo.build();
|
.setGadget(gadgetInfo)
|
||||||
}
|
.setEntityAuthorityInfo(authority)
|
||||||
}
|
.setLifeState(1);
|
||||||
|
|
||||||
|
PropPair pair =
|
||||||
|
PropPair.newBuilder()
|
||||||
|
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||||
|
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 47))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
this.addAllFightPropsToEntityInfo(entityInfo);
|
||||||
|
entityInfo.addPropList(pair);
|
||||||
|
|
||||||
|
return entityInfo.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,264 +1,264 @@
|
|||||||
package emu.grasscutter.game.entity;
|
package emu.grasscutter.game.entity;
|
||||||
|
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.ElementType;
|
import emu.grasscutter.game.props.ElementType;
|
||||||
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;
|
||||||
import emu.grasscutter.game.world.SpawnDataEntry;
|
import emu.grasscutter.game.world.SpawnDataEntry;
|
||||||
import emu.grasscutter.game.world.World;
|
import emu.grasscutter.game.world.World;
|
||||||
import emu.grasscutter.net.proto.FightPropPairOuterClass.FightPropPair;
|
import emu.grasscutter.net.proto.FightPropPairOuterClass.FightPropPair;
|
||||||
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
||||||
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
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.scripts.data.controller.EntityController;
|
import emu.grasscutter.scripts.data.controller.EntityController;
|
||||||
import emu.grasscutter.server.event.entity.EntityDamageEvent;
|
import emu.grasscutter.server.event.entity.EntityDamageEvent;
|
||||||
import emu.grasscutter.server.event.entity.EntityDeathEvent;
|
import emu.grasscutter.server.event.entity.EntityDeathEvent;
|
||||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2FloatMap;
|
import it.unimi.dsi.fastutil.objects.Object2FloatMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
public abstract class GameEntity {
|
public abstract class GameEntity {
|
||||||
@Getter private final Scene scene;
|
@Getter private final Scene scene;
|
||||||
@Getter protected int id;
|
@Getter protected int id;
|
||||||
@Getter @Setter private SpawnDataEntry spawnEntry;
|
@Getter @Setter private SpawnDataEntry spawnEntry;
|
||||||
|
|
||||||
@Getter @Setter private int blockId;
|
@Getter @Setter private int blockId;
|
||||||
@Getter @Setter private int configId;
|
@Getter @Setter private int configId;
|
||||||
@Getter @Setter private int groupId;
|
@Getter @Setter private int groupId;
|
||||||
|
|
||||||
@Getter @Setter private MotionState motionState;
|
@Getter @Setter private MotionState motionState;
|
||||||
@Getter @Setter private int lastMoveSceneTimeMs;
|
@Getter @Setter private int lastMoveSceneTimeMs;
|
||||||
@Getter @Setter private int lastMoveReliableSeq;
|
@Getter @Setter private int lastMoveReliableSeq;
|
||||||
|
|
||||||
@Getter @Setter private boolean lockHP;
|
@Getter @Setter private boolean lockHP;
|
||||||
|
|
||||||
// Lua controller for specific actions
|
// Lua controller for specific actions
|
||||||
@Getter @Setter private EntityController entityController;
|
@Getter @Setter private EntityController entityController;
|
||||||
@Getter private ElementType lastAttackType = ElementType.None;
|
@Getter private ElementType lastAttackType = ElementType.None;
|
||||||
|
|
||||||
// Abilities
|
// Abilities
|
||||||
private Object2FloatMap<String> metaOverrideMap;
|
private Object2FloatMap<String> metaOverrideMap;
|
||||||
private Int2ObjectMap<String> metaModifiers;
|
private Int2ObjectMap<String> metaModifiers;
|
||||||
|
|
||||||
public GameEntity(Scene scene) {
|
public GameEntity(Scene scene) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.motionState = MotionState.MOTION_STATE_NONE;
|
this.motionState = MotionState.MOTION_STATE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getEntityType() {
|
public int getEntityType() {
|
||||||
return this.getId() >> 24;
|
return this.getId() >> 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract int getEntityTypeId();
|
public abstract int getEntityTypeId();
|
||||||
|
|
||||||
public World getWorld() {
|
public World getWorld() {
|
||||||
return this.getScene().getWorld();
|
return this.getScene().getWorld();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAlive() {
|
public boolean isAlive() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LifeState getLifeState() {
|
public LifeState getLifeState() {
|
||||||
return this.isAlive() ? LifeState.LIFE_ALIVE : LifeState.LIFE_DEAD;
|
return this.isAlive() ? LifeState.LIFE_ALIVE : LifeState.LIFE_DEAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object2FloatMap<String> getMetaOverrideMap() {
|
public Object2FloatMap<String> getMetaOverrideMap() {
|
||||||
if (this.metaOverrideMap == null) {
|
if (this.metaOverrideMap == null) {
|
||||||
this.metaOverrideMap = new Object2FloatOpenHashMap<>();
|
this.metaOverrideMap = new Object2FloatOpenHashMap<>();
|
||||||
}
|
}
|
||||||
return this.metaOverrideMap;
|
return this.metaOverrideMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Int2ObjectMap<String> getMetaModifiers() {
|
public Int2ObjectMap<String> getMetaModifiers() {
|
||||||
if (this.metaModifiers == null) {
|
if (this.metaModifiers == null) {
|
||||||
this.metaModifiers = new Int2ObjectOpenHashMap<>();
|
this.metaModifiers = new Int2ObjectOpenHashMap<>();
|
||||||
}
|
}
|
||||||
return this.metaModifiers;
|
return this.metaModifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Int2FloatMap getFightProperties();
|
public abstract Int2FloatMap getFightProperties();
|
||||||
|
|
||||||
public abstract Position getPosition();
|
public abstract Position getPosition();
|
||||||
|
|
||||||
public abstract Position getRotation();
|
public abstract Position getRotation();
|
||||||
|
|
||||||
public void setFightProperty(FightProperty prop, float value) {
|
public void setFightProperty(FightProperty prop, float value) {
|
||||||
this.getFightProperties().put(prop.getId(), value);
|
this.getFightProperties().put(prop.getId(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFightProperty(int id, float value) {
|
public void setFightProperty(int id, float value) {
|
||||||
this.getFightProperties().put(id, value);
|
this.getFightProperties().put(id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addFightProperty(FightProperty prop, float value) {
|
public void addFightProperty(FightProperty prop, float value) {
|
||||||
this.getFightProperties().put(prop.getId(), this.getFightProperty(prop) + value);
|
this.getFightProperties().put(prop.getId(), this.getFightProperty(prop) + value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getFightProperty(FightProperty prop) {
|
public float getFightProperty(FightProperty prop) {
|
||||||
return this.getFightProperties().getOrDefault(prop.getId(), 0f);
|
return this.getFightProperties().getOrDefault(prop.getId(), 0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasFightProperty(FightProperty prop) {
|
public boolean hasFightProperty(FightProperty prop) {
|
||||||
return this.getFightProperties().containsKey(prop.getId());
|
return this.getFightProperties().containsKey(prop.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAllFightPropsToEntityInfo(SceneEntityInfo.Builder entityInfo) {
|
public void addAllFightPropsToEntityInfo(SceneEntityInfo.Builder entityInfo) {
|
||||||
this.getFightProperties()
|
this.getFightProperties()
|
||||||
.forEach(
|
.forEach(
|
||||||
(key, value) -> {
|
(key, value) -> {
|
||||||
if (key == 0) return;
|
if (key == 0) return;
|
||||||
entityInfo.addFightPropList(
|
entityInfo.addFightPropList(
|
||||||
FightPropPair.newBuilder().setPropType(key).setPropValue(value).build());
|
FightPropPair.newBuilder().setPropType(key).setPropValue(value).build());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MotionInfo getMotionInfo() {
|
protected MotionInfo getMotionInfo() {
|
||||||
return MotionInfo.newBuilder()
|
return MotionInfo.newBuilder()
|
||||||
.setPos(this.getPosition().toProto())
|
.setPos(this.getPosition().toProto())
|
||||||
.setRot(this.getRotation().toProto())
|
.setRot(this.getRotation().toProto())
|
||||||
.setSpeed(Vector.newBuilder())
|
.setSpeed(Vector.newBuilder())
|
||||||
.setState(this.getMotionState())
|
.setState(this.getMotionState())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public float heal(float amount) {
|
public float heal(float amount) {
|
||||||
if (this.getFightProperties() == null) {
|
if (this.getFightProperties() == null) {
|
||||||
return 0f;
|
return 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
float curHp = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
float curHp = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||||
float maxHp = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
float maxHp = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||||
|
|
||||||
if (curHp >= maxHp) {
|
if (curHp >= maxHp) {
|
||||||
return 0f;
|
return 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
float healed = Math.min(maxHp - curHp, amount);
|
float healed = Math.min(maxHp - curHp, amount);
|
||||||
this.addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, healed);
|
this.addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, healed);
|
||||||
|
|
||||||
this.getScene()
|
this.getScene()
|
||||||
.broadcastPacket(
|
.broadcastPacket(
|
||||||
new PacketEntityFightPropUpdateNotify(this, FightProperty.FIGHT_PROP_CUR_HP));
|
new PacketEntityFightPropUpdateNotify(this, FightProperty.FIGHT_PROP_CUR_HP));
|
||||||
|
|
||||||
return healed;
|
return healed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void damage(float amount) {
|
public void damage(float amount) {
|
||||||
this.damage(amount, 0, ElementType.None);
|
this.damage(amount, 0, ElementType.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void damage(float amount, int killerId, ElementType attackType) {
|
public void damage(float amount, int killerId, ElementType attackType) {
|
||||||
// Check if the entity has properties.
|
// Check if the entity has properties.
|
||||||
if (this.getFightProperties() == null || !hasFightProperty(FightProperty.FIGHT_PROP_CUR_HP)) {
|
if (this.getFightProperties() == null || !hasFightProperty(FightProperty.FIGHT_PROP_CUR_HP)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoke entity damage event.
|
// Invoke entity damage event.
|
||||||
EntityDamageEvent event =
|
EntityDamageEvent event =
|
||||||
new EntityDamageEvent(this, amount, attackType, this.getScene().getEntityById(killerId));
|
new EntityDamageEvent(this, amount, attackType, this.getScene().getEntityById(killerId));
|
||||||
event.call();
|
event.call();
|
||||||
if (event.isCanceled()) {
|
if (event.isCanceled()) {
|
||||||
return; // If the event is canceled, do not damage the entity.
|
return; // If the event is canceled, do not damage the entity.
|
||||||
}
|
}
|
||||||
|
|
||||||
float curHp = getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
float curHp = getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||||
if (curHp != Float.POSITIVE_INFINITY && !lockHP || lockHP && curHp <= event.getDamage()) {
|
if (curHp != Float.POSITIVE_INFINITY && !lockHP || lockHP && curHp <= event.getDamage()) {
|
||||||
// Add negative HP to the current HP property.
|
// Add negative HP to the current HP property.
|
||||||
this.addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, -(event.getDamage()));
|
this.addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, -(event.getDamage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if dead
|
// Check if dead
|
||||||
boolean isDead = false;
|
boolean isDead = false;
|
||||||
if (this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) <= 0f) {
|
if (this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) <= 0f) {
|
||||||
this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f);
|
this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f);
|
||||||
isDead = true;
|
isDead = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Packets
|
// Packets
|
||||||
this.getScene()
|
this.getScene()
|
||||||
.broadcastPacket(
|
.broadcastPacket(
|
||||||
new PacketEntityFightPropUpdateNotify(this, FightProperty.FIGHT_PROP_CUR_HP));
|
new PacketEntityFightPropUpdateNotify(this, FightProperty.FIGHT_PROP_CUR_HP));
|
||||||
|
|
||||||
// Check if dead.
|
// Check if dead.
|
||||||
if (isDead) {
|
if (isDead) {
|
||||||
this.getScene().killEntity(this, killerId);
|
this.getScene().killEntity(this, killerId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the Lua callbacks for {@link EntityDamageEvent}.
|
* Runs the Lua callbacks for {@link EntityDamageEvent}.
|
||||||
*
|
*
|
||||||
* @param event The damage event.
|
* @param event The damage event.
|
||||||
*/
|
*/
|
||||||
public void runLuaCallbacks(EntityDamageEvent event) {
|
public void runLuaCallbacks(EntityDamageEvent event) {
|
||||||
if (entityController != null) {
|
if (entityController != null) {
|
||||||
entityController.onBeHurt(this, event.getAttackElementType(), true);//todo is host handling
|
entityController.onBeHurt(this, event.getAttackElementType(), true); // todo is host handling
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move this entity to a new position.
|
* Move this entity to a new position.
|
||||||
*
|
*
|
||||||
* @param position The new position.
|
* @param position The new position.
|
||||||
* @param rotation The new rotation.
|
* @param rotation The new rotation.
|
||||||
*/
|
*/
|
||||||
public void move(Position position, Position rotation) {
|
public void move(Position position, Position rotation) {
|
||||||
// Set the position and rotation.
|
// Set the position and rotation.
|
||||||
this.getPosition().set(position);
|
this.getPosition().set(position);
|
||||||
this.getRotation().set(rotation);
|
this.getRotation().set(rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a player interacts with this entity
|
* Called when a player interacts with this entity
|
||||||
*
|
*
|
||||||
* @param player Player that is interacting with this entity
|
* @param player Player that is interacting with this entity
|
||||||
* @param interactReq Interact request protobuf data
|
* @param interactReq Interact request protobuf data
|
||||||
*/
|
*/
|
||||||
public void onInteract(Player player, GadgetInteractReq interactReq) {}
|
public void onInteract(Player player, GadgetInteractReq interactReq) {}
|
||||||
|
|
||||||
/** Called when this entity is added to the world */
|
/** Called when this entity is added to the world */
|
||||||
public void onCreate() {}
|
public void onCreate() {}
|
||||||
|
|
||||||
public void onRemoved() {}
|
public void onRemoved() {}
|
||||||
|
|
||||||
public void onTick(int sceneTime) {
|
public void onTick(int sceneTime) {
|
||||||
if (entityController != null) {
|
if (entityController != null) {
|
||||||
entityController.onTimer(this, sceneTime);
|
entityController.onTimer(this, sceneTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int onClientExecuteRequest(int param1, int param2, int param3) {
|
public int onClientExecuteRequest(int param1, int param2, int param3) {
|
||||||
if (entityController != null) {
|
if (entityController != null) {
|
||||||
return entityController.onClientExecuteRequest(this, param1, param2, param3);
|
return entityController.onClientExecuteRequest(this, param1, param2, param3);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when this entity dies
|
* Called when this entity dies
|
||||||
*
|
*
|
||||||
* @param killerId Entity id of the entity that killed this entity
|
* @param killerId Entity id of the entity that killed this entity
|
||||||
*/
|
*/
|
||||||
public void onDeath(int killerId) {
|
public void onDeath(int killerId) {
|
||||||
// Invoke entity death event.
|
// Invoke entity death event.
|
||||||
EntityDeathEvent event = new EntityDeathEvent(this, killerId);
|
EntityDeathEvent event = new EntityDeathEvent(this, killerId);
|
||||||
event.call();
|
event.call();
|
||||||
|
|
||||||
// Run Lua callbacks.
|
// Run Lua callbacks.
|
||||||
if (entityController != null) {
|
if (entityController != null) {
|
||||||
entityController.onDie(this, getLastAttackType());
|
entityController.onDie(this, getLastAttackType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract SceneEntityInfo toProto();
|
public abstract SceneEntityInfo toProto();
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,34 @@
|
|||||||
package emu.grasscutter.game.entity.gadget;
|
package emu.grasscutter.game.entity.gadget;
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.DungeonChallenge;
|
import emu.grasscutter.game.dungeons.challenge.DungeonChallenge;
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
||||||
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
|
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
|
||||||
import emu.grasscutter.net.proto.ResinCostTypeOuterClass;
|
import emu.grasscutter.net.proto.ResinCostTypeOuterClass;
|
||||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||||
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
|
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
|
||||||
|
|
||||||
public final class GadgetRewardStatue extends GadgetContent {
|
public final class GadgetRewardStatue extends GadgetContent {
|
||||||
|
|
||||||
public GadgetRewardStatue(EntityGadget gadget) {
|
public GadgetRewardStatue(EntityGadget gadget) {
|
||||||
super(gadget);
|
super(gadget);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onInteract(Player player, GadgetInteractReq req) {
|
public boolean onInteract(Player player, GadgetInteractReq req) {
|
||||||
var dungeonManager = player.getScene().getDungeonManager();
|
var dungeonManager = player.getScene().getDungeonManager();
|
||||||
|
|
||||||
if (player.getScene().getChallenge() instanceof DungeonChallenge) {
|
if (player.getScene().getChallenge() instanceof DungeonChallenge) {
|
||||||
var useCondensed = req.getResinCostType() == ResinCostTypeOuterClass.ResinCostType.RESIN_COST_TYPE_CONDENSE;
|
var useCondensed =
|
||||||
dungeonManager.getStatueDrops(player, useCondensed, getGadget().getGroupId());
|
req.getResinCostType() == ResinCostTypeOuterClass.ResinCostType.RESIN_COST_TYPE_CONDENSE;
|
||||||
}
|
dungeonManager.getStatueDrops(player, useCondensed, getGadget().getGroupId());
|
||||||
|
}
|
||||||
player.sendPacket(
|
|
||||||
new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_TYPE_OPEN_STATUE));
|
player.sendPacket(
|
||||||
|
new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_TYPE_OPEN_STATUE));
|
||||||
return false;
|
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) {}
|
|
||||||
}
|
public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) {}
|
||||||
|
}
|
||||||
|
@ -1,40 +1,45 @@
|
|||||||
package emu.grasscutter.game.entity.platform;
|
package emu.grasscutter.game.entity.platform;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.data.binout.config.ConfigEntityGadget;
|
import emu.grasscutter.data.binout.config.ConfigEntityGadget;
|
||||||
import emu.grasscutter.game.entity.*;
|
import emu.grasscutter.game.entity.*;
|
||||||
import emu.grasscutter.game.entity.gadget.GadgetAbility;
|
import emu.grasscutter.game.entity.gadget.GadgetAbility;
|
||||||
import emu.grasscutter.game.entity.gadget.platform.AbilityRoute;
|
import emu.grasscutter.game.entity.gadget.platform.AbilityRoute;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
|
|
||||||
public class EntitySolarIsotomaElevatorPlatform extends EntityGadget {
|
public class EntitySolarIsotomaElevatorPlatform extends EntityGadget {
|
||||||
public EntitySolarIsotomaElevatorPlatform(EntitySolarIsotomaClientGadget isotoma, Scene scene, int gadgetId, Position pos, Position rot) {
|
public EntitySolarIsotomaElevatorPlatform(
|
||||||
super(scene, gadgetId, pos, rot);
|
EntitySolarIsotomaClientGadget isotoma,
|
||||||
setOwner(isotoma);
|
Scene scene,
|
||||||
this.setRouteConfig(new AbilityRoute(rot, false, false, pos));
|
int gadgetId,
|
||||||
this.setContent(new GadgetAbility(this, isotoma));
|
Position pos,
|
||||||
}
|
Position rot) {
|
||||||
|
super(scene, gadgetId, pos, rot);
|
||||||
@Override
|
setOwner(isotoma);
|
||||||
protected void fillFightProps(ConfigEntityGadget configGadget) {
|
this.setRouteConfig(new AbilityRoute(rot, false, false, pos));
|
||||||
if (configGadget == null || configGadget.getCombat() == null) {
|
this.setContent(new GadgetAbility(this, isotoma));
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
var combatData = configGadget.getCombat();
|
@Override
|
||||||
var combatProperties = combatData.getProperty();
|
protected void fillFightProps(ConfigEntityGadget configGadget) {
|
||||||
|
if (configGadget == null || configGadget.getCombat() == null) {
|
||||||
if (combatProperties.isUseCreatorProperty()) {
|
return;
|
||||||
//If useCreatorProperty == true, use owner's property;
|
}
|
||||||
GameEntity ownerEntity = getOwner();
|
var combatData = configGadget.getCombat();
|
||||||
if (ownerEntity != null) {
|
var combatProperties = combatData.getProperty();
|
||||||
getFightProperties().putAll(ownerEntity.getFightProperties());
|
|
||||||
return;
|
if (combatProperties.isUseCreatorProperty()) {
|
||||||
} else {
|
// If useCreatorProperty == true, use owner's property;
|
||||||
Grasscutter.getLogger().warn("Why gadget owner is null?");
|
GameEntity ownerEntity = getOwner();
|
||||||
}
|
if (ownerEntity != null) {
|
||||||
}
|
getFightProperties().putAll(ownerEntity.getFightProperties());
|
||||||
|
return;
|
||||||
super.fillFightProps(configGadget);
|
} else {
|
||||||
}
|
Grasscutter.getLogger().warn("Why gadget owner is null?");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.fillFightProps(configGadget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,163 +1,173 @@
|
|||||||
package emu.grasscutter.game.mail;
|
package emu.grasscutter.game.mail;
|
||||||
|
|
||||||
import dev.morphia.annotations.Entity;
|
import static emu.grasscutter.net.proto.MailItemOuterClass.MailItem.*;
|
||||||
import dev.morphia.annotations.Id;
|
|
||||||
import dev.morphia.annotations.Indexed;
|
import dev.morphia.annotations.Entity;
|
||||||
import dev.morphia.annotations.Transient;
|
import dev.morphia.annotations.Id;
|
||||||
import emu.grasscutter.database.DatabaseHelper;
|
import dev.morphia.annotations.Indexed;
|
||||||
import emu.grasscutter.game.player.Player;
|
import dev.morphia.annotations.Transient;
|
||||||
import emu.grasscutter.net.proto.*;
|
import emu.grasscutter.database.DatabaseHelper;
|
||||||
import emu.grasscutter.net.proto.EquipParamOuterClass.EquipParam;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.net.proto.MailCollectStateOuterClass.MailCollectState;
|
import emu.grasscutter.net.proto.*;
|
||||||
import emu.grasscutter.net.proto.MailTextContentOuterClass.MailTextContent;
|
import emu.grasscutter.net.proto.EquipParamOuterClass.EquipParam;
|
||||||
import org.bson.types.ObjectId;
|
import emu.grasscutter.net.proto.MailCollectStateOuterClass.MailCollectState;
|
||||||
|
import emu.grasscutter.net.proto.MailTextContentOuterClass.MailTextContent;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.bson.types.ObjectId;
|
||||||
import static emu.grasscutter.net.proto.MailItemOuterClass.MailItem.*;
|
|
||||||
|
@Entity(value = "mail", useDiscriminator = false)
|
||||||
@Entity(value = "mail", useDiscriminator = false)
|
public final class Mail {
|
||||||
public final class Mail {
|
@Id private ObjectId id;
|
||||||
@Id private ObjectId id;
|
@Indexed private int ownerUid;
|
||||||
@Indexed private int ownerUid;
|
public MailContent mailContent;
|
||||||
public MailContent mailContent;
|
public List<MailItem> itemList;
|
||||||
public List<MailItem> itemList;
|
public long sendTime;
|
||||||
public long sendTime;
|
public long expireTime;
|
||||||
public long expireTime;
|
public int importance;
|
||||||
public int importance;
|
public boolean isRead;
|
||||||
public boolean isRead;
|
public boolean isAttachmentGot;
|
||||||
public boolean isAttachmentGot;
|
public int stateValue;
|
||||||
public int stateValue;
|
@Transient private boolean shouldDelete;
|
||||||
@Transient private boolean shouldDelete;
|
|
||||||
|
public Mail() {
|
||||||
public Mail() {
|
this(
|
||||||
this(new MailContent(), new ArrayList<MailItem>(), (int) Instant.now().getEpochSecond() + 604800); // TODO: add expire time to send mail command
|
new MailContent(),
|
||||||
}
|
new ArrayList<MailItem>(),
|
||||||
|
(int) Instant.now().getEpochSecond()
|
||||||
public Mail(MailContent mailContent, List<MailItem> itemList, long expireTime) {
|
+ 604800); // TODO: add expire time to send mail command
|
||||||
this(mailContent, itemList, expireTime, 0);
|
}
|
||||||
}
|
|
||||||
|
public Mail(MailContent mailContent, List<MailItem> itemList, long expireTime) {
|
||||||
public Mail(MailContent mailContent, List<MailItem> itemList, long expireTime, int importance) {
|
this(mailContent, itemList, expireTime, 0);
|
||||||
this(mailContent, itemList, expireTime, importance, 1);
|
}
|
||||||
}
|
|
||||||
|
public Mail(MailContent mailContent, List<MailItem> itemList, long expireTime, int importance) {
|
||||||
public Mail(MailContent mailContent, List<MailItem> itemList, long expireTime, int importance, int state) {
|
this(mailContent, itemList, expireTime, importance, 1);
|
||||||
this.mailContent = mailContent;
|
}
|
||||||
this.itemList = itemList;
|
|
||||||
this.sendTime = (int) Instant.now().getEpochSecond();
|
public Mail(
|
||||||
this.expireTime = expireTime;
|
MailContent mailContent,
|
||||||
this.importance = importance; // Starred mail, 0 = No star, 1 = Star.
|
List<MailItem> itemList,
|
||||||
this.isRead = false;
|
long expireTime,
|
||||||
this.isAttachmentGot = false;
|
int importance,
|
||||||
this.stateValue = state; // Different mailboxes, 1 = Default, 3 = Gift-box.
|
int state) {
|
||||||
}
|
this.mailContent = mailContent;
|
||||||
|
this.itemList = itemList;
|
||||||
public ObjectId getId() {
|
this.sendTime = (int) Instant.now().getEpochSecond();
|
||||||
return id;
|
this.expireTime = expireTime;
|
||||||
}
|
this.importance = importance; // Starred mail, 0 = No star, 1 = Star.
|
||||||
|
this.isRead = false;
|
||||||
public int getOwnerUid() {
|
this.isAttachmentGot = false;
|
||||||
return ownerUid;
|
this.stateValue = state; // Different mailboxes, 1 = Default, 3 = Gift-box.
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOwnerUid(int ownerUid) {
|
public ObjectId getId() {
|
||||||
this.ownerUid = ownerUid;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MailDataOuterClass.MailData toProto(Player player) {
|
public int getOwnerUid() {
|
||||||
return MailDataOuterClass.MailData.newBuilder()
|
return ownerUid;
|
||||||
.setMailId(player.getMailId(this))
|
}
|
||||||
.setMailTextContent(this.mailContent.toProto())
|
|
||||||
.addAllItemList(this.itemList.stream().map(MailItem::toProto).toList())
|
public void setOwnerUid(int ownerUid) {
|
||||||
.setSendTime((int) this.sendTime)
|
this.ownerUid = ownerUid;
|
||||||
.setExpireTime((int) this.expireTime)
|
}
|
||||||
.setImportance(this.importance)
|
|
||||||
.setIsRead(this.isRead)
|
public MailDataOuterClass.MailData toProto(Player player) {
|
||||||
.setIsAttachmentGot(this.isAttachmentGot)
|
return MailDataOuterClass.MailData.newBuilder()
|
||||||
.setCollectState(MailCollectState.MAIL_COLLECT_STATE_NOT_COLLECTIBLE)
|
.setMailId(player.getMailId(this))
|
||||||
.build();
|
.setMailTextContent(this.mailContent.toProto())
|
||||||
}
|
.addAllItemList(this.itemList.stream().map(MailItem::toProto).toList())
|
||||||
|
.setSendTime((int) this.sendTime)
|
||||||
@Entity
|
.setExpireTime((int) this.expireTime)
|
||||||
public static class MailContent {
|
.setImportance(this.importance)
|
||||||
public String title;
|
.setIsRead(this.isRead)
|
||||||
public String content;
|
.setIsAttachmentGot(this.isAttachmentGot)
|
||||||
public String sender;
|
.setCollectState(MailCollectState.MAIL_COLLECT_STATE_NOT_COLLECTIBLE)
|
||||||
|
.build();
|
||||||
public MailContent() {
|
}
|
||||||
this.title = "";
|
|
||||||
this.content = "loading...";
|
@Entity
|
||||||
this.sender = "loading";
|
public static class MailContent {
|
||||||
}
|
public String title;
|
||||||
|
public String content;
|
||||||
public MailContent(String title, String content) {
|
public String sender;
|
||||||
this(title, content, "Server");
|
|
||||||
}
|
public MailContent() {
|
||||||
|
this.title = "";
|
||||||
public MailContent(String title, String content, Player sender) {
|
this.content = "loading...";
|
||||||
this(title, content, sender.getNickname());
|
this.sender = "loading";
|
||||||
}
|
}
|
||||||
|
|
||||||
public MailContent(String title, String content, String sender) {
|
public MailContent(String title, String content) {
|
||||||
this.title = title;
|
this(title, content, "Server");
|
||||||
this.content = content;
|
}
|
||||||
this.sender = sender;
|
|
||||||
}
|
public MailContent(String title, String content, Player sender) {
|
||||||
|
this(title, content, sender.getNickname());
|
||||||
public MailTextContent toProto() {
|
}
|
||||||
return MailTextContent.newBuilder()
|
|
||||||
.setTitle(this.title)
|
public MailContent(String title, String content, String sender) {
|
||||||
.setContent(this.content)
|
this.title = title;
|
||||||
.setSender(this.sender)
|
this.content = content;
|
||||||
.build();
|
this.sender = sender;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public MailTextContent toProto() {
|
||||||
@Entity
|
return MailTextContent.newBuilder()
|
||||||
public static class MailItem {
|
.setTitle(this.title)
|
||||||
public int itemId;
|
.setContent(this.content)
|
||||||
public int itemCount;
|
.setSender(this.sender)
|
||||||
public int itemLevel;
|
.build();
|
||||||
|
}
|
||||||
public MailItem() {
|
}
|
||||||
this.itemId = 11101;
|
|
||||||
this.itemCount = 1;
|
@Entity
|
||||||
this.itemLevel = 1;
|
public static class MailItem {
|
||||||
}
|
public int itemId;
|
||||||
|
public int itemCount;
|
||||||
public MailItem(int itemId) {
|
public int itemLevel;
|
||||||
this(itemId, 1);
|
|
||||||
}
|
public MailItem() {
|
||||||
|
this.itemId = 11101;
|
||||||
public MailItem(int itemId, int itemCount) {
|
this.itemCount = 1;
|
||||||
this(itemId, itemCount, 1);
|
this.itemLevel = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MailItem(int itemId, int itemCount, int itemLevel) {
|
public MailItem(int itemId) {
|
||||||
this.itemId = itemId;
|
this(itemId, 1);
|
||||||
this.itemCount = itemCount;
|
}
|
||||||
this.itemLevel = itemLevel;
|
|
||||||
}
|
public MailItem(int itemId, int itemCount) {
|
||||||
|
this(itemId, itemCount, 1);
|
||||||
public MailItemOuterClass.MailItem toProto() {
|
}
|
||||||
return newBuilder().setEquipParam(EquipParam.newBuilder()
|
|
||||||
.setItemId(this.itemId)
|
public MailItem(int itemId, int itemCount, int itemLevel) {
|
||||||
.setItemNum(this.itemCount)
|
this.itemId = itemId;
|
||||||
.setItemLevel(this.itemLevel)
|
this.itemCount = itemCount;
|
||||||
.setPromoteLevel(0)//mock
|
this.itemLevel = itemLevel;
|
||||||
.build())
|
}
|
||||||
.build();
|
|
||||||
}
|
public MailItemOuterClass.MailItem toProto() {
|
||||||
}
|
return newBuilder()
|
||||||
|
.setEquipParam(
|
||||||
public void save() {
|
EquipParam.newBuilder()
|
||||||
if (this.expireTime * 1000 < System.currentTimeMillis()) {
|
.setItemId(this.itemId)
|
||||||
DatabaseHelper.deleteMail(this);
|
.setItemNum(this.itemCount)
|
||||||
} else {
|
.setItemLevel(this.itemLevel)
|
||||||
DatabaseHelper.saveMail(this);
|
.setPromoteLevel(0) // mock
|
||||||
}
|
.build())
|
||||||
}
|
.build();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
if (this.expireTime * 1000 < System.currentTimeMillis()) {
|
||||||
|
DatabaseHelper.deleteMail(this);
|
||||||
|
} else {
|
||||||
|
DatabaseHelper.saveMail(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,133 +1,146 @@
|
|||||||
package emu.grasscutter.game.managers.blossom;
|
package emu.grasscutter.game.managers.blossom;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
import emu.grasscutter.game.entity.EntityMonster;
|
import emu.grasscutter.game.entity.EntityMonster;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.data.SceneBossChest;
|
import emu.grasscutter.scripts.data.SceneBossChest;
|
||||||
import emu.grasscutter.scripts.data.SceneGadget;
|
import emu.grasscutter.scripts.data.SceneGadget;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayList;
|
||||||
import java.util.ArrayList;
|
import java.util.List;
|
||||||
import java.util.List;
|
import java.util.Queue;
|
||||||
import java.util.Queue;
|
|
||||||
|
public final class BlossomActivity {
|
||||||
public final class BlossomActivity {
|
|
||||||
|
private final SceneGroup tempSceneGroup;
|
||||||
private final SceneGroup tempSceneGroup;
|
private final WorldChallenge challenge;
|
||||||
private final WorldChallenge challenge;
|
private final EntityGadget gadget;
|
||||||
private final EntityGadget gadget;
|
private EntityGadget chest;
|
||||||
private EntityGadget chest;
|
private int step;
|
||||||
private int step;
|
private final int goal;
|
||||||
private final int goal;
|
private int generatedCount;
|
||||||
private int generatedCount;
|
private final int worldLevel;
|
||||||
private final int worldLevel;
|
private boolean pass = false;
|
||||||
private boolean pass=false;
|
private final List<EntityMonster> activeMonsters = new ArrayList<>();
|
||||||
private final List<EntityMonster> activeMonsters = new ArrayList<>();
|
private final Queue<Integer> candidateMonsters = new ArrayDeque<>();
|
||||||
private final Queue<Integer> candidateMonsters = new ArrayDeque<>();
|
private static final int BLOOMING_GADGET_ID = 70210109;
|
||||||
private static final int BLOOMING_GADGET_ID = 70210109;
|
|
||||||
public BlossomActivity(EntityGadget entityGadget, List<Integer> monsters, int timeout, int worldLevel) {
|
public BlossomActivity(
|
||||||
this.tempSceneGroup = new SceneGroup();
|
EntityGadget entityGadget, List<Integer> monsters, int timeout, int worldLevel) {
|
||||||
this.tempSceneGroup.id = entityGadget.getId();
|
this.tempSceneGroup = new SceneGroup();
|
||||||
this.gadget=entityGadget;
|
this.tempSceneGroup.id = entityGadget.getId();
|
||||||
this.step=0;
|
this.gadget = entityGadget;
|
||||||
this.goal = monsters.size();
|
this.step = 0;
|
||||||
this.candidateMonsters.addAll(monsters);
|
this.goal = monsters.size();
|
||||||
this.worldLevel = worldLevel;
|
this.candidateMonsters.addAll(monsters);
|
||||||
ArrayList<ChallengeTrigger> challengeTriggers = new ArrayList<>();
|
this.worldLevel = worldLevel;
|
||||||
this.challenge = new WorldChallenge(entityGadget.getScene(),
|
ArrayList<ChallengeTrigger> challengeTriggers = new ArrayList<>();
|
||||||
tempSceneGroup,
|
this.challenge =
|
||||||
1,
|
new WorldChallenge(
|
||||||
1,
|
entityGadget.getScene(),
|
||||||
List.of(goal, timeout),
|
tempSceneGroup,
|
||||||
timeout,
|
1,
|
||||||
goal, challengeTriggers);
|
1,
|
||||||
challengeTriggers.add(new KillMonsterCountTrigger());
|
List.of(goal, timeout),
|
||||||
//this.challengeTriggers.add(new InTimeTrigger());
|
timeout,
|
||||||
}
|
goal,
|
||||||
public WorldChallenge getChallenge() {
|
challengeTriggers);
|
||||||
return this.challenge;
|
challengeTriggers.add(new KillMonsterCountTrigger());
|
||||||
}
|
// this.challengeTriggers.add(new InTimeTrigger());
|
||||||
public void setMonsters(List<EntityMonster> monsters) {
|
}
|
||||||
this.activeMonsters.clear();
|
|
||||||
this.activeMonsters.addAll(monsters);
|
public WorldChallenge getChallenge() {
|
||||||
for (EntityMonster monster : monsters) {
|
return this.challenge;
|
||||||
monster.setGroupId(this.tempSceneGroup.id);
|
}
|
||||||
}
|
|
||||||
}
|
public void setMonsters(List<EntityMonster> monsters) {
|
||||||
public int getAliveMonstersCount() {
|
this.activeMonsters.clear();
|
||||||
int count=0;
|
this.activeMonsters.addAll(monsters);
|
||||||
for (EntityMonster monster: activeMonsters) {
|
for (EntityMonster monster : monsters) {
|
||||||
if (monster.isAlive()) {
|
monster.setGroupId(this.tempSceneGroup.id);
|
||||||
count++;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return count;
|
public int getAliveMonstersCount() {
|
||||||
}
|
int count = 0;
|
||||||
public boolean getPass() {
|
for (EntityMonster monster : activeMonsters) {
|
||||||
return pass;
|
if (monster.isAlive()) {
|
||||||
}
|
count++;
|
||||||
public void start() {
|
}
|
||||||
challenge.start();
|
}
|
||||||
}
|
return count;
|
||||||
public void onTick() {
|
}
|
||||||
Scene scene = gadget.getScene();
|
|
||||||
Position pos = gadget.getPosition();
|
public boolean getPass() {
|
||||||
if (getAliveMonstersCount() <= 2) {
|
return pass;
|
||||||
if (generatedCount<goal) {
|
}
|
||||||
step++;
|
|
||||||
|
public void start() {
|
||||||
var worldLevelData = GameData.getWorldLevelDataMap().get(worldLevel);
|
challenge.start();
|
||||||
int worldLevelOverride = 0;
|
}
|
||||||
if (worldLevelData != null) {
|
|
||||||
worldLevelOverride = worldLevelData.getMonsterLevel();
|
public void onTick() {
|
||||||
}
|
Scene scene = gadget.getScene();
|
||||||
|
Position pos = gadget.getPosition();
|
||||||
List<EntityMonster> newMonsters = new ArrayList<>();
|
if (getAliveMonstersCount() <= 2) {
|
||||||
int willSpawn = Utils.randomRange(3,5);
|
if (generatedCount < goal) {
|
||||||
if (generatedCount+willSpawn>goal) {
|
step++;
|
||||||
willSpawn = goal - generatedCount;
|
|
||||||
}
|
var worldLevelData = GameData.getWorldLevelDataMap().get(worldLevel);
|
||||||
generatedCount+=willSpawn;
|
int worldLevelOverride = 0;
|
||||||
for (int i = 0; i < willSpawn; i++) {
|
if (worldLevelData != null) {
|
||||||
var monsterData = GameData.getMonsterDataMap().get(candidateMonsters.poll());
|
worldLevelOverride = worldLevelData.getMonsterLevel();
|
||||||
int level = scene.getEntityLevel(1, worldLevelOverride);
|
}
|
||||||
EntityMonster entity = new EntityMonster(scene, monsterData, pos.nearby2d(4f), level);
|
|
||||||
scene.addEntity(entity);
|
List<EntityMonster> newMonsters = new ArrayList<>();
|
||||||
newMonsters.add(entity);
|
int willSpawn = Utils.randomRange(3, 5);
|
||||||
}
|
if (generatedCount + willSpawn > goal) {
|
||||||
setMonsters(newMonsters);
|
willSpawn = goal - generatedCount;
|
||||||
}else {
|
}
|
||||||
if (getAliveMonstersCount() == 0) {
|
generatedCount += willSpawn;
|
||||||
this.pass = true;
|
for (int i = 0; i < willSpawn; i++) {
|
||||||
this.challenge.done();
|
var monsterData = GameData.getMonsterDataMap().get(candidateMonsters.poll());
|
||||||
}
|
int level = scene.getEntityLevel(1, worldLevelOverride);
|
||||||
}
|
EntityMonster entity = new EntityMonster(scene, monsterData, pos.nearby2d(4f), level);
|
||||||
}
|
scene.addEntity(entity);
|
||||||
}
|
newMonsters.add(entity);
|
||||||
public EntityGadget getGadget() {
|
}
|
||||||
return gadget;
|
setMonsters(newMonsters);
|
||||||
}
|
} else {
|
||||||
public EntityGadget getChest() {
|
if (getAliveMonstersCount() == 0) {
|
||||||
if (chest==null) {
|
this.pass = true;
|
||||||
EntityGadget rewardGadget = new EntityGadget(gadget.getScene(), BLOOMING_GADGET_ID, gadget.getPosition());
|
this.challenge.done();
|
||||||
SceneGadget metaGadget = new SceneGadget();
|
}
|
||||||
metaGadget.boss_chest = new SceneBossChest();
|
}
|
||||||
metaGadget.boss_chest.resin = 20;
|
}
|
||||||
rewardGadget.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, Float.POSITIVE_INFINITY);
|
}
|
||||||
rewardGadget.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, Float.POSITIVE_INFINITY);
|
|
||||||
rewardGadget.setFightProperty(FightProperty.FIGHT_PROP_MAX_HP, Float.POSITIVE_INFINITY);
|
public EntityGadget getGadget() {
|
||||||
rewardGadget.setMetaGadget(metaGadget);
|
return gadget;
|
||||||
rewardGadget.buildContent();
|
}
|
||||||
chest = rewardGadget;
|
|
||||||
}
|
public EntityGadget getChest() {
|
||||||
return chest;
|
if (chest == null) {
|
||||||
}
|
EntityGadget rewardGadget =
|
||||||
}
|
new EntityGadget(gadget.getScene(), BLOOMING_GADGET_ID, gadget.getPosition());
|
||||||
|
SceneGadget metaGadget = new SceneGadget();
|
||||||
|
metaGadget.boss_chest = new SceneBossChest();
|
||||||
|
metaGadget.boss_chest.resin = 20;
|
||||||
|
rewardGadget.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, Float.POSITIVE_INFINITY);
|
||||||
|
rewardGadget.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, Float.POSITIVE_INFINITY);
|
||||||
|
rewardGadget.setFightProperty(FightProperty.FIGHT_PROP_MAX_HP, Float.POSITIVE_INFINITY);
|
||||||
|
rewardGadget.setMetaGadget(metaGadget);
|
||||||
|
rewardGadget.buildContent();
|
||||||
|
chest = rewardGadget;
|
||||||
|
}
|
||||||
|
return chest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,418 +1,420 @@
|
|||||||
package emu.grasscutter.game.managers.energy;
|
package emu.grasscutter.game.managers.energy;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
||||||
|
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.data.DataLoader;
|
import emu.grasscutter.data.DataLoader;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.excels.ItemData;
|
import emu.grasscutter.data.excels.ItemData;
|
||||||
import emu.grasscutter.data.excels.avatar.AvatarSkillDepotData;
|
import emu.grasscutter.data.excels.avatar.AvatarSkillDepotData;
|
||||||
import emu.grasscutter.data.excels.monster.MonsterData.HpDrops;
|
import emu.grasscutter.data.excels.monster.MonsterData.HpDrops;
|
||||||
import emu.grasscutter.game.avatar.Avatar;
|
import emu.grasscutter.game.avatar.Avatar;
|
||||||
import emu.grasscutter.game.entity.*;
|
import emu.grasscutter.game.entity.*;
|
||||||
import emu.grasscutter.game.player.BasePlayerManager;
|
import emu.grasscutter.game.player.BasePlayerManager;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.ElementType;
|
import emu.grasscutter.game.props.ElementType;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.game.props.MonsterType;
|
import emu.grasscutter.game.props.MonsterType;
|
||||||
import emu.grasscutter.game.props.WeaponType;
|
import emu.grasscutter.game.props.WeaponType;
|
||||||
import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall;
|
import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall;
|
||||||
import emu.grasscutter.net.proto.AbilityIdentifierOuterClass.AbilityIdentifier;
|
import emu.grasscutter.net.proto.AbilityIdentifierOuterClass.AbilityIdentifier;
|
||||||
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
||||||
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
||||||
import emu.grasscutter.net.proto.ChangeEnergyReasonOuterClass.ChangeEnergyReason;
|
import emu.grasscutter.net.proto.ChangeEnergyReasonOuterClass.ChangeEnergyReason;
|
||||||
import emu.grasscutter.net.proto.EvtBeingHitInfoOuterClass.EvtBeingHitInfo;
|
import emu.grasscutter.net.proto.EvtBeingHitInfoOuterClass.EvtBeingHitInfo;
|
||||||
import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
|
import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
import lombok.Getter;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.List;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.Optional;
|
import lombok.Getter;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
|
public class EnergyManager extends BasePlayerManager {
|
||||||
public class EnergyManager extends BasePlayerManager {
|
private static final Int2ObjectMap<List<EnergyDropInfo>> energyDropData =
|
||||||
private static final Int2ObjectMap<List<EnergyDropInfo>> energyDropData =
|
new Int2ObjectOpenHashMap<>();
|
||||||
new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<List<SkillParticleGenerationInfo>>
|
||||||
private static final Int2ObjectMap<List<SkillParticleGenerationInfo>>
|
skillParticleGenerationData = new Int2ObjectOpenHashMap<>();
|
||||||
skillParticleGenerationData = new Int2ObjectOpenHashMap<>();
|
private final Object2IntMap<EntityAvatar> avatarNormalProbabilities;
|
||||||
private final Object2IntMap<EntityAvatar> avatarNormalProbabilities;
|
@Getter private boolean energyUsage; // Should energy usage be enabled for this player?
|
||||||
@Getter private boolean energyUsage; // Should energy usage be enabled for this player?
|
|
||||||
|
public EnergyManager(Player player) {
|
||||||
public EnergyManager(Player player) {
|
super(player);
|
||||||
super(player);
|
this.avatarNormalProbabilities = new Object2IntOpenHashMap<>();
|
||||||
this.avatarNormalProbabilities = new Object2IntOpenHashMap<>();
|
this.energyUsage = GAME_OPTIONS.energyUsage;
|
||||||
this.energyUsage = GAME_OPTIONS.energyUsage;
|
}
|
||||||
}
|
|
||||||
|
public static void initialize() {
|
||||||
public static void initialize() {
|
// Read the data we need for monster energy drops.
|
||||||
// Read the data we need for monster energy drops.
|
try {
|
||||||
try {
|
DataLoader.loadList("EnergyDrop.json", EnergyDropEntry.class)
|
||||||
DataLoader.loadList("EnergyDrop.json", EnergyDropEntry.class)
|
.forEach(
|
||||||
.forEach(
|
entry -> {
|
||||||
entry -> {
|
energyDropData.put(entry.getDropId(), entry.getDropList());
|
||||||
energyDropData.put(entry.getDropId(), entry.getDropList());
|
});
|
||||||
});
|
|
||||||
|
Grasscutter.getLogger().debug("Energy drop data successfully loaded.");
|
||||||
Grasscutter.getLogger().debug("Energy drop data successfully loaded.");
|
} catch (Exception ex) {
|
||||||
} catch (Exception ex) {
|
Grasscutter.getLogger().error("Unable to load energy drop data.", ex);
|
||||||
Grasscutter.getLogger().error("Unable to load energy drop data.", ex);
|
}
|
||||||
}
|
|
||||||
|
// Read the data for particle generation from skills
|
||||||
// Read the data for particle generation from skills
|
try {
|
||||||
try {
|
DataLoader.loadList("SkillParticleGeneration.json", SkillParticleGenerationEntry.class)
|
||||||
DataLoader.loadList("SkillParticleGeneration.json", SkillParticleGenerationEntry.class)
|
.forEach(
|
||||||
.forEach(
|
entry -> {
|
||||||
entry -> {
|
skillParticleGenerationData.put(entry.getAvatarId(), entry.getAmountList());
|
||||||
skillParticleGenerationData.put(entry.getAvatarId(), entry.getAmountList());
|
});
|
||||||
});
|
|
||||||
|
Grasscutter.getLogger().debug("Skill particle generation data successfully loaded.");
|
||||||
Grasscutter.getLogger().debug("Skill particle generation data successfully loaded.");
|
} catch (Exception ex) {
|
||||||
} catch (Exception ex) {
|
Grasscutter.getLogger().error("Unable to load skill particle generation data data.", ex);
|
||||||
Grasscutter.getLogger().error("Unable to load skill particle generation data data.", ex);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/** Particle creation for elemental skills. */
|
||||||
/** Particle creation for elemental skills. */
|
private int getBallCountForAvatar(int avatarId) {
|
||||||
private int getBallCountForAvatar(int avatarId) {
|
// We default to two particles.
|
||||||
// We default to two particles.
|
int count = 2;
|
||||||
int count = 2;
|
|
||||||
|
// If we don't have any data for this avatar, stop.
|
||||||
// If we don't have any data for this avatar, stop.
|
if (!skillParticleGenerationData.containsKey(avatarId)) {
|
||||||
if (!skillParticleGenerationData.containsKey(avatarId)) {
|
Grasscutter.getLogger().warn("No particle generation data for avatarId {} found.", avatarId);
|
||||||
Grasscutter.getLogger().warn("No particle generation data for avatarId {} found.", avatarId);
|
}
|
||||||
}
|
// If we do have data, roll for how many particles we should generate.
|
||||||
// If we do have data, roll for how many particles we should generate.
|
else {
|
||||||
else {
|
int roll = ThreadLocalRandom.current().nextInt(0, 100);
|
||||||
int roll = ThreadLocalRandom.current().nextInt(0, 100);
|
int percentageStack = 0;
|
||||||
int percentageStack = 0;
|
for (SkillParticleGenerationInfo info : skillParticleGenerationData.get(avatarId)) {
|
||||||
for (SkillParticleGenerationInfo info : skillParticleGenerationData.get(avatarId)) {
|
int chance = info.getChance();
|
||||||
int chance = info.getChance();
|
percentageStack += chance;
|
||||||
percentageStack += chance;
|
if (roll < percentageStack) {
|
||||||
if (roll < percentageStack) {
|
count = info.getValue();
|
||||||
count = info.getValue();
|
break;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Done.
|
||||||
// Done.
|
return count;
|
||||||
return count;
|
}
|
||||||
}
|
|
||||||
|
private int getBallIdForElement(ElementType element) {
|
||||||
private int getBallIdForElement(ElementType element) {
|
// If we have no element, we default to an element-less particle.
|
||||||
// If we have no element, we default to an element-less particle.
|
if (element == null) {
|
||||||
if (element == null) {
|
return 2024;
|
||||||
return 2024;
|
}
|
||||||
}
|
|
||||||
|
// Otherwise, we determine the particle's ID based on the element.
|
||||||
// Otherwise, we determine the particle's ID based on the element.
|
return switch (element) {
|
||||||
return switch (element) {
|
case Fire -> 2017;
|
||||||
case Fire -> 2017;
|
case Water -> 2018;
|
||||||
case Water -> 2018;
|
case Grass -> 2019;
|
||||||
case Grass -> 2019;
|
case Electric -> 2020;
|
||||||
case Electric -> 2020;
|
case Wind -> 2021;
|
||||||
case Wind -> 2021;
|
case Ice -> 2022;
|
||||||
case Ice -> 2022;
|
case Rock -> 2023;
|
||||||
case Rock -> 2023;
|
default -> 2024;
|
||||||
default -> 2024;
|
};
|
||||||
};
|
}
|
||||||
}
|
|
||||||
|
public void handleGenerateElemBall(AbilityInvokeEntry invoke)
|
||||||
public void handleGenerateElemBall(AbilityInvokeEntry invoke)
|
throws InvalidProtocolBufferException {
|
||||||
throws InvalidProtocolBufferException {
|
// ToDo:
|
||||||
// ToDo:
|
// This is also called when a weapon like Favonius Warbow etc. creates energy through its
|
||||||
// This is also called when a weapon like Favonius Warbow etc. creates energy through its
|
// passive.
|
||||||
// passive.
|
// We are not handling this correctly at the moment.
|
||||||
// We are not handling this correctly at the moment.
|
|
||||||
|
// Get action info.
|
||||||
// Get action info.
|
AbilityActionGenerateElemBall action =
|
||||||
AbilityActionGenerateElemBall action =
|
AbilityActionGenerateElemBall.parseFrom(invoke.getAbilityData());
|
||||||
AbilityActionGenerateElemBall.parseFrom(invoke.getAbilityData());
|
if (action == null) {
|
||||||
if (action == null) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
// Default to an elementless particle.
|
||||||
// Default to an elementless particle.
|
int itemId = 2024;
|
||||||
int itemId = 2024;
|
|
||||||
|
// Generate 2 particles by default.
|
||||||
// Generate 2 particles by default.
|
int amount = 2;
|
||||||
int amount = 2;
|
|
||||||
|
// Try to get the casting avatar from the player's party.
|
||||||
// Try to get the casting avatar from the player's party.
|
Optional<EntityAvatar> avatarEntity =
|
||||||
Optional<EntityAvatar> avatarEntity =
|
this.getCastingAvatarEntityForEnergy(invoke.getEntityId());
|
||||||
this.getCastingAvatarEntityForEnergy(invoke.getEntityId());
|
|
||||||
|
// Bug: invokes twice sometimes, Ayato, Keqing
|
||||||
// Bug: invokes twice sometimes, Ayato, Keqing
|
// ToDo: deal with press, hold difference. deal with charge(Beidou, Yunjin)
|
||||||
// ToDo: deal with press, hold difference. deal with charge(Beidou, Yunjin)
|
if (avatarEntity.isPresent()) {
|
||||||
if (avatarEntity.isPresent()) {
|
Avatar avatar = avatarEntity.get().getAvatar();
|
||||||
Avatar avatar = avatarEntity.get().getAvatar();
|
|
||||||
|
if (avatar != null) {
|
||||||
if (avatar != null) {
|
int avatarId = avatar.getAvatarId();
|
||||||
int avatarId = avatar.getAvatarId();
|
AvatarSkillDepotData skillDepotData = avatar.getSkillDepot();
|
||||||
AvatarSkillDepotData skillDepotData = avatar.getSkillDepot();
|
|
||||||
|
// Determine how many particles we need to create for this avatar.
|
||||||
// Determine how many particles we need to create for this avatar.
|
amount = this.getBallCountForAvatar(avatarId);
|
||||||
amount = this.getBallCountForAvatar(avatarId);
|
|
||||||
|
// Determine the avatar's element, and based on that the ID of the
|
||||||
// Determine the avatar's element, and based on that the ID of the
|
// particles we have to generate.
|
||||||
// particles we have to generate.
|
if (skillDepotData != null) {
|
||||||
if (skillDepotData != null) {
|
ElementType element = skillDepotData.getElementType();
|
||||||
ElementType element = skillDepotData.getElementType();
|
itemId = this.getBallIdForElement(element);
|
||||||
itemId = this.getBallIdForElement(element);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Generate the particles.
|
||||||
// Generate the particles.
|
var pos = new Position(action.getPos());
|
||||||
var pos = new Position(action.getPos());
|
for (int i = 0; i < amount; i++) {
|
||||||
for (int i = 0; i < amount; i++) {
|
this.generateElemBall(itemId, pos, 1);
|
||||||
this.generateElemBall(itemId, pos, 1);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
/**
|
* Energy generation for NAs/CAs.
|
||||||
* Energy generation for NAs/CAs.
|
*
|
||||||
*
|
* @param avatar The avatar.
|
||||||
* @param avatar The avatar.
|
*/
|
||||||
*/
|
private void generateEnergyForNormalAndCharged(EntityAvatar avatar) {
|
||||||
private void generateEnergyForNormalAndCharged(EntityAvatar avatar) {
|
// This logic is based on the descriptions given in
|
||||||
// This logic is based on the descriptions given in
|
// https://genshin-impact.fandom.com/wiki/Energy#Energy_Generated_by_Normal_Attacks
|
||||||
// https://genshin-impact.fandom.com/wiki/Energy#Energy_Generated_by_Normal_Attacks
|
// https://library.keqingmains.com/combat-mechanics/energy#auto-attacking
|
||||||
// https://library.keqingmains.com/combat-mechanics/energy#auto-attacking
|
// Those descriptions are lacking in some information, so this implementation most likely
|
||||||
// Those descriptions are lacking in some information, so this implementation most likely
|
// does not fully replicate the behavior of the official server. Open questions:
|
||||||
// does not fully replicate the behavior of the official server. Open questions:
|
// - Does the probability for a character reset after some time?
|
||||||
// - Does the probability for a character reset after some time?
|
// - Does the probability for a character reset when switching them out?
|
||||||
// - Does the probability for a character reset when switching them out?
|
// - Does this really count every individual hit separately?
|
||||||
// - Does this really count every individual hit separately?
|
|
||||||
|
// Get the avatar's weapon type.
|
||||||
// Get the avatar's weapon type.
|
WeaponType weaponType = avatar.getAvatar().getAvatarData().getWeaponType();
|
||||||
WeaponType weaponType = avatar.getAvatar().getAvatarData().getWeaponType();
|
|
||||||
|
// Check if we already have probability data for this avatar. If not, insert it.
|
||||||
// Check if we already have probability data for this avatar. If not, insert it.
|
if (!this.avatarNormalProbabilities.containsKey(avatar)) {
|
||||||
if (!this.avatarNormalProbabilities.containsKey(avatar)) {
|
this.avatarNormalProbabilities.put(avatar, weaponType.getEnergyGainInitialProbability());
|
||||||
this.avatarNormalProbabilities.put(avatar, weaponType.getEnergyGainInitialProbability());
|
}
|
||||||
}
|
|
||||||
|
// Roll for energy.
|
||||||
// Roll for energy.
|
int currentProbability = this.avatarNormalProbabilities.getInt(avatar);
|
||||||
int currentProbability = this.avatarNormalProbabilities.getInt(avatar);
|
int roll = ThreadLocalRandom.current().nextInt(0, 100);
|
||||||
int roll = ThreadLocalRandom.current().nextInt(0, 100);
|
|
||||||
|
// If the player wins the roll, we increase the avatar's energy and reset the probability.
|
||||||
// If the player wins the roll, we increase the avatar's energy and reset the probability.
|
if (roll < currentProbability) {
|
||||||
if (roll < currentProbability) {
|
avatar.addEnergy(1.0f, PropChangeReason.PROP_CHANGE_REASON_ABILITY, true);
|
||||||
avatar.addEnergy(1.0f, PropChangeReason.PROP_CHANGE_REASON_ABILITY, true);
|
this.avatarNormalProbabilities.put(avatar, weaponType.getEnergyGainInitialProbability());
|
||||||
this.avatarNormalProbabilities.put(avatar, weaponType.getEnergyGainInitialProbability());
|
}
|
||||||
}
|
// Otherwise, we increase the probability for the next hit.
|
||||||
// Otherwise, we increase the probability for the next hit.
|
else {
|
||||||
else {
|
this.avatarNormalProbabilities.put(
|
||||||
this.avatarNormalProbabilities.put(
|
avatar, currentProbability + weaponType.getEnergyGainIncreaseProbability());
|
||||||
avatar, currentProbability + weaponType.getEnergyGainIncreaseProbability());
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public void handleAttackHit(EvtBeingHitInfo hitInfo) {
|
||||||
public void handleAttackHit(EvtBeingHitInfo hitInfo) {
|
// Get the attack result.
|
||||||
// Get the attack result.
|
AttackResult attackRes = hitInfo.getAttackResult();
|
||||||
AttackResult attackRes = hitInfo.getAttackResult();
|
|
||||||
|
// Make sure the attack was performed by the currently active avatar. If not, we ignore the hit.
|
||||||
// Make sure the attack was performed by the currently active avatar. If not, we ignore the hit.
|
Optional<EntityAvatar> attackerEntity =
|
||||||
Optional<EntityAvatar> attackerEntity =
|
this.getCastingAvatarEntityForEnergy(attackRes.getAttackerId());
|
||||||
this.getCastingAvatarEntityForEnergy(attackRes.getAttackerId());
|
if (attackerEntity.isEmpty()
|
||||||
if (attackerEntity.isEmpty()
|
|| this.player.getTeamManager().getCurrentAvatarEntity().getId()
|
||||||
|| this.player.getTeamManager().getCurrentAvatarEntity().getId()
|
!= attackerEntity.get().getId()) {
|
||||||
!= attackerEntity.get().getId()) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
// Make sure the target is an actual enemy.
|
||||||
// Make sure the target is an actual enemy.
|
GameEntity targetEntity = this.player.getScene().getEntityById(attackRes.getDefenseId());
|
||||||
GameEntity targetEntity = this.player.getScene().getEntityById(attackRes.getDefenseId());
|
if (!(targetEntity instanceof EntityMonster targetMonster)) {
|
||||||
if (!(targetEntity instanceof EntityMonster targetMonster)) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
MonsterType targetType = targetMonster.getMonsterData().getType();
|
||||||
MonsterType targetType = targetMonster.getMonsterData().getType();
|
if (targetType != MonsterType.MONSTER_ORDINARY && targetType != MonsterType.MONSTER_BOSS) {
|
||||||
if (targetType != MonsterType.MONSTER_ORDINARY && targetType != MonsterType.MONSTER_BOSS) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
// Get the ability that caused this hit.
|
||||||
// Get the ability that caused this hit.
|
AbilityIdentifier ability = attackRes.getAbilityIdentifier();
|
||||||
AbilityIdentifier ability = attackRes.getAbilityIdentifier();
|
|
||||||
|
// Make sure there is no actual "ability" associated with the hit. For now, this is how we
|
||||||
// Make sure there is no actual "ability" associated with the hit. For now, this is how we
|
// identify normal and charged attacks. Note that this is not completely accurate:
|
||||||
// identify normal and charged attacks. Note that this is not completely accurate:
|
// - Many character's charged attacks have an ability associated with them. This means that,
|
||||||
// - Many character's charged attacks have an ability associated with them. This means that,
|
// for now, we don't identify charged attacks reliably.
|
||||||
// for now, we don't identify charged attacks reliably.
|
// - There might also be some cases where we incorrectly identify something as a normal or
|
||||||
// - There might also be some cases where we incorrectly identify something as a normal or
|
// charged attack that is not (Diluc's E?).
|
||||||
// charged attack that is not (Diluc's E?).
|
// - Catalyst normal attacks have an ability, so we don't handle those for now.
|
||||||
// - Catalyst normal attacks have an ability, so we don't handle those for now.
|
// ToDo: Fix all of that.
|
||||||
// ToDo: Fix all of that.
|
if (ability != AbilityIdentifier.getDefaultInstance()) {
|
||||||
if (ability != AbilityIdentifier.getDefaultInstance()) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
// Handle the energy generation.
|
||||||
// Handle the energy generation.
|
this.generateEnergyForNormalAndCharged(attackerEntity.get());
|
||||||
this.generateEnergyForNormalAndCharged(attackerEntity.get());
|
}
|
||||||
}
|
|
||||||
|
/*
|
||||||
/*
|
* Energy logic related to using skills.
|
||||||
* Energy logic related to using skills.
|
*/
|
||||||
*/
|
|
||||||
|
private void handleBurstCast(Avatar avatar, int skillId) {
|
||||||
private void handleBurstCast(Avatar avatar, int skillId) {
|
// Don't do anything if energy usage is disabled.
|
||||||
// Don't do anything if energy usage is disabled.
|
if (!GAME_OPTIONS.energyUsage || !this.energyUsage) {
|
||||||
if (!GAME_OPTIONS.energyUsage || !this.energyUsage) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
// If the cast skill was a burst, consume energy.
|
||||||
// If the cast skill was a burst, consume energy.
|
if (avatar.getSkillDepot() != null && skillId == avatar.getSkillDepot().getEnergySkill()) {
|
||||||
if (avatar.getSkillDepot() != null && skillId == avatar.getSkillDepot().getEnergySkill()) {
|
avatar.getAsEntity().clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_SKILL_START);
|
||||||
avatar.getAsEntity().clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_SKILL_START);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public void handleEvtDoSkillSuccNotify(GameSession session, int skillId, int casterId) {
|
||||||
public void handleEvtDoSkillSuccNotify(GameSession session, int skillId, int casterId) {
|
// Determine the entity that has cast the skill. Cancel if we can't find that avatar.
|
||||||
// Determine the entity that has cast the skill. Cancel if we can't find that avatar.
|
Optional<EntityAvatar> caster =
|
||||||
Optional<EntityAvatar> caster =
|
this.player.getTeamManager().getActiveTeam().stream()
|
||||||
this.player.getTeamManager().getActiveTeam().stream()
|
.filter(character -> character.getId() == casterId)
|
||||||
.filter(character -> character.getId() == casterId)
|
.findFirst();
|
||||||
.findFirst();
|
|
||||||
|
if (caster.isEmpty()) {
|
||||||
if (caster.isEmpty()) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
Avatar avatar = caster.get().getAvatar();
|
||||||
Avatar avatar = caster.get().getAvatar();
|
|
||||||
|
// Handle elemental burst.
|
||||||
// Handle elemental burst.
|
this.handleBurstCast(avatar, skillId);
|
||||||
this.handleBurstCast(avatar, skillId);
|
}
|
||||||
}
|
|
||||||
|
/*
|
||||||
/*
|
* Monster energy drops.
|
||||||
* Monster energy drops.
|
*/
|
||||||
*/
|
|
||||||
|
private void generateElemBallDrops(EntityMonster monster, int dropId) {
|
||||||
private void generateElemBallDrops(EntityMonster monster, int dropId) {
|
// Generate all drops specified for the given drop id.
|
||||||
// Generate all drops specified for the given drop id.
|
if (!energyDropData.containsKey(dropId)) {
|
||||||
if (!energyDropData.containsKey(dropId)) {
|
Grasscutter.getLogger().warn("No drop data for dropId {} found.", dropId);
|
||||||
Grasscutter.getLogger().warn("No drop data for dropId {} found.", dropId);
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
for (EnergyDropInfo info : energyDropData.get(dropId)) {
|
||||||
for (EnergyDropInfo info : energyDropData.get(dropId)) {
|
this.generateElemBall(info.getBallId(), monster.getPosition(), info.getCount());
|
||||||
this.generateElemBall(info.getBallId(), monster.getPosition(), info.getCount());
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public void handleMonsterEnergyDrop(
|
||||||
public void handleMonsterEnergyDrop(
|
EntityMonster monster, float hpBeforeDamage, float hpAfterDamage) {
|
||||||
EntityMonster monster, float hpBeforeDamage, float hpAfterDamage) {
|
// Make sure this is actually a monster.
|
||||||
// Make sure this is actually a monster.
|
// Note that some wildlife also has that type, like boars or birds.
|
||||||
// Note that some wildlife also has that type, like boars or birds.
|
MonsterType type = monster.getMonsterData().getType();
|
||||||
MonsterType type = monster.getMonsterData().getType();
|
if (type != MonsterType.MONSTER_ORDINARY && type != MonsterType.MONSTER_BOSS) {
|
||||||
if (type != MonsterType.MONSTER_ORDINARY && type != MonsterType.MONSTER_BOSS) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
// Calculate the HP thresholds for before and after the damage was taken.
|
||||||
// Calculate the HP thresholds for before and after the damage was taken.
|
float maxHp = monster.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||||
float maxHp = monster.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
float thresholdBefore = hpBeforeDamage / maxHp;
|
||||||
float thresholdBefore = hpBeforeDamage / maxHp;
|
float thresholdAfter = hpAfterDamage / maxHp;
|
||||||
float thresholdAfter = hpAfterDamage / maxHp;
|
|
||||||
|
// Determine the thresholds the monster has passed, and generate drops based on that.
|
||||||
// Determine the thresholds the monster has passed, and generate drops based on that.
|
for (HpDrops drop : monster.getMonsterData().getHpDrops()) {
|
||||||
for (HpDrops drop : monster.getMonsterData().getHpDrops()) {
|
if (drop.getDropId() == 0) {
|
||||||
if (drop.getDropId() == 0) {
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
|
||||||
|
float threshold = drop.getHpPercent() / 100.0f;
|
||||||
float threshold = drop.getHpPercent() / 100.0f;
|
if (threshold < thresholdBefore && threshold >= thresholdAfter) {
|
||||||
if (threshold < thresholdBefore && threshold >= thresholdAfter) {
|
this.generateElemBallDrops(monster, drop.getDropId());
|
||||||
this.generateElemBallDrops(monster, drop.getDropId());
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Handle kill drops.
|
||||||
// Handle kill drops.
|
if (hpAfterDamage <= 0 && monster.getMonsterData().getKillDropId() != 0) {
|
||||||
if (hpAfterDamage <= 0 && monster.getMonsterData().getKillDropId() != 0) {
|
this.generateElemBallDrops(monster, monster.getMonsterData().getKillDropId());
|
||||||
this.generateElemBallDrops(monster, monster.getMonsterData().getKillDropId());
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/*
|
||||||
/*
|
* Utilities.
|
||||||
* Utilities.
|
*/
|
||||||
*/
|
|
||||||
|
private void generateElemBall(int ballId, Position position, int count) {
|
||||||
private void generateElemBall(int ballId, Position position, int count) {
|
// Generate a particle/orb with the specified parameters.
|
||||||
// Generate a particle/orb with the specified parameters.
|
ItemData itemData = GameData.getItemDataMap().get(ballId);
|
||||||
ItemData itemData = GameData.getItemDataMap().get(ballId);
|
if (itemData == null) {
|
||||||
if (itemData == null) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
EntityItem energyBall =
|
||||||
EntityItem energyBall =
|
new EntityItem(this.getPlayer().getScene(), this.getPlayer(), itemData, position, count);
|
||||||
new EntityItem(this.getPlayer().getScene(), this.getPlayer(), itemData, position, count);
|
this.getPlayer().getScene().addEntity(energyBall);
|
||||||
this.getPlayer().getScene().addEntity(energyBall);
|
}
|
||||||
}
|
|
||||||
|
private Optional<EntityAvatar> getCastingAvatarEntityForEnergy(int invokeEntityId) {
|
||||||
private Optional<EntityAvatar> getCastingAvatarEntityForEnergy(int invokeEntityId) {
|
// To determine the avatar that has cast the skill that caused the energy particle to be
|
||||||
// To determine the avatar that has cast the skill that caused the energy particle to be
|
// generated,
|
||||||
// generated,
|
// we have to look at the entity that has invoked the ability. This can either be that avatar
|
||||||
// we have to look at the entity that has invoked the ability. This can either be that avatar
|
// directly,
|
||||||
// directly,
|
// or it can be an `EntityClientGadget`, owned (some way up the owner hierarchy) by the avatar
|
||||||
// or it can be an `EntityClientGadget`, owned (some way up the owner hierarchy) by the avatar
|
// that cast the skill.
|
||||||
// that cast the skill.
|
|
||||||
|
// Try to get the invoking entity from the scene.
|
||||||
// Try to get the invoking entity from the scene.
|
GameEntity entity = this.player.getScene().getEntityById(invokeEntityId);
|
||||||
GameEntity entity = this.player.getScene().getEntityById(invokeEntityId);
|
|
||||||
|
// Determine the ID of the entity that originally cast this skill. If the scene entity is null,
|
||||||
// Determine the ID of the entity that originally cast this skill. If the scene entity is null,
|
// or not an `EntityClientGadget`, we assume that we are directly looking at the casting avatar
|
||||||
// or not an `EntityClientGadget`, we assume that we are directly looking at the casting avatar
|
// (the null case will happen if the avatar was switched out between casting the skill and the
|
||||||
// (the null case will happen if the avatar was switched out between casting the skill and the
|
// particle being generated). If the scene entity is an `EntityClientGadget`, we need to find
|
||||||
// particle being generated). If the scene entity is an `EntityClientGadget`, we need to find
|
// the
|
||||||
// the
|
// ID of the original owner of that gadget.
|
||||||
// ID of the original owner of that gadget.
|
int avatarEntityId =
|
||||||
int avatarEntityId =
|
(!(entity instanceof EntityClientGadget))
|
||||||
(!(entity instanceof EntityClientGadget))
|
? invokeEntityId
|
||||||
? invokeEntityId
|
: ((EntityClientGadget) entity).getOriginalOwnerEntityId();
|
||||||
: ((EntityClientGadget) entity).getOriginalOwnerEntityId();
|
|
||||||
|
// Finally, find the avatar entity in the player's team.
|
||||||
// Finally, find the avatar entity in the player's team.
|
return this.player.getTeamManager().getActiveTeam().stream()
|
||||||
return this.player.getTeamManager().getActiveTeam().stream()
|
.filter(character -> character.getId() == avatarEntityId)
|
||||||
.filter(character -> character.getId() == avatarEntityId)
|
.findFirst();
|
||||||
.findFirst();
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
/**
|
* Refills the energy of the active avatar.
|
||||||
* Refills the energy of the active avatar.
|
*
|
||||||
*
|
* @return True if the energy was refilled, false otherwise.
|
||||||
* @return True if the energy was refilled, false otherwise.
|
*/
|
||||||
*/
|
public boolean refillActiveEnergy() {
|
||||||
public boolean refillActiveEnergy() {
|
var activeEntity = this.player.getTeamManager().getCurrentAvatarEntity();
|
||||||
var activeEntity = this.player.getTeamManager().getCurrentAvatarEntity();
|
return activeEntity.addEnergy(
|
||||||
return activeEntity.addEnergy(activeEntity.getAvatar().getSkillDepot().getEnergySkillData().getCostElemVal());
|
activeEntity.getAvatar().getSkillDepot().getEnergySkillData().getCostElemVal());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refills the energy of the entire team.
|
* Refills the energy of the entire team.
|
||||||
*
|
*
|
||||||
* @param changeReason The reason for the energy change.
|
* @param changeReason The reason for the energy change.
|
||||||
* @param isFlat Whether the energy should be added as a flat value.
|
* @param isFlat Whether the energy should be added as a flat value.
|
||||||
*/
|
*/
|
||||||
public void refillTeamEnergy(PropChangeReason changeReason, boolean isFlat) {
|
public void refillTeamEnergy(PropChangeReason changeReason, boolean isFlat) {
|
||||||
for (var entityAvatar : this.player.getTeamManager().getActiveTeam()) {
|
for (var entityAvatar : this.player.getTeamManager().getActiveTeam()) {
|
||||||
// giving the exact amount read off the AvatarSkillData.json
|
// giving the exact amount read off the AvatarSkillData.json
|
||||||
entityAvatar.addEnergy(entityAvatar.getAvatar().getSkillDepot()
|
entityAvatar.addEnergy(
|
||||||
.getEnergySkillData().getCostElemVal(), changeReason, isFlat);
|
entityAvatar.getAvatar().getSkillDepot().getEnergySkillData().getCostElemVal(),
|
||||||
}
|
changeReason,
|
||||||
}
|
isFlat);
|
||||||
|
}
|
||||||
public void setEnergyUsage(boolean energyUsage) {
|
}
|
||||||
this.energyUsage = energyUsage;
|
|
||||||
if (!energyUsage) { // Refill team energy if usage is disabled
|
public void setEnergyUsage(boolean energyUsage) {
|
||||||
for (EntityAvatar entityAvatar : this.player.getTeamManager().getActiveTeam()) {
|
this.energyUsage = energyUsage;
|
||||||
entityAvatar.addEnergy(1000, PropChangeReason.PROP_CHANGE_REASON_GM, true);
|
if (!energyUsage) { // Refill team energy if usage is disabled
|
||||||
}
|
for (EntityAvatar entityAvatar : this.player.getTeamManager().getActiveTeam()) {
|
||||||
}
|
entityAvatar.addEnergy(1000, PropChangeReason.PROP_CHANGE_REASON_GM, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,280 +1,276 @@
|
|||||||
package emu.grasscutter.game.player;
|
package emu.grasscutter.game.player;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.binout.ScenePointEntry;
|
import emu.grasscutter.data.binout.ScenePointEntry;
|
||||||
import emu.grasscutter.data.excels.OpenStateData;
|
import emu.grasscutter.data.excels.OpenStateData;
|
||||||
import emu.grasscutter.data.excels.OpenStateData.OpenStateCondType;
|
import emu.grasscutter.data.excels.OpenStateData.OpenStateCondType;
|
||||||
import emu.grasscutter.game.props.ActionReason;
|
import emu.grasscutter.game.props.ActionReason;
|
||||||
import emu.grasscutter.game.quest.enums.QuestCond;
|
import emu.grasscutter.game.quest.enums.QuestCond;
|
||||||
import emu.grasscutter.game.quest.enums.QuestContent;
|
import emu.grasscutter.game.quest.enums.QuestContent;
|
||||||
import emu.grasscutter.game.quest.enums.QuestState;
|
import emu.grasscutter.game.quest.enums.QuestState;
|
||||||
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
||||||
import emu.grasscutter.server.packet.send.*;
|
import emu.grasscutter.server.packet.send.*;
|
||||||
import lombok.val;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
// @Entity
|
||||||
|
public final class PlayerProgressManager extends BasePlayerDataManager {
|
||||||
// @Entity
|
/******************************************************************************************************************
|
||||||
public final class PlayerProgressManager extends BasePlayerDataManager {
|
******************************************************************************************************************
|
||||||
/******************************************************************************************************************
|
* OPEN STATES
|
||||||
******************************************************************************************************************
|
******************************************************************************************************************
|
||||||
* OPEN STATES
|
*****************************************************************************************************************/
|
||||||
******************************************************************************************************************
|
|
||||||
*****************************************************************************************************************/
|
// Set of open states that are never unlocked, whether they fulfill the conditions or not.
|
||||||
|
public static final Set<Integer> BLACKLIST_OPEN_STATES =
|
||||||
// Set of open states that are never unlocked, whether they fulfill the conditions or not.
|
Set.of(
|
||||||
public static final Set<Integer> BLACKLIST_OPEN_STATES =
|
48 // blacklist OPEN_STATE_LIMIT_REGION_GLOBAL to make Meledy happy. =D Remove this as
|
||||||
Set.of(
|
// soon as quest unlocks are fully implemented.
|
||||||
48 // blacklist OPEN_STATE_LIMIT_REGION_GLOBAL to make Meledy happy. =D Remove this as
|
);
|
||||||
// soon as quest unlocks are fully implemented.
|
// Set of open states that are set per default for all accounts. Can be overwritten by an entry in
|
||||||
);
|
// `map`.
|
||||||
// Set of open states that are set per default for all accounts. Can be overwritten by an entry in
|
public static final Set<Integer> DEFAULT_OPEN_STATES =
|
||||||
// `map`.
|
GameData.getOpenStateList().stream()
|
||||||
public static final Set<Integer> DEFAULT_OPEN_STATES =
|
.filter(
|
||||||
GameData.getOpenStateList().stream()
|
s ->
|
||||||
.filter(
|
s.isDefaultState() // Actual default-opened states.
|
||||||
s ->
|
// All states whose unlock we don't handle correctly yet.
|
||||||
s.isDefaultState() // Actual default-opened states.
|
|| (s.getCond().stream()
|
||||||
// All states whose unlock we don't handle correctly yet.
|
.filter(
|
||||||
|| (s.getCond().stream()
|
c ->
|
||||||
.filter(
|
c.getCondType()
|
||||||
c ->
|
== OpenStateCondType.OPEN_STATE_COND_PLAYER_LEVEL)
|
||||||
c.getCondType()
|
.count()
|
||||||
== OpenStateCondType.OPEN_STATE_COND_PLAYER_LEVEL)
|
== 0)
|
||||||
.count()
|
// Always unlock OPEN_STATE_PAIMON, otherwise the player will not have a
|
||||||
== 0)
|
// working chat.
|
||||||
// Always unlock OPEN_STATE_PAIMON, otherwise the player will not have a
|
|| s.getId() == 1)
|
||||||
// working chat.
|
.filter(
|
||||||
|| s.getId() == 1)
|
s ->
|
||||||
.filter(
|
!BLACKLIST_OPEN_STATES.contains(s.getId())) // Filter out states in the blacklist.
|
||||||
s ->
|
.map(s -> s.getId())
|
||||||
!BLACKLIST_OPEN_STATES.contains(s.getId())) // Filter out states in the blacklist.
|
.collect(Collectors.toSet());
|
||||||
.map(s -> s.getId())
|
|
||||||
.collect(Collectors.toSet());
|
public PlayerProgressManager(Player player) {
|
||||||
|
super(player);
|
||||||
public PlayerProgressManager(Player player) {
|
}
|
||||||
super(player);
|
|
||||||
}
|
/**********
|
||||||
|
* Handler for player login.
|
||||||
/**********
|
**********/
|
||||||
* Handler for player login.
|
public void onPlayerLogin() {
|
||||||
**********/
|
// Try unlocking open states on player login. This handles accounts where unlock conditions were
|
||||||
public void onPlayerLogin() {
|
// already met before certain open state unlocks were implemented.
|
||||||
// Try unlocking open states on player login. This handles accounts where unlock conditions were
|
this.tryUnlockOpenStates(false);
|
||||||
// already met before certain open state unlocks were implemented.
|
|
||||||
this.tryUnlockOpenStates(false);
|
// Send notify to the client.
|
||||||
|
player.getSession().send(new PacketOpenStateUpdateNotify(this.player));
|
||||||
// Send notify to the client.
|
|
||||||
player.getSession().send(new PacketOpenStateUpdateNotify(this.player));
|
// Add statue quests if necessary.
|
||||||
|
this.addStatueQuestsOnLogin();
|
||||||
// Add statue quests if necessary.
|
|
||||||
this.addStatueQuestsOnLogin();
|
// Auto-unlock the first statue and map area, until we figure out how to make
|
||||||
|
// that particular statue interactable.
|
||||||
// Auto-unlock the first statue and map area, until we figure out how to make
|
this.player.getUnlockedScenePoints(3).add(7);
|
||||||
// that particular statue interactable.
|
this.player.getUnlockedSceneAreas(3).add(1);
|
||||||
this.player.getUnlockedScenePoints(3).add(7);
|
}
|
||||||
this.player.getUnlockedSceneAreas(3).add(1);
|
|
||||||
}
|
/**********
|
||||||
|
* Direct getters and setters for open states.
|
||||||
/**********
|
**********/
|
||||||
* Direct getters and setters for open states.
|
public int getOpenState(int openState) {
|
||||||
**********/
|
return this.player.getOpenStates().getOrDefault(openState, 0);
|
||||||
public int getOpenState(int openState) {
|
}
|
||||||
return this.player.getOpenStates().getOrDefault(openState, 0);
|
|
||||||
}
|
private void setOpenState(int openState, int value, boolean sendNotify) {
|
||||||
|
int previousValue = this.player.getOpenStates().getOrDefault(openState, 0);
|
||||||
private void setOpenState(int openState, int value, boolean sendNotify) {
|
|
||||||
int previousValue = this.player.getOpenStates().getOrDefault(openState, 0);
|
if (value != previousValue) {
|
||||||
|
this.player.getOpenStates().put(openState, value);
|
||||||
if (value != previousValue) {
|
|
||||||
this.player.getOpenStates().put(openState, value);
|
if (sendNotify) {
|
||||||
|
player.getSession().send(new PacketOpenStateChangeNotify(openState, value));
|
||||||
if (sendNotify) {
|
}
|
||||||
player.getSession().send(new PacketOpenStateChangeNotify(openState, value));
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
private void setOpenState(int openState, int value) {
|
||||||
|
this.setOpenState(openState, value, true);
|
||||||
private void setOpenState(int openState, int value) {
|
}
|
||||||
this.setOpenState(openState, value, true);
|
|
||||||
}
|
/**********
|
||||||
|
* Condition checking for setting open states.
|
||||||
/**********
|
**********/
|
||||||
* Condition checking for setting open states.
|
private boolean areConditionsMet(OpenStateData openState) {
|
||||||
**********/
|
// Check all conditions and test if at least one of them is violated.
|
||||||
private boolean areConditionsMet(OpenStateData openState) {
|
for (var condition : openState.getCond()) {
|
||||||
// Check all conditions and test if at least one of them is violated.
|
// For level conditions, check if the player has reached the necessary level.
|
||||||
for (var condition : openState.getCond()) {
|
if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_PLAYER_LEVEL) {
|
||||||
// For level conditions, check if the player has reached the necessary level.
|
if (this.player.getLevel() < condition.getParam()) {
|
||||||
if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_PLAYER_LEVEL) {
|
return false;
|
||||||
if (this.player.getLevel() < condition.getParam()) {
|
}
|
||||||
return false;
|
} else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_QUEST) {
|
||||||
}
|
// ToDo: Implement.
|
||||||
} else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_QUEST) {
|
} else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_PARENT_QUEST) {
|
||||||
// ToDo: Implement.
|
// ToDo: Implement.
|
||||||
} else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_COND_PARENT_QUEST) {
|
} else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_OFFERING_LEVEL) {
|
||||||
// ToDo: Implement.
|
// ToDo: Implement.
|
||||||
} else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_OFFERING_LEVEL) {
|
} else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_CITY_REPUTATION_LEVEL) {
|
||||||
// ToDo: Implement.
|
// ToDo: Implement.
|
||||||
} else if (condition.getCondType() == OpenStateCondType.OPEN_STATE_CITY_REPUTATION_LEVEL) {
|
}
|
||||||
// ToDo: Implement.
|
}
|
||||||
}
|
|
||||||
}
|
// Done. If we didn't find any violations, all conditions are met.
|
||||||
|
return true;
|
||||||
// Done. If we didn't find any violations, all conditions are met.
|
}
|
||||||
return true;
|
|
||||||
}
|
/**********
|
||||||
|
* Setting open states from the client (via `SetOpenStateReq`).
|
||||||
/**********
|
**********/
|
||||||
* Setting open states from the client (via `SetOpenStateReq`).
|
public void setOpenStateFromClient(int openState, int value) {
|
||||||
**********/
|
// Get the data for this open state.
|
||||||
public void setOpenStateFromClient(int openState, int value) {
|
OpenStateData data = GameData.getOpenStateDataMap().get(openState);
|
||||||
// Get the data for this open state.
|
if (data == null) {
|
||||||
OpenStateData data = GameData.getOpenStateDataMap().get(openState);
|
this.player.sendPacket(new PacketSetOpenStateRsp(Retcode.RET_FAIL));
|
||||||
if (data == null) {
|
return;
|
||||||
this.player.sendPacket(new PacketSetOpenStateRsp(Retcode.RET_FAIL));
|
}
|
||||||
return;
|
|
||||||
}
|
// Make sure that this is an open state that the client is allowed to set,
|
||||||
|
// and that it doesn't have any further conditions attached.
|
||||||
// Make sure that this is an open state that the client is allowed to set,
|
if (!data.isAllowClientOpen() || !this.areConditionsMet(data)) {
|
||||||
// and that it doesn't have any further conditions attached.
|
this.player.sendPacket(new PacketSetOpenStateRsp(Retcode.RET_FAIL));
|
||||||
if (!data.isAllowClientOpen() || !this.areConditionsMet(data)) {
|
return;
|
||||||
this.player.sendPacket(new PacketSetOpenStateRsp(Retcode.RET_FAIL));
|
}
|
||||||
return;
|
|
||||||
}
|
// Set.
|
||||||
|
this.setOpenState(openState, value);
|
||||||
// Set.
|
this.player.sendPacket(new PacketSetOpenStateRsp(openState, value));
|
||||||
this.setOpenState(openState, value);
|
}
|
||||||
this.player.sendPacket(new PacketSetOpenStateRsp(openState, value));
|
|
||||||
}
|
/** This force sets an open state, ignoring all conditions and permissions */
|
||||||
|
public void forceSetOpenState(int openState, int value) {
|
||||||
/**
|
this.setOpenState(openState, value);
|
||||||
* This force sets an open state, ignoring all conditions and permissions
|
}
|
||||||
*/
|
|
||||||
public void forceSetOpenState(int openState, int value) {
|
/**********
|
||||||
this.setOpenState(openState, value);
|
* Triggered unlocking of open states (unlock states whose conditions have been met.)
|
||||||
}
|
**********/
|
||||||
|
public void tryUnlockOpenStates(boolean sendNotify) {
|
||||||
/**********
|
// Get list of open states that are not yet unlocked.
|
||||||
* Triggered unlocking of open states (unlock states whose conditions have been met.)
|
var lockedStates =
|
||||||
**********/
|
GameData.getOpenStateList().stream()
|
||||||
public void tryUnlockOpenStates(boolean sendNotify) {
|
.filter(s -> this.player.getOpenStates().getOrDefault(s, 0) == 0)
|
||||||
// Get list of open states that are not yet unlocked.
|
.toList();
|
||||||
var lockedStates =
|
|
||||||
GameData.getOpenStateList().stream()
|
// Try unlocking all of them.
|
||||||
.filter(s -> this.player.getOpenStates().getOrDefault(s, 0) == 0)
|
for (var state : lockedStates) {
|
||||||
.toList();
|
// To auto-unlock a state, it has to meet three conditions:
|
||||||
|
// * it can not be a state that is unlocked by the client,
|
||||||
// Try unlocking all of them.
|
// * it has to meet all its unlock conditions, and
|
||||||
for (var state : lockedStates) {
|
// * it can not be in the blacklist.
|
||||||
// To auto-unlock a state, it has to meet three conditions:
|
if (!state.isAllowClientOpen()
|
||||||
// * it can not be a state that is unlocked by the client,
|
&& this.areConditionsMet(state)
|
||||||
// * it has to meet all its unlock conditions, and
|
&& !BLACKLIST_OPEN_STATES.contains(state.getId())) {
|
||||||
// * it can not be in the blacklist.
|
this.setOpenState(state.getId(), 1, sendNotify);
|
||||||
if (!state.isAllowClientOpen()
|
}
|
||||||
&& this.areConditionsMet(state)
|
}
|
||||||
&& !BLACKLIST_OPEN_STATES.contains(state.getId())) {
|
}
|
||||||
this.setOpenState(state.getId(), 1, sendNotify);
|
|
||||||
}
|
public void tryUnlockOpenStates() {
|
||||||
}
|
this.tryUnlockOpenStates(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tryUnlockOpenStates() {
|
/******************************************************************************************************************
|
||||||
this.tryUnlockOpenStates(true);
|
******************************************************************************************************************
|
||||||
}
|
* MAP AREAS AND POINTS
|
||||||
|
******************************************************************************************************************
|
||||||
/******************************************************************************************************************
|
*****************************************************************************************************************/
|
||||||
******************************************************************************************************************
|
private void addStatueQuestsOnLogin() {
|
||||||
* MAP AREAS AND POINTS
|
// Get all currently existing subquests for the "unlock all statues" main quest.
|
||||||
******************************************************************************************************************
|
var statueMainQuest = GameData.getMainQuestDataMap().get(303);
|
||||||
*****************************************************************************************************************/
|
var statueSubQuests = statueMainQuest.getSubQuests();
|
||||||
private void addStatueQuestsOnLogin() {
|
|
||||||
// Get all currently existing subquests for the "unlock all statues" main quest.
|
// Add the main statue quest if it isn't active yet.
|
||||||
var statueMainQuest = GameData.getMainQuestDataMap().get(303);
|
var statueGameMainQuest = this.player.getQuestManager().getMainQuestById(303);
|
||||||
var statueSubQuests = statueMainQuest.getSubQuests();
|
if (statueGameMainQuest == null) {
|
||||||
|
this.player.getQuestManager().addQuest(30302);
|
||||||
// Add the main statue quest if it isn't active yet.
|
statueGameMainQuest = this.player.getQuestManager().getMainQuestById(303);
|
||||||
var statueGameMainQuest = this.player.getQuestManager().getMainQuestById(303);
|
}
|
||||||
if (statueGameMainQuest == null) {
|
|
||||||
this.player.getQuestManager().addQuest(30302);
|
// Set all subquests to active if they aren't already finished.
|
||||||
statueGameMainQuest = this.player.getQuestManager().getMainQuestById(303);
|
for (var subData : statueSubQuests) {
|
||||||
}
|
var subGameQuest = statueGameMainQuest.getChildQuestById(subData.getSubId());
|
||||||
|
if (subGameQuest != null && subGameQuest.getState() == QuestState.QUEST_STATE_UNSTARTED) {
|
||||||
// Set all subquests to active if they aren't already finished.
|
this.player.getQuestManager().addQuest(subData.getSubId());
|
||||||
for (var subData : statueSubQuests) {
|
}
|
||||||
var subGameQuest = statueGameMainQuest.getChildQuestById(subData.getSubId());
|
}
|
||||||
if (subGameQuest != null && subGameQuest.getState() == QuestState.QUEST_STATE_UNSTARTED) {
|
}
|
||||||
this.player.getQuestManager().addQuest(subData.getSubId());
|
|
||||||
}
|
public boolean unlockTransPoint(int sceneId, int pointId, boolean isStatue) {
|
||||||
}
|
// Check whether the unlocked point exists and whether it is still locked.
|
||||||
}
|
ScenePointEntry scenePointEntry = GameData.getScenePointEntryById(sceneId, pointId);
|
||||||
|
|
||||||
public boolean unlockTransPoint(int sceneId, int pointId, boolean isStatue) {
|
if (scenePointEntry == null || this.player.getUnlockedScenePoints(sceneId).contains(pointId)) {
|
||||||
// Check whether the unlocked point exists and whether it is still locked.
|
return false;
|
||||||
ScenePointEntry scenePointEntry = GameData.getScenePointEntryById(sceneId, pointId);
|
}
|
||||||
|
|
||||||
if (scenePointEntry == null || this.player.getUnlockedScenePoints(sceneId).contains(pointId)) {
|
// Add the point to the list of unlocked points for its scene.
|
||||||
return false;
|
this.player.getUnlockedScenePoints(sceneId).add(pointId);
|
||||||
}
|
|
||||||
|
// Give primogems and Adventure EXP for unlocking.
|
||||||
// Add the point to the list of unlocked points for its scene.
|
this.player.getInventory().addItem(201, 5, ActionReason.UnlockPointReward);
|
||||||
this.player.getUnlockedScenePoints(sceneId).add(pointId);
|
this.player.getInventory().addItem(102, isStatue ? 50 : 10, ActionReason.UnlockPointReward);
|
||||||
|
|
||||||
// Give primogems and Adventure EXP for unlocking.
|
// this.player.sendPacket(new
|
||||||
this.player.getInventory().addItem(201, 5, ActionReason.UnlockPointReward);
|
// PacketPlayerPropChangeReasonNotify(this.player.getProperty(PlayerProperty.PROP_PLAYER_EXP),
|
||||||
this.player.getInventory().addItem(102, isStatue ? 50 : 10, ActionReason.UnlockPointReward);
|
// PlayerProperty.PROP_PLAYER_EXP, PropChangeReason.PROP_CHANGE_REASON_PLAYER_ADD_EXP));
|
||||||
|
|
||||||
// this.player.sendPacket(new
|
// Fire quest trigger for trans point unlock.
|
||||||
// PacketPlayerPropChangeReasonNotify(this.player.getProperty(PlayerProperty.PROP_PLAYER_EXP),
|
this.player
|
||||||
// PlayerProperty.PROP_PLAYER_EXP, PropChangeReason.PROP_CHANGE_REASON_PLAYER_ADD_EXP));
|
.getQuestManager()
|
||||||
|
.queueEvent(QuestContent.QUEST_CONTENT_UNLOCK_TRANS_POINT, sceneId, pointId);
|
||||||
// Fire quest trigger for trans point unlock.
|
|
||||||
this.player
|
// Send packet.
|
||||||
.getQuestManager()
|
this.player.sendPacket(new PacketScenePointUnlockNotify(sceneId, pointId));
|
||||||
.queueEvent(QuestContent.QUEST_CONTENT_UNLOCK_TRANS_POINT, sceneId, pointId);
|
return true;
|
||||||
|
}
|
||||||
// Send packet.
|
|
||||||
this.player.sendPacket(new PacketScenePointUnlockNotify(sceneId, pointId));
|
public void unlockSceneArea(int sceneId, int areaId) {
|
||||||
return true;
|
// Add the area to the list of unlocked areas in its scene.
|
||||||
}
|
this.player.getUnlockedSceneAreas(sceneId).add(areaId);
|
||||||
|
|
||||||
public void unlockSceneArea(int sceneId, int areaId) {
|
// Send packet.
|
||||||
// Add the area to the list of unlocked areas in its scene.
|
this.player.sendPacket(new PacketSceneAreaUnlockNotify(sceneId, areaId));
|
||||||
this.player.getUnlockedSceneAreas(sceneId).add(areaId);
|
}
|
||||||
|
|
||||||
// Send packet.
|
/** Give replace costume to player (Amber, Jean, Mona, Rosaria) */
|
||||||
this.player.sendPacket(new PacketSceneAreaUnlockNotify(sceneId, areaId));
|
public void addReplaceCostumes() {
|
||||||
}
|
var currentPlayerCostumes = player.getCostumeList();
|
||||||
|
GameData.getAvatarReplaceCostumeDataMap()
|
||||||
/**
|
.keySet()
|
||||||
* Give replace costume to player (Amber, Jean, Mona, Rosaria)
|
.forEach(
|
||||||
*/
|
costumeId -> {
|
||||||
public void addReplaceCostumes(){
|
if (GameData.getAvatarCostumeDataMap().get(costumeId) == null
|
||||||
var currentPlayerCostumes = player.getCostumeList();
|
|| currentPlayerCostumes.contains(costumeId)) {
|
||||||
GameData.getAvatarReplaceCostumeDataMap().keySet().forEach(costumeId -> {
|
return;
|
||||||
if (GameData.getAvatarCostumeDataMap().get(costumeId) == null || currentPlayerCostumes.contains(costumeId)){
|
}
|
||||||
return;
|
this.player.addCostume(costumeId);
|
||||||
}
|
});
|
||||||
this.player.addCostume(costumeId);
|
}
|
||||||
});
|
|
||||||
}
|
/** Quest progress */
|
||||||
|
public void addQuestProgress(int id, int count) {
|
||||||
/**
|
var newCount = player.getPlayerProgress().addToCurrentProgress(id, count);
|
||||||
* Quest progress
|
player.save();
|
||||||
*/
|
player
|
||||||
public void addQuestProgress(int id, int count){
|
.getQuestManager()
|
||||||
var newCount = player.getPlayerProgress().addToCurrentProgress(id, count);
|
.queueEvent(QuestContent.QUEST_CONTENT_ADD_QUEST_PROGRESS, id, newCount);
|
||||||
player.save();
|
}
|
||||||
player.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_ADD_QUEST_PROGRESS, id, newCount);
|
|
||||||
}
|
/** Item history */
|
||||||
|
public void addItemObtainedHistory(int id, int count) {
|
||||||
/**
|
var newCount = player.getPlayerProgress().addToItemHistory(id, count);
|
||||||
* Item history
|
player.save();
|
||||||
*/
|
player.getQuestManager().queueEvent(QuestCond.QUEST_COND_HISTORY_GOT_ANY_ITEM, id, newCount);
|
||||||
public void addItemObtainedHistory(int id, int count){
|
}
|
||||||
var newCount = player.getPlayerProgress().addToItemHistory(id, count);
|
}
|
||||||
player.save();
|
|
||||||
player.getQuestManager().queueEvent(QuestCond.QUEST_COND_HISTORY_GOT_ANY_ITEM, id, newCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,72 +1,131 @@
|
|||||||
package emu.grasscutter.game.props;
|
package emu.grasscutter.game.props;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import emu.grasscutter.scripts.constants.IntValueEnum;
|
||||||
import java.util.Map;
|
import emu.grasscutter.utils.Utils;
|
||||||
import java.util.stream.Stream;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import emu.grasscutter.scripts.constants.IntValueEnum;
|
import java.util.HashMap;
|
||||||
import emu.grasscutter.utils.Utils;
|
import java.util.Map;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import java.util.stream.Stream;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import lombok.Getter;
|
||||||
import lombok.Getter;
|
|
||||||
|
public enum ElementType implements IntValueEnum {
|
||||||
public enum ElementType implements IntValueEnum {
|
None(0, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
||||||
None (0, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
Fire(
|
||||||
Fire (1, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, 10101, "TeamResonance_Fire_Lv2", 1),
|
1,
|
||||||
Water (2, FightProperty.FIGHT_PROP_CUR_WATER_ENERGY, FightProperty.FIGHT_PROP_MAX_WATER_ENERGY, 10201, "TeamResonance_Water_Lv2", 2),
|
FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY,
|
||||||
Grass (3, FightProperty.FIGHT_PROP_CUR_GRASS_ENERGY, FightProperty.FIGHT_PROP_MAX_GRASS_ENERGY, 10501, "TeamResonance_Grass_Lv2", 7),
|
FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY,
|
||||||
Electric (4, FightProperty.FIGHT_PROP_CUR_ELEC_ENERGY, FightProperty.FIGHT_PROP_MAX_ELEC_ENERGY, 10401, "TeamResonance_Electric_Lv2", 6),
|
10101,
|
||||||
Ice (5, FightProperty.FIGHT_PROP_CUR_ICE_ENERGY, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY, 10601, "TeamResonance_Ice_Lv2", 4),
|
"TeamResonance_Fire_Lv2",
|
||||||
Frozen (6, FightProperty.FIGHT_PROP_CUR_ICE_ENERGY, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY),
|
1),
|
||||||
Wind (7, FightProperty.FIGHT_PROP_CUR_WIND_ENERGY, FightProperty.FIGHT_PROP_MAX_WIND_ENERGY, 10301, "TeamResonance_Wind_Lv2", 3),
|
Water(
|
||||||
Rock (8, FightProperty.FIGHT_PROP_CUR_ROCK_ENERGY, FightProperty.FIGHT_PROP_MAX_ROCK_ENERGY, 10701, "TeamResonance_Rock_Lv2", 5),
|
2,
|
||||||
AntiFire (9, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
FightProperty.FIGHT_PROP_CUR_WATER_ENERGY,
|
||||||
Default (255, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, 10801, "TeamResonance_AllDifferent");
|
FightProperty.FIGHT_PROP_MAX_WATER_ENERGY,
|
||||||
|
10201,
|
||||||
private static final Int2ObjectMap<ElementType> map = new Int2ObjectOpenHashMap<>();
|
"TeamResonance_Water_Lv2",
|
||||||
private static final Map<String, ElementType> stringMap = new HashMap<>();
|
2),
|
||||||
|
Grass(
|
||||||
static {
|
3,
|
||||||
// Create bindings for each value.
|
FightProperty.FIGHT_PROP_CUR_GRASS_ENERGY,
|
||||||
Stream.of(ElementType.values()).forEach(entry -> {
|
FightProperty.FIGHT_PROP_MAX_GRASS_ENERGY,
|
||||||
map.put(entry.getValue(), entry);
|
10501,
|
||||||
stringMap.put(entry.name(), entry);
|
"TeamResonance_Grass_Lv2",
|
||||||
});
|
7),
|
||||||
}
|
Electric(
|
||||||
|
4,
|
||||||
@Getter private final int value;
|
FightProperty.FIGHT_PROP_CUR_ELEC_ENERGY,
|
||||||
@Getter private final int teamResonanceId;
|
FightProperty.FIGHT_PROP_MAX_ELEC_ENERGY,
|
||||||
@Getter private final FightProperty curEnergyProp;
|
10401,
|
||||||
@Getter private final FightProperty maxEnergyProp;
|
"TeamResonance_Electric_Lv2",
|
||||||
@Getter private final int depotIndex;
|
6),
|
||||||
@Getter private final int configHash;
|
Ice(
|
||||||
|
5,
|
||||||
ElementType(int value, FightProperty curEnergyProp, FightProperty maxEnergyProp) {
|
FightProperty.FIGHT_PROP_CUR_ICE_ENERGY,
|
||||||
this(value, curEnergyProp, maxEnergyProp, 0, null, 1);
|
FightProperty.FIGHT_PROP_MAX_ICE_ENERGY,
|
||||||
}
|
10601,
|
||||||
|
"TeamResonance_Ice_Lv2",
|
||||||
ElementType(int value, FightProperty curEnergyProp, FightProperty maxEnergyProp, int teamResonanceId, String configName) {
|
4),
|
||||||
this(value, curEnergyProp, maxEnergyProp, teamResonanceId, configName, 1);
|
Frozen(6, FightProperty.FIGHT_PROP_CUR_ICE_ENERGY, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY),
|
||||||
}
|
Wind(
|
||||||
|
7,
|
||||||
ElementType(int value, FightProperty curEnergyProp, FightProperty maxEnergyProp, int teamResonanceId, String configName, int depotIndex) {
|
FightProperty.FIGHT_PROP_CUR_WIND_ENERGY,
|
||||||
this.value = value;
|
FightProperty.FIGHT_PROP_MAX_WIND_ENERGY,
|
||||||
this.curEnergyProp = curEnergyProp;
|
10301,
|
||||||
this.maxEnergyProp = maxEnergyProp;
|
"TeamResonance_Wind_Lv2",
|
||||||
this.teamResonanceId = teamResonanceId;
|
3),
|
||||||
this.depotIndex = depotIndex;
|
Rock(
|
||||||
if (configName != null) {
|
8,
|
||||||
this.configHash = Utils.abilityHash(configName);
|
FightProperty.FIGHT_PROP_CUR_ROCK_ENERGY,
|
||||||
} else {
|
FightProperty.FIGHT_PROP_MAX_ROCK_ENERGY,
|
||||||
this.configHash = 0;
|
10701,
|
||||||
}
|
"TeamResonance_Rock_Lv2",
|
||||||
}
|
5),
|
||||||
|
AntiFire(9, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
||||||
public static ElementType getTypeByValue(int value) {
|
Default(
|
||||||
return map.getOrDefault(value, None);
|
255,
|
||||||
}
|
FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY,
|
||||||
|
FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY,
|
||||||
public static ElementType getTypeByName(String name) {
|
10801,
|
||||||
return stringMap.getOrDefault(name, None);
|
"TeamResonance_AllDifferent");
|
||||||
}
|
|
||||||
}
|
private static final Int2ObjectMap<ElementType> map = new Int2ObjectOpenHashMap<>();
|
||||||
|
private static final Map<String, ElementType> stringMap = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
// Create bindings for each value.
|
||||||
|
Stream.of(ElementType.values())
|
||||||
|
.forEach(
|
||||||
|
entry -> {
|
||||||
|
map.put(entry.getValue(), entry);
|
||||||
|
stringMap.put(entry.name(), entry);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter private final int value;
|
||||||
|
@Getter private final int teamResonanceId;
|
||||||
|
@Getter private final FightProperty curEnergyProp;
|
||||||
|
@Getter private final FightProperty maxEnergyProp;
|
||||||
|
@Getter private final int depotIndex;
|
||||||
|
@Getter private final int configHash;
|
||||||
|
|
||||||
|
ElementType(int value, FightProperty curEnergyProp, FightProperty maxEnergyProp) {
|
||||||
|
this(value, curEnergyProp, maxEnergyProp, 0, null, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementType(
|
||||||
|
int value,
|
||||||
|
FightProperty curEnergyProp,
|
||||||
|
FightProperty maxEnergyProp,
|
||||||
|
int teamResonanceId,
|
||||||
|
String configName) {
|
||||||
|
this(value, curEnergyProp, maxEnergyProp, teamResonanceId, configName, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementType(
|
||||||
|
int value,
|
||||||
|
FightProperty curEnergyProp,
|
||||||
|
FightProperty maxEnergyProp,
|
||||||
|
int teamResonanceId,
|
||||||
|
String configName,
|
||||||
|
int depotIndex) {
|
||||||
|
this.value = value;
|
||||||
|
this.curEnergyProp = curEnergyProp;
|
||||||
|
this.maxEnergyProp = maxEnergyProp;
|
||||||
|
this.teamResonanceId = teamResonanceId;
|
||||||
|
this.depotIndex = depotIndex;
|
||||||
|
if (configName != null) {
|
||||||
|
this.configHash = Utils.abilityHash(configName);
|
||||||
|
} else {
|
||||||
|
this.configHash = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ElementType getTypeByValue(int value) {
|
||||||
|
return map.getOrDefault(value, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ElementType getTypeByName(String name) {
|
||||||
|
return stringMap.getOrDefault(name, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,23 +1,21 @@
|
|||||||
package emu.grasscutter.game.quest.conditions;
|
package emu.grasscutter.game.quest.conditions;
|
||||||
|
|
||||||
import emu.grasscutter.data.excels.QuestData;
|
import emu.grasscutter.data.excels.QuestData;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.quest.QuestValueCond;
|
import emu.grasscutter.game.quest.QuestValueCond;
|
||||||
import emu.grasscutter.game.quest.enums.QuestCond;
|
import emu.grasscutter.game.quest.enums.QuestCond;
|
||||||
import lombok.val;
|
|
||||||
|
@QuestValueCond(QuestCond.QUEST_COND_PERSONAL_LINE_UNLOCK)
|
||||||
@QuestValueCond(QuestCond.QUEST_COND_PERSONAL_LINE_UNLOCK)
|
public class ConditionPersonalLineUnlock extends BaseCondition {
|
||||||
public class ConditionPersonalLineUnlock extends BaseCondition {
|
|
||||||
|
@Override
|
||||||
@Override
|
public boolean execute(
|
||||||
public boolean execute(
|
Player owner,
|
||||||
Player owner,
|
QuestData questData,
|
||||||
QuestData questData,
|
QuestData.QuestAcceptCondition condition,
|
||||||
QuestData.QuestAcceptCondition condition,
|
String paramStr,
|
||||||
String paramStr,
|
int... params) {
|
||||||
int... params
|
var personalLineId = condition.getParam()[0];
|
||||||
) {
|
return owner.getPersonalLineList().contains(personalLineId);
|
||||||
var personalLineId = condition.getParam()[0];
|
}
|
||||||
return owner.getPersonalLineList().contains(personalLineId);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
package emu.grasscutter.game.quest.exec;
|
package emu.grasscutter.game.quest.exec;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.data.excels.QuestData;
|
import emu.grasscutter.data.excels.QuestData;
|
||||||
import emu.grasscutter.game.quest.GameQuest;
|
import emu.grasscutter.game.quest.GameQuest;
|
||||||
import emu.grasscutter.game.quest.QuestValueExec;
|
import emu.grasscutter.game.quest.QuestValueExec;
|
||||||
import emu.grasscutter.game.quest.enums.QuestExec;
|
import emu.grasscutter.game.quest.enums.QuestExec;
|
||||||
import emu.grasscutter.game.quest.handlers.QuestExecHandler;
|
import emu.grasscutter.game.quest.handlers.QuestExecHandler;
|
||||||
|
|
||||||
@QuestValueExec(QuestExec.QUEST_EXEC_ADD_CUR_AVATAR_ENERGY)
|
@QuestValueExec(QuestExec.QUEST_EXEC_ADD_CUR_AVATAR_ENERGY)
|
||||||
public class ExecAddCurAvatarEnergy extends QuestExecHandler {
|
public class ExecAddCurAvatarEnergy extends QuestExecHandler {
|
||||||
@Override
|
@Override
|
||||||
public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) {
|
public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) {
|
||||||
Grasscutter.getLogger().info("Energy refilled");
|
Grasscutter.getLogger().info("Energy refilled");
|
||||||
return quest.getOwner().getEnergyManager().refillActiveEnergy();
|
return quest.getOwner().getEnergyManager().refillActiveEnergy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
package emu.grasscutter.game.quest.exec;
|
package emu.grasscutter.game.quest.exec;
|
||||||
|
|
||||||
import emu.grasscutter.data.excels.QuestData;
|
import emu.grasscutter.data.excels.QuestData;
|
||||||
import emu.grasscutter.game.quest.GameQuest;
|
import emu.grasscutter.game.quest.GameQuest;
|
||||||
import emu.grasscutter.game.quest.QuestValueExec;
|
import emu.grasscutter.game.quest.QuestValueExec;
|
||||||
import emu.grasscutter.game.quest.enums.QuestExec;
|
import emu.grasscutter.game.quest.enums.QuestExec;
|
||||||
import emu.grasscutter.game.quest.handlers.QuestExecHandler;
|
import emu.grasscutter.game.quest.handlers.QuestExecHandler;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@QuestValueExec(QuestExec.QUEST_EXEC_ADD_QUEST_PROGRESS)
|
@QuestValueExec(QuestExec.QUEST_EXEC_ADD_QUEST_PROGRESS)
|
||||||
public final class ExecAddQuestProgress extends QuestExecHandler {
|
public final class ExecAddQuestProgress extends QuestExecHandler {
|
||||||
@Override
|
@Override
|
||||||
public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) {
|
public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) {
|
||||||
var param =
|
var param =
|
||||||
Arrays.stream(paramStr).filter(i -> !i.isBlank()).mapToInt(Integer::parseInt).toArray();
|
Arrays.stream(paramStr).filter(i -> !i.isBlank()).mapToInt(Integer::parseInt).toArray();
|
||||||
|
|
||||||
quest.getOwner().getProgressManager().addQuestProgress(param[0], param[1]);
|
quest.getOwner().getProgressManager().addQuestProgress(param[0], param[1]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
package emu.grasscutter.game.quest.exec;
|
package emu.grasscutter.game.quest.exec;
|
||||||
|
|
||||||
import emu.grasscutter.data.excels.QuestData;
|
import emu.grasscutter.data.excels.QuestData;
|
||||||
import emu.grasscutter.game.quest.GameQuest;
|
import emu.grasscutter.game.quest.GameQuest;
|
||||||
import emu.grasscutter.game.quest.QuestValueExec;
|
import emu.grasscutter.game.quest.QuestValueExec;
|
||||||
import emu.grasscutter.game.quest.enums.QuestExec;
|
import emu.grasscutter.game.quest.enums.QuestExec;
|
||||||
import emu.grasscutter.game.quest.handlers.QuestExecHandler;
|
import emu.grasscutter.game.quest.handlers.QuestExecHandler;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@QuestValueExec(QuestExec.QUEST_EXEC_SET_OPEN_STATE)
|
@QuestValueExec(QuestExec.QUEST_EXEC_SET_OPEN_STATE)
|
||||||
public class ExecSetOpenState extends QuestExecHandler {
|
public class ExecSetOpenState extends QuestExecHandler {
|
||||||
@Override
|
@Override
|
||||||
public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) {
|
public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) {
|
||||||
var param =
|
var param =
|
||||||
Arrays.stream(paramStr).filter(i -> !i.isBlank()).mapToInt(Integer::parseInt).toArray();
|
Arrays.stream(paramStr).filter(i -> !i.isBlank()).mapToInt(Integer::parseInt).toArray();
|
||||||
|
|
||||||
quest.getOwner().getProgressManager().forceSetOpenState(param[0], param[1]);
|
quest.getOwner().getProgressManager().forceSetOpenState(param[0], param[1]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,86 +1,85 @@
|
|||||||
package emu.grasscutter.game.world;
|
package emu.grasscutter.game.world;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import dev.morphia.annotations.Entity;
|
||||||
import java.util.Map;
|
import dev.morphia.annotations.Id;
|
||||||
import java.util.Set;
|
import dev.morphia.annotations.Indexed;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import emu.grasscutter.database.DatabaseHelper;
|
||||||
|
import emu.grasscutter.game.player.Player;
|
||||||
import org.bson.types.ObjectId;
|
import emu.grasscutter.scripts.data.SceneGadget;
|
||||||
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
import dev.morphia.annotations.Entity;
|
import java.util.HashSet;
|
||||||
import dev.morphia.annotations.Id;
|
import java.util.Map;
|
||||||
import dev.morphia.annotations.Indexed;
|
import java.util.Set;
|
||||||
import emu.grasscutter.database.DatabaseHelper;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import emu.grasscutter.game.player.Player;
|
import lombok.Getter;
|
||||||
import emu.grasscutter.scripts.data.SceneGadget;
|
import lombok.Setter;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import org.bson.types.ObjectId;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
@Entity(value = "group_instances", useDiscriminator = false)
|
||||||
|
public final class SceneGroupInstance {
|
||||||
@Entity(value = "group_instances", useDiscriminator = false)
|
@Id private ObjectId id;
|
||||||
public final class SceneGroupInstance {
|
|
||||||
@Id private ObjectId id;
|
@Indexed private int ownerUid; // This group is owned by the host player
|
||||||
|
@Getter private int groupId;
|
||||||
@Indexed private int ownerUid; //This group is owned by the host player
|
|
||||||
@Getter private int groupId;
|
@Getter private transient SceneGroup luaGroup;
|
||||||
|
@Getter @Setter private int targetSuiteId;
|
||||||
@Getter private transient SceneGroup luaGroup;
|
@Getter @Setter private int activeSuiteId;
|
||||||
@Getter @Setter private int targetSuiteId;
|
@Getter private Set<Integer> deadEntities; // Config_ids
|
||||||
@Getter @Setter private int activeSuiteId;
|
private boolean isCached;
|
||||||
@Getter private Set<Integer> deadEntities; //Config_ids
|
|
||||||
private boolean isCached;
|
@Getter private Map<Integer, Integer> cachedGadgetStates;
|
||||||
|
@Getter private Map<String, Integer> cachedVariables;
|
||||||
@Getter private Map<Integer, Integer> cachedGadgetStates;
|
|
||||||
@Getter private Map<String, Integer> cachedVariables;
|
@Getter @Setter private int lastTimeRefreshed;
|
||||||
|
|
||||||
@Getter @Setter private int lastTimeRefreshed;
|
public SceneGroupInstance(SceneGroup group, Player owner) {
|
||||||
|
this.luaGroup = group;
|
||||||
public SceneGroupInstance(SceneGroup group, Player owner) {
|
this.groupId = group.id;
|
||||||
this.luaGroup = group;
|
this.targetSuiteId = 0;
|
||||||
this.groupId = group.id;
|
this.activeSuiteId = 0;
|
||||||
this.targetSuiteId = 0;
|
this.lastTimeRefreshed = 0;
|
||||||
this.activeSuiteId = 0;
|
this.ownerUid = owner.getUid();
|
||||||
this.lastTimeRefreshed = 0;
|
this.deadEntities = new HashSet<>();
|
||||||
this.ownerUid = owner.getUid();
|
this.cachedGadgetStates = new ConcurrentHashMap<>();
|
||||||
this.deadEntities = new HashSet<>();
|
this.cachedVariables = new ConcurrentHashMap<>();
|
||||||
this.cachedGadgetStates = new ConcurrentHashMap<>();
|
|
||||||
this.cachedVariables = new ConcurrentHashMap<>();
|
this.isCached =
|
||||||
|
false; // This is true when the group is not loaded on scene but caches suite data
|
||||||
this.isCached = false; //This is true when the group is not loaded on scene but caches suite data
|
}
|
||||||
}
|
|
||||||
|
@Deprecated // Morphia only!
|
||||||
@Deprecated // Morphia only!
|
SceneGroupInstance() {
|
||||||
SceneGroupInstance(){
|
this.cachedVariables = new ConcurrentHashMap<>();
|
||||||
this.cachedVariables = new ConcurrentHashMap<>();
|
this.deadEntities = new HashSet<>();
|
||||||
this.deadEntities = new HashSet<>();
|
this.cachedGadgetStates = new ConcurrentHashMap<>();
|
||||||
this.cachedGadgetStates = new ConcurrentHashMap<>();
|
}
|
||||||
}
|
|
||||||
|
public void setLuaGroup(SceneGroup group) {
|
||||||
public void setLuaGroup(SceneGroup group) {
|
this.luaGroup = group;
|
||||||
this.luaGroup = group;
|
this.groupId = group.id;
|
||||||
this.groupId = group.id;
|
}
|
||||||
}
|
|
||||||
|
public boolean isCached() {
|
||||||
public boolean isCached() {
|
return this.isCached;
|
||||||
return this.isCached;
|
}
|
||||||
}
|
|
||||||
|
public void setCached(boolean value) {
|
||||||
public void setCached(boolean value) {
|
this.isCached = value;
|
||||||
this.isCached = value;
|
save(); // Save each time a group is registered or unregistered
|
||||||
save(); //Save each time a group is registered or unregistered
|
}
|
||||||
}
|
|
||||||
|
public void cacheGadgetState(SceneGadget g, int state) {
|
||||||
public void cacheGadgetState(SceneGadget g, int state) {
|
if (g.persistent) // Only cache when is persistent
|
||||||
if(g.persistent) //Only cache when is persistent
|
cachedGadgetStates.put(g.config_id, state);
|
||||||
cachedGadgetStates.put(g.config_id, state);
|
}
|
||||||
}
|
|
||||||
|
public int getCachedGadgetState(SceneGadget g) {
|
||||||
public int getCachedGadgetState(SceneGadget g) {
|
Integer state = cachedGadgetStates.getOrDefault(g.config_id, null);
|
||||||
Integer state = cachedGadgetStates.getOrDefault(g.config_id, null);
|
return (state == null) ? g.state : state;
|
||||||
return (state == null) ? g.state : state;
|
}
|
||||||
}
|
|
||||||
|
public void save() {
|
||||||
public void save() {
|
DatabaseHelper.saveGroupInstance(this);
|
||||||
DatabaseHelper.saveGroupInstance(this);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,66 +1,64 @@
|
|||||||
package emu.grasscutter.scripts;
|
package emu.grasscutter.scripts;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import java.util.HashMap;
|
import emu.grasscutter.utils.Position;
|
||||||
|
import java.util.HashMap;
|
||||||
import emu.grasscutter.utils.Position;
|
import org.luaj.vm2.LuaTable;
|
||||||
import lombok.val;
|
import org.luaj.vm2.LuaValue;
|
||||||
import org.luaj.vm2.LuaTable;
|
|
||||||
import org.luaj.vm2.LuaValue;
|
public interface ScriptUtils {
|
||||||
|
static HashMap<Object, Object> toMap(LuaTable table) {
|
||||||
public interface ScriptUtils {
|
HashMap<Object, Object> map = new HashMap<>();
|
||||||
static HashMap<Object, Object> toMap(LuaTable table) {
|
LuaValue[] rootKeys = table.keys();
|
||||||
HashMap<Object, Object> map = new HashMap<>();
|
for (LuaValue k : rootKeys) {
|
||||||
LuaValue[] rootKeys = table.keys();
|
if (table.get(k).istable()) {
|
||||||
for (LuaValue k : rootKeys) {
|
map.put(k, toMap(table.get(k).checktable()));
|
||||||
if (table.get(k).istable()) {
|
} else {
|
||||||
map.put(k, toMap(table.get(k).checktable()));
|
map.put(k, table.get(k));
|
||||||
} else {
|
}
|
||||||
map.put(k, table.get(k));
|
}
|
||||||
}
|
return map;
|
||||||
}
|
}
|
||||||
return map;
|
|
||||||
}
|
static void print(LuaTable table) {
|
||||||
|
Grasscutter.getLogger().info(toMap(table).toString());
|
||||||
static void print(LuaTable table) {
|
}
|
||||||
Grasscutter.getLogger().info(toMap(table).toString());
|
|
||||||
}
|
/**
|
||||||
|
* Converts a position object into a Lua table.
|
||||||
/**
|
*
|
||||||
* Converts a position object into a Lua table.
|
* @param position The position object to convert.
|
||||||
*
|
* @return The Lua table.
|
||||||
* @param position The position object to convert.
|
*/
|
||||||
* @return The Lua table.
|
static LuaTable posToLua(Position position) {
|
||||||
*/
|
var result = new LuaTable();
|
||||||
static LuaTable posToLua(Position position) {
|
if (position != null) {
|
||||||
var result = new LuaTable();
|
result.set("x", position.getX());
|
||||||
if (position != null) {
|
result.set("y", position.getY());
|
||||||
result.set("x", position.getX());
|
result.set("z", position.getZ());
|
||||||
result.set("y", position.getY());
|
} else {
|
||||||
result.set("z", position.getZ());
|
result.set("x", 0);
|
||||||
} else {
|
result.set("y", 0);
|
||||||
result.set("x", 0);
|
result.set("z", 0);
|
||||||
result.set("y", 0);
|
}
|
||||||
result.set("z", 0);
|
|
||||||
}
|
return result;
|
||||||
|
}
|
||||||
return result;
|
|
||||||
}
|
/**
|
||||||
|
* Converts a Lua table into a position object.
|
||||||
/**
|
*
|
||||||
* Converts a Lua table into a position object.
|
* @param position The Lua table to convert.
|
||||||
*
|
* @return The position object.
|
||||||
* @param position The Lua table to convert.
|
*/
|
||||||
* @return The position object.
|
static Position luaToPos(LuaValue position) {
|
||||||
*/
|
var result = new Position();
|
||||||
static Position luaToPos(LuaValue position) {
|
if (position != null && !position.isnil()) {
|
||||||
var result = new Position();
|
result.setX(position.get("x").optint(0));
|
||||||
if (position != null && !position.isnil()) {
|
result.setY(position.get("y").optint(0));
|
||||||
result.setX(position.get("x").optint(0));
|
result.setZ(position.get("z").optint(0));
|
||||||
result.setY(position.get("y").optint(0));
|
}
|
||||||
result.setZ(position.get("z").optint(0));
|
|
||||||
}
|
return result;
|
||||||
|
}
|
||||||
return result;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package emu.grasscutter.scripts.data;
|
package emu.grasscutter.scripts.data;
|
||||||
|
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@Setter
|
@Setter
|
||||||
public class SceneConfig {
|
public class SceneConfig {
|
||||||
public Position vision_anchor;
|
public Position vision_anchor;
|
||||||
public Position born_pos;
|
public Position born_pos;
|
||||||
public Position born_rot;
|
public Position born_rot;
|
||||||
public Position begin_pos;
|
public Position begin_pos;
|
||||||
public Position size;
|
public Position size;
|
||||||
public float die_y;
|
public float die_y;
|
||||||
}
|
}
|
||||||
|
@ -1,183 +1,206 @@
|
|||||||
package emu.grasscutter.scripts.data;
|
package emu.grasscutter.scripts.data;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.scripts.ScriptLoader;
|
import emu.grasscutter.scripts.ScriptLoader;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import lombok.Getter;
|
import java.util.ArrayList;
|
||||||
import lombok.Setter;
|
import java.util.List;
|
||||||
import lombok.ToString;
|
import java.util.Map;
|
||||||
import org.luaj.vm2.LuaValue;
|
import java.util.Optional;
|
||||||
|
import java.util.Random;
|
||||||
import javax.script.Bindings;
|
import java.util.stream.Collectors;
|
||||||
import javax.script.CompiledScript;
|
import javax.script.Bindings;
|
||||||
import javax.script.ScriptException;
|
import javax.script.CompiledScript;
|
||||||
|
import javax.script.ScriptException;
|
||||||
import java.util.ArrayList;
|
import lombok.Getter;
|
||||||
import java.util.List;
|
import lombok.Setter;
|
||||||
import java.util.Map;
|
import lombok.ToString;
|
||||||
import java.util.Optional;
|
import org.luaj.vm2.LuaValue;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.stream.Collectors;
|
@ToString
|
||||||
|
@Setter
|
||||||
@ToString
|
public final class SceneGroup {
|
||||||
@Setter
|
public transient int
|
||||||
public final class SceneGroup {
|
block_id; // Not an actual variable in the scripts but we will keep it here for reference
|
||||||
public transient int block_id; // Not an actual variable in the scripts but we will keep it here for reference
|
|
||||||
|
public int id;
|
||||||
public int id;
|
public int refresh_id;
|
||||||
public int refresh_id;
|
public Position pos;
|
||||||
public Position pos;
|
|
||||||
|
public Map<Integer, SceneMonster> monsters; // <ConfigId, Monster>
|
||||||
public Map<Integer, SceneMonster> monsters; // <ConfigId, Monster>
|
public Map<Integer, SceneNPC> npcs; // <ConfigId, Npc>
|
||||||
public Map<Integer, SceneNPC> npcs; // <ConfigId, Npc>
|
public Map<Integer, SceneGadget> gadgets; // <ConfigId, Gadgets>
|
||||||
public Map<Integer, SceneGadget> gadgets; // <ConfigId, Gadgets>
|
public Map<String, SceneTrigger> triggers;
|
||||||
public Map<String, SceneTrigger> triggers;
|
public Map<Integer, SceneRegion> regions;
|
||||||
public Map<Integer, SceneRegion> regions;
|
public List<SceneSuite> suites;
|
||||||
public List<SceneSuite> suites;
|
public List<SceneVar> variables;
|
||||||
public List<SceneVar> variables;
|
|
||||||
|
public SceneBusiness business;
|
||||||
public SceneBusiness business;
|
public SceneGarbage garbages;
|
||||||
public SceneGarbage garbages;
|
public SceneInitConfig init_config;
|
||||||
public SceneInitConfig init_config;
|
@Getter public boolean dynamic_load = false;
|
||||||
@Getter public boolean dynamic_load = false;
|
|
||||||
|
public SceneReplaceable is_replaceable;
|
||||||
public SceneReplaceable is_replaceable;
|
|
||||||
|
private transient boolean loaded; // Not an actual variable in the scripts either
|
||||||
private transient boolean loaded; // Not an actual variable in the scripts either
|
private transient CompiledScript script;
|
||||||
private transient CompiledScript script;
|
private transient Bindings bindings;
|
||||||
private transient Bindings bindings;
|
|
||||||
public static SceneGroup of(int groupId) {
|
public static SceneGroup of(int groupId) {
|
||||||
var group = new SceneGroup();
|
var group = new SceneGroup();
|
||||||
group.id = groupId;
|
group.id = groupId;
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLoaded() {
|
public boolean isLoaded() {
|
||||||
return this.loaded;
|
return this.loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLoaded(boolean loaded) {
|
public void setLoaded(boolean loaded) {
|
||||||
this.loaded = loaded;
|
this.loaded = loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBusinessType() {
|
public int getBusinessType() {
|
||||||
return this.business == null ? 0 : this.business.type;
|
return this.business == null ? 0 : this.business.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SceneGadget> getGarbageGadgets() {
|
public List<SceneGadget> getGarbageGadgets() {
|
||||||
return this.garbages == null ? null : this.garbages.gadgets;
|
return this.garbages == null ? null : this.garbages.gadgets;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompiledScript getScript() {
|
public CompiledScript getScript() {
|
||||||
return this.script;
|
return this.script;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SceneSuite getSuiteByIndex(int index) {
|
public SceneSuite getSuiteByIndex(int index) {
|
||||||
if(index < 1 || index > suites.size()) {
|
if (index < 1 || index > suites.size()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return this.suites.get(index - 1);
|
return this.suites.get(index - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bindings getBindings() {
|
public Bindings getBindings() {
|
||||||
return this.bindings;
|
return this.bindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized SceneGroup load(int sceneId) {
|
public synchronized SceneGroup load(int sceneId) {
|
||||||
if (this.loaded) {
|
if (this.loaded) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
// Set flag here so if there is no script, we don't call this function over and over again.
|
// Set flag here so if there is no script, we don't call this function over and over again.
|
||||||
this.setLoaded(true);
|
this.setLoaded(true);
|
||||||
|
|
||||||
this.bindings = ScriptLoader.getEngine().createBindings();
|
this.bindings = ScriptLoader.getEngine().createBindings();
|
||||||
|
|
||||||
CompiledScript cs = ScriptLoader.getScript("Scene/" + sceneId + "/scene" + sceneId + "_group" + this.id + ".lua");
|
CompiledScript cs =
|
||||||
|
ScriptLoader.getScript(
|
||||||
if (cs == null) {
|
"Scene/" + sceneId + "/scene" + sceneId + "_group" + this.id + ".lua");
|
||||||
return this;
|
|
||||||
}
|
if (cs == null) {
|
||||||
|
return this;
|
||||||
this.script = cs;
|
}
|
||||||
|
|
||||||
// Eval script
|
this.script = cs;
|
||||||
try {
|
|
||||||
cs.eval(this.bindings);
|
// Eval script
|
||||||
|
try {
|
||||||
// Set
|
cs.eval(this.bindings);
|
||||||
this.monsters = ScriptLoader.getSerializer().toList(SceneMonster.class, this.bindings.get("monsters")).stream()
|
|
||||||
.collect(Collectors.toMap(x -> x.config_id, y -> y, (a, b) -> a));
|
// Set
|
||||||
this.monsters.values().forEach(m -> m.group = this);
|
this.monsters =
|
||||||
|
ScriptLoader.getSerializer()
|
||||||
this.npcs = ScriptLoader.getSerializer().toList(SceneNPC.class, this.bindings.get("npcs")).stream()
|
.toList(SceneMonster.class, this.bindings.get("monsters"))
|
||||||
.collect(Collectors.toMap(x -> x.config_id, y -> y, (a, b) -> a));
|
.stream()
|
||||||
this.npcs.values().forEach(m -> m.group = this);
|
.collect(Collectors.toMap(x -> x.config_id, y -> y, (a, b) -> a));
|
||||||
|
this.monsters.values().forEach(m -> m.group = this);
|
||||||
this.gadgets = ScriptLoader.getSerializer().toList(SceneGadget.class, this.bindings.get("gadgets")).stream()
|
|
||||||
.collect(Collectors.toMap(x -> x.config_id, y -> y, (a, b) -> a));
|
this.npcs =
|
||||||
this.gadgets.values().forEach(m -> m.group = this);
|
ScriptLoader.getSerializer().toList(SceneNPC.class, this.bindings.get("npcs")).stream()
|
||||||
|
.collect(Collectors.toMap(x -> x.config_id, y -> y, (a, b) -> a));
|
||||||
this.triggers = ScriptLoader.getSerializer().toList(SceneTrigger.class, this.bindings.get("triggers")).stream()
|
this.npcs.values().forEach(m -> m.group = this);
|
||||||
.collect(Collectors.toMap(SceneTrigger::getName, y -> y, (a, b) -> a));
|
|
||||||
this.triggers.values().forEach(t -> t.currentGroup = this);
|
this.gadgets =
|
||||||
|
ScriptLoader.getSerializer()
|
||||||
this.suites = ScriptLoader.getSerializer().toList(SceneSuite.class, this.bindings.get("suites"));
|
.toList(SceneGadget.class, this.bindings.get("gadgets"))
|
||||||
this.regions = ScriptLoader.getSerializer().toList(SceneRegion.class, this.bindings.get("regions")).stream()
|
.stream()
|
||||||
.collect(Collectors.toMap(x -> x.config_id, y -> y, (a, b) -> a));
|
.collect(Collectors.toMap(x -> x.config_id, y -> y, (a, b) -> a));
|
||||||
this.regions.values().forEach(m -> m.group = this);
|
this.gadgets.values().forEach(m -> m.group = this);
|
||||||
|
|
||||||
this.init_config = ScriptLoader.getSerializer().toObject(SceneInitConfig.class, this.bindings.get("init_config"));
|
this.triggers =
|
||||||
|
ScriptLoader.getSerializer()
|
||||||
// Garbages // TODO: fix properly later
|
.toList(SceneTrigger.class, this.bindings.get("triggers"))
|
||||||
Object garbagesValue = this.bindings.get("garbages");
|
.stream()
|
||||||
if (garbagesValue instanceof LuaValue garbagesTable) {
|
.collect(Collectors.toMap(SceneTrigger::getName, y -> y, (a, b) -> a));
|
||||||
this.garbages = new SceneGarbage();
|
this.triggers.values().forEach(t -> t.currentGroup = this);
|
||||||
if (garbagesTable.checktable().get("gadgets") != LuaValue.NIL) {
|
|
||||||
this.garbages.gadgets = ScriptLoader.getSerializer().toList(SceneGadget.class, garbagesTable.checktable().get("gadgets").checktable());
|
this.suites =
|
||||||
this.garbages.gadgets.forEach(m -> m.group = this);
|
ScriptLoader.getSerializer().toList(SceneSuite.class, this.bindings.get("suites"));
|
||||||
}
|
this.regions =
|
||||||
}
|
ScriptLoader.getSerializer()
|
||||||
|
.toList(SceneRegion.class, this.bindings.get("regions"))
|
||||||
// Add variables to suite
|
.stream()
|
||||||
this.variables = ScriptLoader.getSerializer().toList(SceneVar.class, this.bindings.get("variables"));
|
.collect(Collectors.toMap(x -> x.config_id, y -> y, (a, b) -> a));
|
||||||
|
this.regions.values().forEach(m -> m.group = this);
|
||||||
// Add monsters and gadgets to suite
|
|
||||||
this.suites.forEach(i -> i.init(this));
|
this.init_config =
|
||||||
|
ScriptLoader.getSerializer()
|
||||||
} catch (ScriptException e) {
|
.toObject(SceneInitConfig.class, this.bindings.get("init_config"));
|
||||||
Grasscutter.getLogger().error("An error occurred while loading group " + this.id + " in scene " + sceneId + ".", e);
|
|
||||||
}
|
// Garbages // TODO: fix properly later
|
||||||
|
Object garbagesValue = this.bindings.get("garbages");
|
||||||
Grasscutter.getLogger().debug("Successfully loaded group {} in scene {}.", this.id, sceneId);
|
if (garbagesValue instanceof LuaValue garbagesTable) {
|
||||||
return this;
|
this.garbages = new SceneGarbage();
|
||||||
}
|
if (garbagesTable.checktable().get("gadgets") != LuaValue.NIL) {
|
||||||
|
this.garbages.gadgets =
|
||||||
public int findInitSuiteIndex(int exclude_index) { //TODO: Investigate end index
|
ScriptLoader.getSerializer()
|
||||||
if (init_config == null) return 1;
|
.toList(
|
||||||
if (init_config.io_type == 1) return init_config.suite; //IO TYPE FLOW
|
SceneGadget.class, garbagesTable.checktable().get("gadgets").checktable());
|
||||||
if (init_config.rand_suite) {
|
this.garbages.gadgets.forEach(m -> m.group = this);
|
||||||
if (suites.size() == 1) {
|
}
|
||||||
return init_config.suite;
|
}
|
||||||
} else {
|
|
||||||
List<Integer> randSuiteList = new ArrayList<>();
|
// Add variables to suite
|
||||||
for (int i = 0; i < suites.size(); i++) {
|
this.variables =
|
||||||
if (i == exclude_index) continue;
|
ScriptLoader.getSerializer().toList(SceneVar.class, this.bindings.get("variables"));
|
||||||
|
|
||||||
var suite = suites.get(i);
|
// Add monsters and gadgets to suite
|
||||||
for(int j = 0; j < suite.rand_weight; j++) randSuiteList.add(i);
|
this.suites.forEach(i -> i.init(this));
|
||||||
}
|
|
||||||
|
} catch (ScriptException e) {
|
||||||
return randSuiteList.get(new Random().nextInt(randSuiteList.size()));
|
Grasscutter.getLogger()
|
||||||
}
|
.error(
|
||||||
}
|
"An error occurred while loading group " + this.id + " in scene " + sceneId + ".", e);
|
||||||
return init_config.suite;
|
}
|
||||||
}
|
|
||||||
|
Grasscutter.getLogger().debug("Successfully loaded group {} in scene {}.", this.id, sceneId);
|
||||||
public Optional<SceneBossChest> searchBossChestInGroup() {
|
return this;
|
||||||
return this.gadgets.values().stream()
|
}
|
||||||
.filter(g -> g.boss_chest != null && g.boss_chest.monster_config_id > 0)
|
|
||||||
.map(g -> g.boss_chest)
|
public int findInitSuiteIndex(int exclude_index) { // TODO: Investigate end index
|
||||||
.findFirst();
|
if (init_config == null) return 1;
|
||||||
}
|
if (init_config.io_type == 1) return init_config.suite; // IO TYPE FLOW
|
||||||
|
if (init_config.rand_suite) {
|
||||||
}
|
if (suites.size() == 1) {
|
||||||
|
return init_config.suite;
|
||||||
|
} else {
|
||||||
|
List<Integer> randSuiteList = new ArrayList<>();
|
||||||
|
for (int i = 0; i < suites.size(); i++) {
|
||||||
|
if (i == exclude_index) continue;
|
||||||
|
|
||||||
|
var suite = suites.get(i);
|
||||||
|
for (int j = 0; j < suite.rand_weight; j++) randSuiteList.add(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return randSuiteList.get(new Random().nextInt(randSuiteList.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return init_config.suite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<SceneBossChest> searchBossChestInGroup() {
|
||||||
|
return this.gadgets.values().stream()
|
||||||
|
.filter(g -> g.boss_chest != null && g.boss_chest.monster_config_id > 0)
|
||||||
|
.map(g -> g.boss_chest)
|
||||||
|
.findFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package emu.grasscutter.scripts.data;
|
package emu.grasscutter.scripts.data;
|
||||||
|
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@Setter
|
@Setter
|
||||||
public final class SceneInitConfig {
|
public final class SceneInitConfig {
|
||||||
public int suite;
|
public int suite;
|
||||||
public int end_suite;
|
public int end_suite;
|
||||||
public int io_type;
|
public int io_type;
|
||||||
public boolean rand_suite;
|
public boolean rand_suite;
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package emu.grasscutter.scripts.data;
|
package emu.grasscutter.scripts.data;
|
||||||
|
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@Setter
|
@Setter
|
||||||
public class SceneMonster extends SceneObject{
|
public class SceneMonster extends SceneObject {
|
||||||
public int monster_id;
|
public int monster_id;
|
||||||
public int pose_id;
|
public int pose_id;
|
||||||
public int drop_id;
|
public int drop_id;
|
||||||
public boolean disableWander;
|
public boolean disableWander;
|
||||||
public int title_id;
|
public int title_id;
|
||||||
public int special_name_id;
|
public int special_name_id;
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
package emu.grasscutter.scripts.data;
|
package emu.grasscutter.scripts.data;
|
||||||
|
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@Setter
|
@Setter
|
||||||
public abstract class SceneObject {
|
public abstract class SceneObject {
|
||||||
public int level;
|
public int level;
|
||||||
public int config_id;
|
public int config_id;
|
||||||
public int area_id;
|
public int area_id;
|
||||||
public int vision_level = 0;
|
public int vision_level = 0;
|
||||||
|
|
||||||
public Position pos;
|
public Position pos;
|
||||||
public Position rot;
|
public Position rot;
|
||||||
/** not set by lua */
|
/** not set by lua */
|
||||||
public transient SceneGroup group;
|
public transient SceneGroup group;
|
||||||
}
|
}
|
||||||
|
@ -1,63 +1,61 @@
|
|||||||
package emu.grasscutter.scripts.data;
|
package emu.grasscutter.scripts.data;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import lombok.Setter;
|
||||||
import lombok.Setter;
|
import lombok.ToString;
|
||||||
import lombok.ToString;
|
|
||||||
|
@ToString
|
||||||
@ToString
|
@Setter
|
||||||
@Setter
|
public class SceneSuite {
|
||||||
public class SceneSuite {
|
// make it refer the default empty list to avoid NPE caused by some group
|
||||||
// make it refer the default empty list to avoid NPE caused by some group
|
public List<Integer> monsters = List.of();
|
||||||
public List<Integer> monsters = List.of();
|
public List<Integer> gadgets = List.of();
|
||||||
public List<Integer> gadgets = List.of();
|
public List<String> triggers = List.of();
|
||||||
public List<String> triggers = List.of();
|
public List<Integer> regions = List.of();
|
||||||
public List<Integer> regions = List.of();
|
public int rand_weight;
|
||||||
public int rand_weight;
|
|
||||||
|
public boolean ban_refresh = false;
|
||||||
public boolean ban_refresh = false;
|
|
||||||
|
public transient List<SceneMonster> sceneMonsters = List.of();
|
||||||
public transient List<SceneMonster> sceneMonsters = List.of();
|
public transient List<SceneGadget> sceneGadgets = List.of();
|
||||||
public transient List<SceneGadget> sceneGadgets = List.of();
|
public transient List<SceneTrigger> sceneTriggers = List.of();
|
||||||
public transient List<SceneTrigger> sceneTriggers = List.of();
|
public transient List<SceneRegion> sceneRegions = List.of();
|
||||||
public transient List<SceneRegion> sceneRegions = List.of();
|
|
||||||
|
public void init(SceneGroup sceneGroup) {
|
||||||
public void init(SceneGroup sceneGroup) {
|
if (sceneGroup.monsters != null) {
|
||||||
if(sceneGroup.monsters != null){
|
this.sceneMonsters =
|
||||||
this.sceneMonsters = new ArrayList<>(
|
new ArrayList<>(
|
||||||
this.monsters.stream()
|
this.monsters.stream()
|
||||||
.filter(sceneGroup.monsters::containsKey)
|
.filter(sceneGroup.monsters::containsKey)
|
||||||
.map(sceneGroup.monsters::get)
|
.map(sceneGroup.monsters::get)
|
||||||
.toList()
|
.toList());
|
||||||
);
|
}
|
||||||
}
|
|
||||||
|
if (sceneGroup.gadgets != null) {
|
||||||
if(sceneGroup.gadgets != null){
|
this.sceneGadgets =
|
||||||
this.sceneGadgets = new ArrayList<>(
|
new ArrayList<>(
|
||||||
this.gadgets.stream()
|
this.gadgets.stream()
|
||||||
.filter(sceneGroup.gadgets::containsKey)
|
.filter(sceneGroup.gadgets::containsKey)
|
||||||
.map(sceneGroup.gadgets::get)
|
.map(sceneGroup.gadgets::get)
|
||||||
.toList()
|
.toList());
|
||||||
);
|
}
|
||||||
}
|
|
||||||
|
if (sceneGroup.triggers != null) {
|
||||||
if(sceneGroup.triggers != null) {
|
this.sceneTriggers =
|
||||||
this.sceneTriggers = new ArrayList<>(
|
new ArrayList<>(
|
||||||
this.triggers.stream()
|
this.triggers.stream()
|
||||||
.filter(sceneGroup.triggers::containsKey)
|
.filter(sceneGroup.triggers::containsKey)
|
||||||
.map(sceneGroup.triggers::get)
|
.map(sceneGroup.triggers::get)
|
||||||
.toList()
|
.toList());
|
||||||
);
|
}
|
||||||
}
|
if (sceneGroup.regions != null) {
|
||||||
if(sceneGroup.regions != null) {
|
this.sceneRegions =
|
||||||
this.sceneRegions = new ArrayList<>(
|
new ArrayList<>(
|
||||||
this.regions.stream()
|
this.regions.stream()
|
||||||
.filter(sceneGroup.regions::containsKey)
|
.filter(sceneGroup.regions::containsKey)
|
||||||
.map(sceneGroup.regions::get)
|
.map(sceneGroup.regions::get)
|
||||||
.toList()
|
.toList());
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,45 +1,57 @@
|
|||||||
package emu.grasscutter.scripts.data;
|
package emu.grasscutter.scripts.data;
|
||||||
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@Getter
|
@Getter
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
// todo find way to deserialize from lua with final fields, maybe with the help of Builder?
|
// todo find way to deserialize from lua with final fields, maybe with the help of Builder?
|
||||||
public final class SceneTrigger {
|
public final class SceneTrigger {
|
||||||
private String name;
|
private String name;
|
||||||
private int config_id;
|
private int config_id;
|
||||||
private int event;
|
private int event;
|
||||||
private int trigger_count = 1;
|
private int trigger_count = 1;
|
||||||
private String source;
|
private String source;
|
||||||
private String condition;
|
private String condition;
|
||||||
private String action;
|
private String action;
|
||||||
private String tag;
|
private String tag;
|
||||||
|
|
||||||
public transient SceneGroup currentGroup;
|
public transient SceneGroup currentGroup;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (obj instanceof SceneTrigger sceneTrigger){
|
if (obj instanceof SceneTrigger sceneTrigger) {
|
||||||
return this.name.equals(sceneTrigger.name);
|
return this.name.equals(sceneTrigger.name);
|
||||||
} else return super.equals(obj);
|
} else return super.equals(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return name.hashCode();
|
return name.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SceneTrigger{" +
|
return "SceneTrigger{"
|
||||||
"name='" + name + '\'' +
|
+ "name='"
|
||||||
", config_id=" + config_id +
|
+ name
|
||||||
", event=" + event +
|
+ '\''
|
||||||
", source='" + source + '\'' +
|
+ ", config_id="
|
||||||
", condition='" + condition + '\'' +
|
+ config_id
|
||||||
", action='" + action + '\'' +
|
+ ", event="
|
||||||
", trigger_count='" + trigger_count + '\'' +
|
+ event
|
||||||
'}';
|
+ ", source='"
|
||||||
}
|
+ source
|
||||||
}
|
+ '\''
|
||||||
|
+ ", condition='"
|
||||||
|
+ condition
|
||||||
|
+ '\''
|
||||||
|
+ ", action='"
|
||||||
|
+ action
|
||||||
|
+ '\''
|
||||||
|
+ ", trigger_count='"
|
||||||
|
+ trigger_count
|
||||||
|
+ '\''
|
||||||
|
+ '}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,90 +1,90 @@
|
|||||||
package emu.grasscutter.scripts.data;
|
package emu.grasscutter.scripts.data;
|
||||||
|
|
||||||
public class ScriptArgs {
|
public class ScriptArgs {
|
||||||
public int param1;
|
public int param1;
|
||||||
public int param2;
|
public int param2;
|
||||||
public int param3;
|
public int param3;
|
||||||
public int source_eid; // Source entity
|
public int source_eid; // Source entity
|
||||||
public int target_eid;
|
public int target_eid;
|
||||||
public int group_id;
|
public int group_id;
|
||||||
public String source; // source string, used for timers
|
public String source; // source string, used for timers
|
||||||
public int type; // lua event type, used by scripts and the ScriptManager
|
public int type; // lua event type, used by scripts and the ScriptManager
|
||||||
|
|
||||||
public ScriptArgs(int groupId, int eventType) {
|
public ScriptArgs(int groupId, int eventType) {
|
||||||
this(groupId, eventType, 0,0);
|
this(groupId, eventType, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScriptArgs(int groupId, int eventType, int param1) {
|
public ScriptArgs(int groupId, int eventType, int param1) {
|
||||||
this(groupId, eventType, param1,0);
|
this(groupId, eventType, param1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScriptArgs(int groupId, int eventType, int param1, int param2) {
|
public ScriptArgs(int groupId, int eventType, int param1, int param2) {
|
||||||
this.type = eventType;
|
this.type = eventType;
|
||||||
this.param1 = param1;
|
this.param1 = param1;
|
||||||
this.param2 = param2;
|
this.param2 = param2;
|
||||||
this.group_id = groupId;
|
this.group_id = groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getParam1() {
|
public int getParam1() {
|
||||||
return param1;
|
return param1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScriptArgs setParam1(int param1) {
|
public ScriptArgs setParam1(int param1) {
|
||||||
this.param1 = param1;
|
this.param1 = param1;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getParam2() {
|
public int getParam2() {
|
||||||
return param2;
|
return param2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScriptArgs setParam2(int param2) {
|
public ScriptArgs setParam2(int param2) {
|
||||||
this.param2 = param2;
|
this.param2 = param2;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getParam3() {
|
public int getParam3() {
|
||||||
return param3;
|
return param3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScriptArgs setParam3(int param3) {
|
public ScriptArgs setParam3(int param3) {
|
||||||
this.param3 = param3;
|
this.param3 = param3;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSourceEntityId() {
|
public int getSourceEntityId() {
|
||||||
return source_eid;
|
return source_eid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScriptArgs setSourceEntityId(int source_eid) {
|
public ScriptArgs setSourceEntityId(int source_eid) {
|
||||||
this.source_eid = source_eid;
|
this.source_eid = source_eid;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTargetEntityId() {
|
public int getTargetEntityId() {
|
||||||
return target_eid;
|
return target_eid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScriptArgs setTargetEntityId(int target_eid) {
|
public ScriptArgs setTargetEntityId(int target_eid) {
|
||||||
this.target_eid = target_eid;
|
this.target_eid = target_eid;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEventSource() {
|
public String getEventSource() {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScriptArgs setEventSource(String source) {
|
public ScriptArgs setEventSource(String source) {
|
||||||
this.source = source;
|
this.source = source;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getGroupId() {
|
public int getGroupId() {
|
||||||
return group_id;
|
return group_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScriptArgs setGroupId(int group_id) {
|
public ScriptArgs setGroupId(int group_id) {
|
||||||
this.group_id = group_id;
|
this.group_id = group_id;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,92 +1,102 @@
|
|||||||
package emu.grasscutter.scripts.service;
|
package emu.grasscutter.scripts.service;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.EntityMonster;
|
import emu.grasscutter.game.entity.EntityMonster;
|
||||||
import emu.grasscutter.scripts.SceneScriptManager;
|
import emu.grasscutter.scripts.SceneScriptManager;
|
||||||
import emu.grasscutter.scripts.constants.EventType;
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
import emu.grasscutter.scripts.data.SceneMonster;
|
import emu.grasscutter.scripts.data.SceneMonster;
|
||||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||||
import emu.grasscutter.scripts.listener.ScriptMonsterListener;
|
import emu.grasscutter.scripts.listener.ScriptMonsterListener;
|
||||||
|
import java.util.List;
|
||||||
import java.util.ArrayList;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.List;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
public final class ScriptMonsterTideService {
|
||||||
|
private final SceneScriptManager sceneScriptManager;
|
||||||
public final class ScriptMonsterTideService {
|
private final SceneGroup currentGroup;
|
||||||
private final SceneScriptManager sceneScriptManager;
|
private final AtomicInteger monsterAlive;
|
||||||
private final SceneGroup currentGroup;
|
private final AtomicInteger monsterTideCount;
|
||||||
private final AtomicInteger monsterAlive;
|
private final AtomicInteger monsterKillCount;
|
||||||
private final AtomicInteger monsterTideCount;
|
private final int monsterSceneLimit;
|
||||||
private final AtomicInteger monsterKillCount;
|
private final ConcurrentLinkedQueue<Integer> monsterConfigOrders;
|
||||||
private final int monsterSceneLimit;
|
private final List<Integer> monsterConfigIds;
|
||||||
private final ConcurrentLinkedQueue<Integer> monsterConfigOrders;
|
private final OnMonsterCreated onMonsterCreated = new OnMonsterCreated();
|
||||||
private final List<Integer> monsterConfigIds;
|
private final OnMonsterDead onMonsterDead = new OnMonsterDead();
|
||||||
private final OnMonsterCreated onMonsterCreated= new OnMonsterCreated();
|
|
||||||
private final OnMonsterDead onMonsterDead= new OnMonsterDead();
|
public ScriptMonsterTideService(
|
||||||
|
SceneScriptManager sceneScriptManager,
|
||||||
public ScriptMonsterTideService(SceneScriptManager sceneScriptManager,
|
SceneGroup group,
|
||||||
SceneGroup group, int tideCount, int monsterSceneLimit, Integer[] ordersConfigId){
|
int tideCount,
|
||||||
this.sceneScriptManager = sceneScriptManager;
|
int monsterSceneLimit,
|
||||||
this.currentGroup = group;
|
Integer[] ordersConfigId) {
|
||||||
this.monsterSceneLimit = monsterSceneLimit;
|
this.sceneScriptManager = sceneScriptManager;
|
||||||
this.monsterTideCount = new AtomicInteger(tideCount);
|
this.currentGroup = group;
|
||||||
this.monsterKillCount = new AtomicInteger(0);
|
this.monsterSceneLimit = monsterSceneLimit;
|
||||||
this.monsterAlive = new AtomicInteger(0);
|
this.monsterTideCount = new AtomicInteger(tideCount);
|
||||||
this.monsterConfigOrders = new ConcurrentLinkedQueue<>(List.of(ordersConfigId));
|
this.monsterKillCount = new AtomicInteger(0);
|
||||||
this.monsterConfigIds = List.of(ordersConfigId);
|
this.monsterAlive = new AtomicInteger(0);
|
||||||
|
this.monsterConfigOrders = new ConcurrentLinkedQueue<>(List.of(ordersConfigId));
|
||||||
this.sceneScriptManager.getScriptMonsterSpawnService().addMonsterCreatedListener(onMonsterCreated);
|
this.monsterConfigIds = List.of(ordersConfigId);
|
||||||
this.sceneScriptManager.getScriptMonsterSpawnService().addMonsterDeadListener(onMonsterDead);
|
|
||||||
// spawn the first turn
|
this.sceneScriptManager
|
||||||
for (int i = 0; i < this.monsterSceneLimit; i++) {
|
.getScriptMonsterSpawnService()
|
||||||
sceneScriptManager.addEntity(this.sceneScriptManager.createMonster(group.id, group.block_id, getNextMonster()));
|
.addMonsterCreatedListener(onMonsterCreated);
|
||||||
}
|
this.sceneScriptManager.getScriptMonsterSpawnService().addMonsterDeadListener(onMonsterDead);
|
||||||
}
|
// spawn the first turn
|
||||||
|
for (int i = 0; i < this.monsterSceneLimit; i++) {
|
||||||
public class OnMonsterCreated implements ScriptMonsterListener{
|
sceneScriptManager.addEntity(
|
||||||
@Override
|
this.sceneScriptManager.createMonster(group.id, group.block_id, getNextMonster()));
|
||||||
public void onNotify(EntityMonster sceneMonster) {
|
}
|
||||||
if(monsterConfigIds.contains(sceneMonster.getConfigId()) && monsterSceneLimit > 0){
|
}
|
||||||
monsterAlive.incrementAndGet();
|
|
||||||
monsterTideCount.decrementAndGet();
|
public class OnMonsterCreated implements ScriptMonsterListener {
|
||||||
}
|
@Override
|
||||||
}
|
public void onNotify(EntityMonster sceneMonster) {
|
||||||
}
|
if (monsterConfigIds.contains(sceneMonster.getConfigId()) && monsterSceneLimit > 0) {
|
||||||
|
monsterAlive.incrementAndGet();
|
||||||
public SceneMonster getNextMonster(){
|
monsterTideCount.decrementAndGet();
|
||||||
var nextId = this.monsterConfigOrders.poll();
|
}
|
||||||
if(currentGroup.monsters.containsKey(nextId)){
|
}
|
||||||
return currentGroup.monsters.get(nextId);
|
}
|
||||||
}
|
|
||||||
// TODO some monster config_id do not exist in groups, so temporarily set it to the first
|
public SceneMonster getNextMonster() {
|
||||||
return currentGroup.monsters.values().stream().findFirst().orElse(null);
|
var nextId = this.monsterConfigOrders.poll();
|
||||||
}
|
if (currentGroup.monsters.containsKey(nextId)) {
|
||||||
|
return currentGroup.monsters.get(nextId);
|
||||||
public class OnMonsterDead implements ScriptMonsterListener {
|
}
|
||||||
@Override
|
// TODO some monster config_id do not exist in groups, so temporarily set it to the first
|
||||||
public void onNotify(EntityMonster sceneMonster) {
|
return currentGroup.monsters.values().stream().findFirst().orElse(null);
|
||||||
if (monsterSceneLimit <= 0) {
|
}
|
||||||
return;
|
|
||||||
}
|
public class OnMonsterDead implements ScriptMonsterListener {
|
||||||
if (monsterAlive.decrementAndGet() >= monsterSceneLimit) {
|
@Override
|
||||||
// maybe not happen
|
public void onNotify(EntityMonster sceneMonster) {
|
||||||
return;
|
if (monsterSceneLimit <= 0) {
|
||||||
}
|
return;
|
||||||
monsterKillCount.incrementAndGet();
|
}
|
||||||
if (monsterTideCount.get() > 0) {
|
if (monsterAlive.decrementAndGet() >= monsterSceneLimit) {
|
||||||
// add more
|
// maybe not happen
|
||||||
sceneScriptManager.addEntity(sceneScriptManager.createMonster(currentGroup.id, currentGroup.block_id, getNextMonster()));
|
return;
|
||||||
}
|
}
|
||||||
// spawn the last turn of monsters
|
monsterKillCount.incrementAndGet();
|
||||||
// fix the 5-2
|
if (monsterTideCount.get() > 0) {
|
||||||
sceneScriptManager.callEvent(new ScriptArgs(currentGroup.id, EventType.EVENT_MONSTER_TIDE_DIE, monsterKillCount.get()));
|
// add more
|
||||||
}
|
sceneScriptManager.addEntity(
|
||||||
|
sceneScriptManager.createMonster(
|
||||||
}
|
currentGroup.id, currentGroup.block_id, getNextMonster()));
|
||||||
|
}
|
||||||
public void unload(){
|
// spawn the last turn of monsters
|
||||||
this.sceneScriptManager.getScriptMonsterSpawnService().removeMonsterCreatedListener(onMonsterCreated);
|
// fix the 5-2
|
||||||
this.sceneScriptManager.getScriptMonsterSpawnService().removeMonsterDeadListener(onMonsterDead);
|
sceneScriptManager.callEvent(
|
||||||
}
|
new ScriptArgs(
|
||||||
}
|
currentGroup.id, EventType.EVENT_MONSTER_TIDE_DIE, monsterKillCount.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unload() {
|
||||||
|
this.sceneScriptManager
|
||||||
|
.getScriptMonsterSpawnService()
|
||||||
|
.removeMonsterCreatedListener(onMonsterCreated);
|
||||||
|
this.sceneScriptManager.getScriptMonsterSpawnService().removeMonsterDeadListener(onMonsterDead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,24 +1,27 @@
|
|||||||
package emu.grasscutter.server.event.entity;
|
package emu.grasscutter.server.event.entity;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.GameEntity;
|
import emu.grasscutter.game.entity.GameEntity;
|
||||||
import emu.grasscutter.game.props.ElementType;
|
import emu.grasscutter.game.props.ElementType;
|
||||||
import emu.grasscutter.server.event.Cancellable;
|
import emu.grasscutter.server.event.Cancellable;
|
||||||
import emu.grasscutter.server.event.types.EntityEvent;
|
import emu.grasscutter.server.event.types.EntityEvent;
|
||||||
import lombok.Getter;
|
import javax.annotation.Nullable;
|
||||||
import lombok.Setter;
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
public final class EntityDamageEvent extends EntityEvent implements Cancellable {
|
||||||
public final class EntityDamageEvent extends EntityEvent implements Cancellable {
|
@Getter @Setter private float damage;
|
||||||
@Getter @Setter private float damage;
|
@Getter @Setter private ElementType attackElementType;
|
||||||
@Getter @Setter private ElementType attackElementType;
|
@Getter @Nullable private final GameEntity damager;
|
||||||
@Getter @Nullable private final GameEntity damager;
|
|
||||||
|
public EntityDamageEvent(
|
||||||
public EntityDamageEvent(GameEntity entity, float damage, ElementType attackElementType, @Nullable GameEntity damager) {
|
GameEntity entity,
|
||||||
super(entity);
|
float damage,
|
||||||
|
ElementType attackElementType,
|
||||||
this.damage = damage;
|
@Nullable GameEntity damager) {
|
||||||
this.attackElementType = attackElementType;
|
super(entity);
|
||||||
this.damager = damager;
|
|
||||||
}
|
this.damage = damage;
|
||||||
}
|
this.attackElementType = attackElementType;
|
||||||
|
this.damager = damager;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,279 +1,279 @@
|
|||||||
package emu.grasscutter.server.game;
|
package emu.grasscutter.server.game;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.GAME_INFO;
|
import static emu.grasscutter.config.Configuration.GAME_INFO;
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
|
||||||
import emu.grasscutter.GameConstants;
|
import emu.grasscutter.GameConstants;
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.database.DatabaseHelper;
|
import emu.grasscutter.database.DatabaseHelper;
|
||||||
import emu.grasscutter.game.Account;
|
import emu.grasscutter.game.Account;
|
||||||
import emu.grasscutter.game.battlepass.BattlePassSystem;
|
import emu.grasscutter.game.battlepass.BattlePassSystem;
|
||||||
import emu.grasscutter.game.chat.ChatSystem;
|
import emu.grasscutter.game.chat.ChatSystem;
|
||||||
import emu.grasscutter.game.chat.ChatSystemHandler;
|
import emu.grasscutter.game.chat.ChatSystemHandler;
|
||||||
import emu.grasscutter.game.combine.CombineManger;
|
import emu.grasscutter.game.combine.CombineManger;
|
||||||
import emu.grasscutter.game.drop.DropSystem;
|
import emu.grasscutter.game.drop.DropSystem;
|
||||||
import emu.grasscutter.game.dungeons.DungeonSystem;
|
import emu.grasscutter.game.dungeons.DungeonSystem;
|
||||||
import emu.grasscutter.game.expedition.ExpeditionSystem;
|
import emu.grasscutter.game.expedition.ExpeditionSystem;
|
||||||
import emu.grasscutter.game.gacha.GachaSystem;
|
import emu.grasscutter.game.gacha.GachaSystem;
|
||||||
import emu.grasscutter.game.managers.cooking.CookingCompoundManager;
|
import emu.grasscutter.game.managers.cooking.CookingCompoundManager;
|
||||||
import emu.grasscutter.game.managers.cooking.CookingManager;
|
import emu.grasscutter.game.managers.cooking.CookingManager;
|
||||||
import emu.grasscutter.game.managers.energy.EnergyManager;
|
import emu.grasscutter.game.managers.energy.EnergyManager;
|
||||||
import emu.grasscutter.game.managers.stamina.StaminaManager;
|
import emu.grasscutter.game.managers.stamina.StaminaManager;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.quest.QuestSystem;
|
import emu.grasscutter.game.quest.QuestSystem;
|
||||||
import emu.grasscutter.game.shop.ShopSystem;
|
import emu.grasscutter.game.shop.ShopSystem;
|
||||||
import emu.grasscutter.game.systems.AnnouncementSystem;
|
import emu.grasscutter.game.systems.AnnouncementSystem;
|
||||||
import emu.grasscutter.game.systems.InventorySystem;
|
import emu.grasscutter.game.systems.InventorySystem;
|
||||||
import emu.grasscutter.game.systems.MultiplayerSystem;
|
import emu.grasscutter.game.systems.MultiplayerSystem;
|
||||||
import emu.grasscutter.game.tower.TowerSystem;
|
import emu.grasscutter.game.tower.TowerSystem;
|
||||||
import emu.grasscutter.game.world.World;
|
import emu.grasscutter.game.world.World;
|
||||||
import emu.grasscutter.game.world.WorldDataSystem;
|
import emu.grasscutter.game.world.WorldDataSystem;
|
||||||
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;
|
||||||
import emu.grasscutter.server.event.game.ServerTickEvent;
|
import emu.grasscutter.server.event.game.ServerTickEvent;
|
||||||
import emu.grasscutter.server.event.internal.ServerStartEvent;
|
import emu.grasscutter.server.event.internal.ServerStartEvent;
|
||||||
import emu.grasscutter.server.event.internal.ServerStopEvent;
|
import emu.grasscutter.server.event.internal.ServerStopEvent;
|
||||||
import emu.grasscutter.server.event.types.ServerEvent;
|
import emu.grasscutter.server.event.types.ServerEvent;
|
||||||
import emu.grasscutter.server.scheduler.ServerTaskScheduler;
|
import emu.grasscutter.server.scheduler.ServerTaskScheduler;
|
||||||
import emu.grasscutter.task.TaskMap;
|
import emu.grasscutter.task.TaskMap;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import kcp.highway.ChannelConfig;
|
import kcp.highway.ChannelConfig;
|
||||||
import kcp.highway.KcpServer;
|
import kcp.highway.KcpServer;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public final class GameServer extends KcpServer {
|
public final class GameServer extends KcpServer {
|
||||||
// Game server base
|
// Game server base
|
||||||
private final InetSocketAddress address;
|
private final InetSocketAddress address;
|
||||||
private final GameServerPacketHandler packetHandler;
|
private final GameServerPacketHandler packetHandler;
|
||||||
private final Map<Integer, Player> players;
|
private final Map<Integer, Player> players;
|
||||||
private final Set<World> worlds;
|
private final Set<World> worlds;
|
||||||
|
|
||||||
// Server systems
|
// Server systems
|
||||||
private final InventorySystem inventorySystem;
|
private final InventorySystem inventorySystem;
|
||||||
private final GachaSystem gachaSystem;
|
private final GachaSystem gachaSystem;
|
||||||
private final ShopSystem shopSystem;
|
private final ShopSystem shopSystem;
|
||||||
private final MultiplayerSystem multiplayerSystem;
|
private final MultiplayerSystem multiplayerSystem;
|
||||||
private final DungeonSystem dungeonSystem;
|
private final DungeonSystem dungeonSystem;
|
||||||
private final ExpeditionSystem expeditionSystem;
|
private final ExpeditionSystem expeditionSystem;
|
||||||
private final DropSystem dropSystem;
|
private final DropSystem dropSystem;
|
||||||
private final WorldDataSystem worldDataSystem;
|
private final WorldDataSystem worldDataSystem;
|
||||||
private final BattlePassSystem battlePassSystem;
|
private final BattlePassSystem battlePassSystem;
|
||||||
private final CombineManger combineSystem;
|
private final CombineManger combineSystem;
|
||||||
private final TowerSystem towerSystem;
|
private final TowerSystem towerSystem;
|
||||||
private final AnnouncementSystem announcementSystem;
|
private final AnnouncementSystem announcementSystem;
|
||||||
private final QuestSystem questSystem;
|
private final QuestSystem questSystem;
|
||||||
|
|
||||||
// Extra
|
// Extra
|
||||||
private final ServerTaskScheduler scheduler;
|
private final ServerTaskScheduler scheduler;
|
||||||
private final TaskMap taskMap;
|
private final TaskMap taskMap;
|
||||||
|
|
||||||
private ChatSystemHandler chatManager;
|
private ChatSystemHandler chatManager;
|
||||||
|
|
||||||
public GameServer() {
|
public GameServer() {
|
||||||
this(getAdapterInetSocketAddress());
|
this(getAdapterInetSocketAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameServer(InetSocketAddress address) {
|
public GameServer(InetSocketAddress address) {
|
||||||
ChannelConfig channelConfig = new ChannelConfig();
|
ChannelConfig channelConfig = new ChannelConfig();
|
||||||
channelConfig.nodelay(true, GAME_INFO.kcpInterval, 2, true);
|
channelConfig.nodelay(true, GAME_INFO.kcpInterval, 2, true);
|
||||||
channelConfig.setMtu(1400);
|
channelConfig.setMtu(1400);
|
||||||
channelConfig.setSndwnd(256);
|
channelConfig.setSndwnd(256);
|
||||||
channelConfig.setRcvwnd(256);
|
channelConfig.setRcvwnd(256);
|
||||||
channelConfig.setTimeoutMillis(30 * 1000); // 30s
|
channelConfig.setTimeoutMillis(30 * 1000); // 30s
|
||||||
channelConfig.setUseConvChannel(true);
|
channelConfig.setUseConvChannel(true);
|
||||||
channelConfig.setAckNoDelay(false);
|
channelConfig.setAckNoDelay(false);
|
||||||
|
|
||||||
this.init(GameSessionManager.getListener(), channelConfig, address);
|
this.init(GameSessionManager.getListener(), channelConfig, address);
|
||||||
|
|
||||||
EnergyManager.initialize();
|
EnergyManager.initialize();
|
||||||
StaminaManager.initialize();
|
StaminaManager.initialize();
|
||||||
CookingManager.initialize();
|
CookingManager.initialize();
|
||||||
CookingCompoundManager.initialize();
|
CookingCompoundManager.initialize();
|
||||||
CombineManger.initialize();
|
CombineManger.initialize();
|
||||||
|
|
||||||
// Game Server base
|
// Game Server base
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.packetHandler = new GameServerPacketHandler(PacketHandler.class);
|
this.packetHandler = new GameServerPacketHandler(PacketHandler.class);
|
||||||
this.players = new ConcurrentHashMap<>();
|
this.players = new ConcurrentHashMap<>();
|
||||||
this.worlds = Collections.synchronizedSet(new HashSet<>());
|
this.worlds = Collections.synchronizedSet(new HashSet<>());
|
||||||
|
|
||||||
// Extra
|
// Extra
|
||||||
this.scheduler = new ServerTaskScheduler();
|
this.scheduler = new ServerTaskScheduler();
|
||||||
this.taskMap = new TaskMap(true);
|
this.taskMap = new TaskMap(true);
|
||||||
|
|
||||||
// Create game systems
|
// Create game systems
|
||||||
this.inventorySystem = new InventorySystem(this);
|
this.inventorySystem = new InventorySystem(this);
|
||||||
this.gachaSystem = new GachaSystem(this);
|
this.gachaSystem = new GachaSystem(this);
|
||||||
this.shopSystem = new ShopSystem(this);
|
this.shopSystem = new ShopSystem(this);
|
||||||
this.multiplayerSystem = new MultiplayerSystem(this);
|
this.multiplayerSystem = new MultiplayerSystem(this);
|
||||||
this.dungeonSystem = new DungeonSystem(this);
|
this.dungeonSystem = new DungeonSystem(this);
|
||||||
this.dropSystem = new DropSystem(this);
|
this.dropSystem = new DropSystem(this);
|
||||||
this.expeditionSystem = new ExpeditionSystem(this);
|
this.expeditionSystem = new ExpeditionSystem(this);
|
||||||
this.combineSystem = new CombineManger(this);
|
this.combineSystem = new CombineManger(this);
|
||||||
this.towerSystem = new TowerSystem(this);
|
this.towerSystem = new TowerSystem(this);
|
||||||
this.worldDataSystem = new WorldDataSystem(this);
|
this.worldDataSystem = new WorldDataSystem(this);
|
||||||
this.battlePassSystem = new BattlePassSystem(this);
|
this.battlePassSystem = new BattlePassSystem(this);
|
||||||
this.announcementSystem = new AnnouncementSystem(this);
|
this.announcementSystem = new AnnouncementSystem(this);
|
||||||
this.questSystem = new QuestSystem(this);
|
this.questSystem = new QuestSystem(this);
|
||||||
|
|
||||||
// Chata manager
|
// Chata manager
|
||||||
this.chatManager = new ChatSystem(this);
|
this.chatManager = new ChatSystem(this);
|
||||||
|
|
||||||
// Hook into shutdown event.
|
// Hook into shutdown event.
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(this::onServerShutdown));
|
Runtime.getRuntime().addShutdownHook(new Thread(this::onServerShutdown));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InetSocketAddress getAdapterInetSocketAddress() {
|
private static InetSocketAddress getAdapterInetSocketAddress() {
|
||||||
InetSocketAddress inetSocketAddress;
|
InetSocketAddress inetSocketAddress;
|
||||||
if (GAME_INFO.bindAddress.equals("")) {
|
if (GAME_INFO.bindAddress.equals("")) {
|
||||||
inetSocketAddress = new InetSocketAddress(GAME_INFO.bindPort);
|
inetSocketAddress = new InetSocketAddress(GAME_INFO.bindPort);
|
||||||
} else {
|
} else {
|
||||||
inetSocketAddress = new InetSocketAddress(GAME_INFO.bindAddress, GAME_INFO.bindPort);
|
inetSocketAddress = new InetSocketAddress(GAME_INFO.bindAddress, GAME_INFO.bindPort);
|
||||||
}
|
}
|
||||||
return inetSocketAddress;
|
return inetSocketAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public ChatSystemHandler getChatManager() {
|
public ChatSystemHandler getChatManager() {
|
||||||
return chatManager;
|
return chatManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void setChatManager(ChatSystemHandler chatManager) {
|
public void setChatManager(ChatSystemHandler chatManager) {
|
||||||
this.chatManager = chatManager;
|
this.chatManager = chatManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatSystemHandler getChatSystem() {
|
public ChatSystemHandler getChatSystem() {
|
||||||
return chatManager;
|
return chatManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setChatSystem(ChatSystemHandler chatManager) {
|
public void setChatSystem(ChatSystemHandler chatManager) {
|
||||||
this.chatManager = chatManager;
|
this.chatManager = chatManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerPlayer(Player player) {
|
public void registerPlayer(Player player) {
|
||||||
getPlayers().put(player.getUid(), player);
|
getPlayers().put(player.getUid(), player);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player getPlayerByUid(int id) {
|
public Player getPlayerByUid(int id) {
|
||||||
return this.getPlayerByUid(id, false);
|
return this.getPlayerByUid(id, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player getPlayerByUid(int id, boolean allowOfflinePlayers) {
|
public Player getPlayerByUid(int id, boolean allowOfflinePlayers) {
|
||||||
// Console check
|
// Console check
|
||||||
if (id == GameConstants.SERVER_CONSOLE_UID) {
|
if (id == GameConstants.SERVER_CONSOLE_UID) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get from online players
|
// Get from online players
|
||||||
Player player = this.getPlayers().get(id);
|
Player player = this.getPlayers().get(id);
|
||||||
|
|
||||||
if (!allowOfflinePlayers) {
|
if (!allowOfflinePlayers) {
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check database if character isnt here
|
// Check database if character isnt here
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
player = DatabaseHelper.getPlayerByUid(id);
|
player = DatabaseHelper.getPlayerByUid(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player getPlayerByAccountId(String accountId) {
|
public Player getPlayerByAccountId(String accountId) {
|
||||||
Optional<Player> playerOpt =
|
Optional<Player> playerOpt =
|
||||||
getPlayers().values().stream()
|
getPlayers().values().stream()
|
||||||
.filter(player -> player.getAccount().getId().equals(accountId))
|
.filter(player -> player.getAccount().getId().equals(accountId))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
return playerOpt.orElse(null);
|
return playerOpt.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SocialDetail.Builder getSocialDetailByUid(int id) {
|
public SocialDetail.Builder getSocialDetailByUid(int id) {
|
||||||
// Get from online players
|
// Get from online players
|
||||||
Player player = this.getPlayerByUid(id, true);
|
Player player = this.getPlayerByUid(id, true);
|
||||||
|
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return player.getSocialDetail();
|
return player.getSocialDetail();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Account getAccountByName(String username) {
|
public Account getAccountByName(String username) {
|
||||||
Optional<Player> playerOpt =
|
Optional<Player> playerOpt =
|
||||||
getPlayers().values().stream()
|
getPlayers().values().stream()
|
||||||
.filter(player -> player.getAccount().getUsername().equals(username))
|
.filter(player -> player.getAccount().getUsername().equals(username))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
if (playerOpt.isPresent()) {
|
if (playerOpt.isPresent()) {
|
||||||
return playerOpt.get().getAccount();
|
return playerOpt.get().getAccount();
|
||||||
}
|
}
|
||||||
return DatabaseHelper.getAccountByName(username);
|
return DatabaseHelper.getAccountByName(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void onTick() {
|
public synchronized void onTick() {
|
||||||
var tickStart = Instant.now();
|
var tickStart = Instant.now();
|
||||||
|
|
||||||
// Tick worlds.
|
// Tick worlds.
|
||||||
this.worlds.removeIf(World::onTick);
|
this.worlds.removeIf(World::onTick);
|
||||||
|
|
||||||
// Tick players.
|
// Tick players.
|
||||||
this.players.values().forEach(Player::onTick);
|
this.players.values().forEach(Player::onTick);
|
||||||
|
|
||||||
// Tick scheduler.
|
// Tick scheduler.
|
||||||
this.getScheduler().runTasks();
|
this.getScheduler().runTasks();
|
||||||
|
|
||||||
// Call server tick event.
|
// Call server tick event.
|
||||||
ServerTickEvent event = new ServerTickEvent(tickStart, Instant.now());
|
ServerTickEvent event = new ServerTickEvent(tickStart, Instant.now());
|
||||||
event.call();
|
event.call();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerWorld(World world) {
|
public void registerWorld(World world) {
|
||||||
this.getWorlds().add(world);
|
this.getWorlds().add(world);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deregisterWorld(World world) {
|
public void deregisterWorld(World world) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
// Schedule game loop.
|
// Schedule game loop.
|
||||||
Timer gameLoop = new Timer();
|
Timer gameLoop = new Timer();
|
||||||
gameLoop.scheduleAtFixedRate(
|
gameLoop.scheduleAtFixedRate(
|
||||||
new TimerTask() {
|
new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
onTick();
|
onTick();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Grasscutter.getLogger().error(translate("messages.game.game_update_error"), e);
|
Grasscutter.getLogger().error(translate("messages.game.game_update_error"), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Date(),
|
new Date(),
|
||||||
1000L);
|
1000L);
|
||||||
Grasscutter.getLogger().info(translate("messages.status.free_software"));
|
Grasscutter.getLogger().info(translate("messages.status.free_software"));
|
||||||
Grasscutter.getLogger()
|
Grasscutter.getLogger()
|
||||||
.info(translate("messages.game.address_bind", GAME_INFO.accessAddress, address.getPort()));
|
.info(translate("messages.game.address_bind", GAME_INFO.accessAddress, address.getPort()));
|
||||||
ServerStartEvent event = new ServerStartEvent(ServerEvent.Type.GAME, OffsetDateTime.now());
|
ServerStartEvent event = new ServerStartEvent(ServerEvent.Type.GAME, OffsetDateTime.now());
|
||||||
event.call();
|
event.call();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onServerShutdown() {
|
public void onServerShutdown() {
|
||||||
ServerStopEvent event = new ServerStopEvent(ServerEvent.Type.GAME, OffsetDateTime.now());
|
ServerStopEvent event = new ServerStopEvent(ServerEvent.Type.GAME, OffsetDateTime.now());
|
||||||
event.call();
|
event.call();
|
||||||
|
|
||||||
// Kick and save all players
|
// Kick and save all players
|
||||||
List<Player> list = new ArrayList<>(this.getPlayers().size());
|
List<Player> list = new ArrayList<>(this.getPlayers().size());
|
||||||
list.addAll(this.getPlayers().values());
|
list.addAll(this.getPlayers().values());
|
||||||
|
|
||||||
for (Player player : list) {
|
for (Player player : list) {
|
||||||
player.getSession().close();
|
player.getSession().close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
//package emu.grasscutter.server.packet.recv;
|
// package emu.grasscutter.server.packet.recv;
|
||||||
//
|
//
|
||||||
//import emu.grasscutter.net.packet.Opcodes;
|
// import emu.grasscutter.net.packet.Opcodes;
|
||||||
//import emu.grasscutter.net.packet.PacketHandler;
|
// import emu.grasscutter.net.packet.PacketHandler;
|
||||||
//import emu.grasscutter.net.packet.PacketOpcodes;
|
// import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
//import emu.grasscutter.server.game.GameSession;
|
// import emu.grasscutter.server.game.GameSession;
|
||||||
//
|
//
|
||||||
//@Opcodes(PacketOpcodes.AddCustomTeamReq)
|
// @Opcodes(PacketOpcodes.AddCustomTeamReq)
|
||||||
//public class HandlerAddCustomTeamReq extends PacketHandler {
|
// public class HandlerAddCustomTeamReq 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.getPlayer().getTeamManager().addNewCustomTeam();
|
// session.getPlayer().getTeamManager().addNewCustomTeam();
|
||||||
// }
|
// }
|
||||||
//}
|
// }
|
||||||
|
@ -1,26 +1,25 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.game.quest.enums.QuestContent;
|
import emu.grasscutter.game.quest.enums.QuestContent;
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.AddQuestContentProgressReqOuterClass.AddQuestContentProgressReq;
|
import emu.grasscutter.net.proto.AddQuestContentProgressReqOuterClass.AddQuestContentProgressReq;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.PacketAddQuestContentProgressRsp;
|
import emu.grasscutter.server.packet.send.PacketAddQuestContentProgressRsp;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.AddQuestContentProgressReq)
|
@Opcodes(PacketOpcodes.AddQuestContentProgressReq)
|
||||||
public class HandlerAddQuestContentProgressReq extends PacketHandler {
|
public class HandlerAddQuestContentProgressReq 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 {
|
||||||
var req = AddQuestContentProgressReq.parseFrom(payload);
|
var req = AddQuestContentProgressReq.parseFrom(payload);
|
||||||
|
|
||||||
// Find all conditions in quest that are the same as the given one
|
// Find all conditions in quest that are the same as the given one
|
||||||
var type = QuestContent.getContentTriggerByValue(req.getContentType());
|
var type = QuestContent.getContentTriggerByValue(req.getContentType());
|
||||||
if(type != null) {
|
if (type != null) {
|
||||||
session.getPlayer().getQuestManager().queueEvent(type, req.getParam());
|
session.getPlayer().getQuestManager().queueEvent(type, req.getParam());
|
||||||
}
|
}
|
||||||
|
|
||||||
session.send(new PacketAddQuestContentProgressRsp(req.getContentType()));
|
session.send(new PacketAddQuestContentProgressRsp(req.getContentType()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
@ -1,39 +1,38 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.AvatarChangeElementTypeReqOuterClass.AvatarChangeElementTypeReq;
|
import emu.grasscutter.net.proto.AvatarChangeElementTypeReqOuterClass.AvatarChangeElementTypeReq;
|
||||||
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.PacketAvatarChangeElementTypeRsp;
|
import emu.grasscutter.server.packet.send.PacketAvatarChangeElementTypeRsp;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
/**
|
/** Changes the currently active avatars Element if possible */
|
||||||
* Changes the currently active avatars Element if possible
|
@Opcodes(PacketOpcodes.AvatarChangeElementTypeReq)
|
||||||
*/
|
public class HandlerAvatarChangeElementTypeReq extends PacketHandler {
|
||||||
@Opcodes(PacketOpcodes.AvatarChangeElementTypeReq)
|
|
||||||
public class HandlerAvatarChangeElementTypeReq extends PacketHandler {
|
@Override
|
||||||
|
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||||
@Override
|
var req = AvatarChangeElementTypeReq.parseFrom(payload);
|
||||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
var area = GameData.getWorldAreaDataMap().get(req.getAreaId());
|
||||||
var req = AvatarChangeElementTypeReq.parseFrom(payload);
|
|
||||||
var area = GameData.getWorldAreaDataMap().get(req.getAreaId());
|
if (area == null
|
||||||
|
|| area.getElementType() == null
|
||||||
if (area == null || area.getElementType() == null || area.getElementType().getDepotIndex() <= 0) {
|
|| area.getElementType().getDepotIndex() <= 0) {
|
||||||
session.send(new PacketAvatarChangeElementTypeRsp(Retcode.RET_SVR_ERROR_VALUE));
|
session.send(new PacketAvatarChangeElementTypeRsp(Retcode.RET_SVR_ERROR_VALUE));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
val avatar = session.getPlayer().getTeamManager().getCurrentAvatarEntity().getAvatar();
|
val avatar = session.getPlayer().getTeamManager().getCurrentAvatarEntity().getAvatar();
|
||||||
if (!avatar.changeElement(area.getElementType())) {
|
if (!avatar.changeElement(area.getElementType())) {
|
||||||
session.send(new PacketAvatarChangeElementTypeRsp(Retcode.RET_SVR_ERROR_VALUE));
|
session.send(new PacketAvatarChangeElementTypeRsp(Retcode.RET_SVR_ERROR_VALUE));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
session.send(new PacketAvatarChangeElementTypeRsp());
|
session.send(new PacketAvatarChangeElementTypeRsp());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
//package emu.grasscutter.server.packet.recv;
|
// package emu.grasscutter.server.packet.recv;
|
||||||
//
|
//
|
||||||
//import emu.grasscutter.net.packet.Opcodes;
|
// import emu.grasscutter.net.packet.Opcodes;
|
||||||
//import emu.grasscutter.net.packet.PacketHandler;
|
// import emu.grasscutter.net.packet.PacketHandler;
|
||||||
//import emu.grasscutter.net.packet.PacketOpcodes;
|
// import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
//import emu.grasscutter.net.proto.Unk2700BEDLIGJANCJClientReq;
|
// import emu.grasscutter.net.proto.Unk2700BEDLIGJANCJClientReq;
|
||||||
//import emu.grasscutter.server.game.GameSession;
|
// import emu.grasscutter.server.game.GameSession;
|
||||||
//import emu.grasscutter.server.packet.send.PacketChangeHomeBgmNotify;
|
// import emu.grasscutter.server.packet.send.PacketChangeHomeBgmNotify;
|
||||||
//import emu.grasscutter.server.packet.send.PacketChangeHomeBgmRsp;
|
// import emu.grasscutter.server.packet.send.PacketChangeHomeBgmRsp;
|
||||||
//
|
//
|
||||||
//@Opcodes(PacketOpcodes.Unk2700_BEDLIGJANCJ_ClientReq)
|
// @Opcodes(PacketOpcodes.Unk2700_BEDLIGJANCJ_ClientReq)
|
||||||
//public class HandlerChangeHomeBgmReq extends PacketHandler {
|
// public class HandlerChangeHomeBgmReq 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 {
|
||||||
// var req = Unk2700BEDLIGJANCJClientReq.Unk2700_BEDLIGJANCJ_ClientReq.parseFrom(payload);
|
// var req = Unk2700BEDLIGJANCJClientReq.Unk2700_BEDLIGJANCJ_ClientReq.parseFrom(payload);
|
||||||
//
|
//
|
||||||
// int homeBgmId = req.getUnk2700BJHAMKKECEI();
|
// int homeBgmId = req.getUnk2700BJHAMKKECEI();
|
||||||
// var home = session.getPlayer().getHome();
|
// var home = session.getPlayer().getHome();
|
||||||
//
|
//
|
||||||
// home.getHomeSceneItem(session.getPlayer().getSceneId()).setHomeBgmId(homeBgmId);
|
// home.getHomeSceneItem(session.getPlayer().getSceneId()).setHomeBgmId(homeBgmId);
|
||||||
// home.save();
|
// home.save();
|
||||||
//
|
//
|
||||||
// session.send(new PacketChangeHomeBgmNotify(homeBgmId));
|
// session.send(new PacketChangeHomeBgmNotify(homeBgmId));
|
||||||
// session.send(new PacketChangeHomeBgmRsp());
|
// session.send(new PacketChangeHomeBgmRsp());
|
||||||
// }
|
// }
|
||||||
//}
|
// }
|
||||||
|
@ -1,191 +1,191 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.game.entity.GameEntity;
|
import emu.grasscutter.game.entity.GameEntity;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
||||||
import emu.grasscutter.net.proto.CombatInvocationsNotifyOuterClass.CombatInvocationsNotify;
|
import emu.grasscutter.net.proto.CombatInvocationsNotifyOuterClass.CombatInvocationsNotify;
|
||||||
import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry;
|
import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry;
|
||||||
import emu.grasscutter.net.proto.EntityMoveInfoOuterClass.EntityMoveInfo;
|
import emu.grasscutter.net.proto.EntityMoveInfoOuterClass.EntityMoveInfo;
|
||||||
import emu.grasscutter.net.proto.EvtAnimatorParameterInfoOuterClass.EvtAnimatorParameterInfo;
|
import emu.grasscutter.net.proto.EvtAnimatorParameterInfoOuterClass.EvtAnimatorParameterInfo;
|
||||||
import emu.grasscutter.net.proto.EvtBeingHitInfoOuterClass.EvtBeingHitInfo;
|
import emu.grasscutter.net.proto.EvtBeingHitInfoOuterClass.EvtBeingHitInfo;
|
||||||
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
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.PlayerDieTypeOuterClass;
|
import emu.grasscutter.net.proto.PlayerDieTypeOuterClass;
|
||||||
import emu.grasscutter.server.event.entity.EntityMoveEvent;
|
import emu.grasscutter.server.event.entity.EntityMoveEvent;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.CombatInvocationsNotify)
|
@Opcodes(PacketOpcodes.CombatInvocationsNotify)
|
||||||
public class HandlerCombatInvocationsNotify extends PacketHandler {
|
public class HandlerCombatInvocationsNotify extends PacketHandler {
|
||||||
|
|
||||||
private float cachedLandingSpeed = 0;
|
private float cachedLandingSpeed = 0;
|
||||||
private long cachedLandingTimeMillisecond = 0;
|
private long cachedLandingTimeMillisecond = 0;
|
||||||
private boolean monitorLandingEvent = false;
|
private boolean monitorLandingEvent = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||||
CombatInvocationsNotify notif = CombatInvocationsNotify.parseFrom(payload);
|
CombatInvocationsNotify notif = CombatInvocationsNotify.parseFrom(payload);
|
||||||
for (CombatInvokeEntry entry : notif.getInvokeListList()) {
|
for (CombatInvokeEntry entry : notif.getInvokeListList()) {
|
||||||
// Handle combat invoke
|
// Handle combat invoke
|
||||||
switch (entry.getArgumentType()) {
|
switch (entry.getArgumentType()) {
|
||||||
case COMBAT_TYPE_ARGUMENT_EVT_BEING_HIT -> {
|
case COMBAT_TYPE_ARGUMENT_EVT_BEING_HIT -> {
|
||||||
EvtBeingHitInfo hitInfo = EvtBeingHitInfo.parseFrom(entry.getCombatData());
|
EvtBeingHitInfo hitInfo = EvtBeingHitInfo.parseFrom(entry.getCombatData());
|
||||||
AttackResult attackResult = hitInfo.getAttackResult();
|
AttackResult attackResult = hitInfo.getAttackResult();
|
||||||
Player player = session.getPlayer();
|
Player player = session.getPlayer();
|
||||||
|
|
||||||
// Check if the player is invulnerable.
|
// Check if the player is invulnerable.
|
||||||
if (attackResult.getAttackerId()
|
if (attackResult.getAttackerId()
|
||||||
!= player.getTeamManager().getCurrentAvatarEntity().getId()
|
!= player.getTeamManager().getCurrentAvatarEntity().getId()
|
||||||
&& player.getAbilityManager().isAbilityInvulnerable()) break;
|
&& player.getAbilityManager().isAbilityInvulnerable()) break;
|
||||||
|
|
||||||
// Handle damage
|
// Handle damage
|
||||||
player.getAttackResults().add(attackResult);
|
player.getAttackResults().add(attackResult);
|
||||||
player.getEnergyManager().handleAttackHit(hitInfo);
|
player.getEnergyManager().handleAttackHit(hitInfo);
|
||||||
}
|
}
|
||||||
case COMBAT_TYPE_ARGUMENT_ENTITY_MOVE -> {
|
case COMBAT_TYPE_ARGUMENT_ENTITY_MOVE -> {
|
||||||
// Handle movement
|
// Handle movement
|
||||||
EntityMoveInfo moveInfo = EntityMoveInfo.parseFrom(entry.getCombatData());
|
EntityMoveInfo moveInfo = EntityMoveInfo.parseFrom(entry.getCombatData());
|
||||||
GameEntity entity = session.getPlayer().getScene().getEntityById(moveInfo.getEntityId());
|
GameEntity entity = session.getPlayer().getScene().getEntityById(moveInfo.getEntityId());
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
// Move player
|
// Move player
|
||||||
MotionInfo motionInfo = moveInfo.getMotionInfo();
|
MotionInfo motionInfo = moveInfo.getMotionInfo();
|
||||||
MotionState motionState = motionInfo.getState();
|
MotionState motionState = motionInfo.getState();
|
||||||
|
|
||||||
// Call entity move event.
|
// Call entity move event.
|
||||||
EntityMoveEvent event =
|
EntityMoveEvent event =
|
||||||
new EntityMoveEvent(
|
new EntityMoveEvent(
|
||||||
entity,
|
entity,
|
||||||
new Position(motionInfo.getPos()),
|
new Position(motionInfo.getPos()),
|
||||||
new Position(motionInfo.getRot()),
|
new Position(motionInfo.getRot()),
|
||||||
motionState);
|
motionState);
|
||||||
event.call();
|
event.call();
|
||||||
|
|
||||||
entity.move(event.getPosition(), event.getRotation());
|
entity.move(event.getPosition(), event.getRotation());
|
||||||
entity.setLastMoveSceneTimeMs(moveInfo.getSceneTime());
|
entity.setLastMoveSceneTimeMs(moveInfo.getSceneTime());
|
||||||
entity.setLastMoveReliableSeq(moveInfo.getReliableSeq());
|
entity.setLastMoveReliableSeq(moveInfo.getReliableSeq());
|
||||||
entity.setMotionState(motionState);
|
entity.setMotionState(motionState);
|
||||||
|
|
||||||
session
|
session
|
||||||
.getPlayer()
|
.getPlayer()
|
||||||
.getStaminaManager()
|
.getStaminaManager()
|
||||||
.handleCombatInvocationsNotify(session, moveInfo, entity);
|
.handleCombatInvocationsNotify(session, moveInfo, entity);
|
||||||
|
|
||||||
// TODO: handle MOTION_FIGHT landing which has a different damage factor
|
// TODO: handle MOTION_FIGHT landing which has a different damage factor
|
||||||
// Also, for plunge attacks, LAND_SPEED is always -30 and is not useful.
|
// Also, for plunge attacks, LAND_SPEED is always -30 and is not useful.
|
||||||
// May need the height when starting plunge attack.
|
// May need the height when starting plunge attack.
|
||||||
|
|
||||||
// MOTION_LAND_SPEED and MOTION_FALL_ON_GROUND arrive in different packets.
|
// MOTION_LAND_SPEED and MOTION_FALL_ON_GROUND arrive in different packets.
|
||||||
// Cache land speed for later use.
|
// Cache land speed for later use.
|
||||||
if (motionState == MotionState.MOTION_STATE_LAND_SPEED) {
|
if (motionState == MotionState.MOTION_STATE_LAND_SPEED) {
|
||||||
cachedLandingSpeed = motionInfo.getSpeed().getY();
|
cachedLandingSpeed = motionInfo.getSpeed().getY();
|
||||||
cachedLandingTimeMillisecond = System.currentTimeMillis();
|
cachedLandingTimeMillisecond = System.currentTimeMillis();
|
||||||
monitorLandingEvent = true;
|
monitorLandingEvent = true;
|
||||||
}
|
}
|
||||||
if (monitorLandingEvent) {
|
if (monitorLandingEvent) {
|
||||||
if (motionState == MotionState.MOTION_STATE_FALL_ON_GROUND) {
|
if (motionState == MotionState.MOTION_STATE_FALL_ON_GROUND) {
|
||||||
monitorLandingEvent = false;
|
monitorLandingEvent = false;
|
||||||
handleFallOnGround(session, entity, motionState);
|
handleFallOnGround(session, entity, motionState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MOTION_STATE_NOTIFY = Dont send to other players
|
// MOTION_STATE_NOTIFY = Dont send to other players
|
||||||
if (motionState == MotionState.MOTION_STATE_NOTIFY) {
|
if (motionState == MotionState.MOTION_STATE_NOTIFY) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case COMBAT_TYPE_ARGUMENT_ANIMATOR_PARAMETER_CHANGED -> {
|
case COMBAT_TYPE_ARGUMENT_ANIMATOR_PARAMETER_CHANGED -> {
|
||||||
EvtAnimatorParameterInfo paramInfo =
|
EvtAnimatorParameterInfo paramInfo =
|
||||||
EvtAnimatorParameterInfo.parseFrom(entry.getCombatData());
|
EvtAnimatorParameterInfo.parseFrom(entry.getCombatData());
|
||||||
if (paramInfo.getIsServerCache()) {
|
if (paramInfo.getIsServerCache()) {
|
||||||
paramInfo = paramInfo.toBuilder().setIsServerCache(false).build();
|
paramInfo = paramInfo.toBuilder().setIsServerCache(false).build();
|
||||||
entry = entry.toBuilder().setCombatData(paramInfo.toByteString()).build();
|
entry = entry.toBuilder().setCombatData(paramInfo.toByteString()).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default -> {}
|
default -> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
session.getPlayer().getCombatInvokeHandler().addEntry(entry.getForwardType(), entry);
|
session.getPlayer().getCombatInvokeHandler().addEntry(entry.getForwardType(), entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleFallOnGround(GameSession session, GameEntity entity, MotionState motionState) {
|
private void handleFallOnGround(GameSession session, GameEntity entity, MotionState motionState) {
|
||||||
if (session.getPlayer().isInGodMode()) {
|
if (session.getPlayer().isInGodMode()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// People have reported that after plunge attack (client sends a FIGHT instead of
|
// People have reported that after plunge attack (client sends a FIGHT instead of
|
||||||
// FALL_ON_GROUND) they will die
|
// FALL_ON_GROUND) they will die
|
||||||
// if they talk to an NPC (this is when the client sends a FALL_ON_GROUND) without jumping
|
// if they talk to an NPC (this is when the client sends a FALL_ON_GROUND) without jumping
|
||||||
// again.
|
// again.
|
||||||
// A dirty patch: if not received immediately after MOTION_LAND_SPEED, discard this packet.
|
// A dirty patch: if not received immediately after MOTION_LAND_SPEED, discard this packet.
|
||||||
// 200ms seems to be a reasonable delay.
|
// 200ms seems to be a reasonable delay.
|
||||||
int maxDelay = 200;
|
int maxDelay = 200;
|
||||||
long actualDelay = System.currentTimeMillis() - cachedLandingTimeMillisecond;
|
long actualDelay = System.currentTimeMillis() - cachedLandingTimeMillisecond;
|
||||||
Grasscutter.getLogger()
|
Grasscutter.getLogger()
|
||||||
.trace(
|
.trace(
|
||||||
"MOTION_FALL_ON_GROUND received after "
|
"MOTION_FALL_ON_GROUND received after "
|
||||||
+ actualDelay
|
+ actualDelay
|
||||||
+ "/"
|
+ "/"
|
||||||
+ maxDelay
|
+ maxDelay
|
||||||
+ "ms."
|
+ "ms."
|
||||||
+ (actualDelay > maxDelay ? " Discard" : ""));
|
+ (actualDelay > maxDelay ? " Discard" : ""));
|
||||||
if (actualDelay > maxDelay) {
|
if (actualDelay > maxDelay) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float currentHP = entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
float currentHP = entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||||
float maxHP = entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
float maxHP = entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||||
float damageFactor = 0;
|
float damageFactor = 0;
|
||||||
if (cachedLandingSpeed < -23.5) {
|
if (cachedLandingSpeed < -23.5) {
|
||||||
damageFactor = 0.33f;
|
damageFactor = 0.33f;
|
||||||
}
|
}
|
||||||
if (cachedLandingSpeed < -25) {
|
if (cachedLandingSpeed < -25) {
|
||||||
damageFactor = 0.5f;
|
damageFactor = 0.5f;
|
||||||
}
|
}
|
||||||
if (cachedLandingSpeed < -26.5) {
|
if (cachedLandingSpeed < -26.5) {
|
||||||
damageFactor = 0.66f;
|
damageFactor = 0.66f;
|
||||||
}
|
}
|
||||||
if (cachedLandingSpeed < -28) {
|
if (cachedLandingSpeed < -28) {
|
||||||
damageFactor = 1f;
|
damageFactor = 1f;
|
||||||
}
|
}
|
||||||
float damage = maxHP * damageFactor;
|
float damage = maxHP * damageFactor;
|
||||||
float newHP = currentHP - damage;
|
float newHP = currentHP - damage;
|
||||||
if (newHP < 0) {
|
if (newHP < 0) {
|
||||||
newHP = 0;
|
newHP = 0;
|
||||||
}
|
}
|
||||||
if (damageFactor > 0) {
|
if (damageFactor > 0) {
|
||||||
Grasscutter.getLogger()
|
Grasscutter.getLogger()
|
||||||
.debug(
|
.debug(
|
||||||
currentHP
|
currentHP
|
||||||
+ "/"
|
+ "/"
|
||||||
+ maxHP
|
+ maxHP
|
||||||
+ "\tLandingSpeed: "
|
+ "\tLandingSpeed: "
|
||||||
+ cachedLandingSpeed
|
+ cachedLandingSpeed
|
||||||
+ "\tDamageFactor: "
|
+ "\tDamageFactor: "
|
||||||
+ damageFactor
|
+ damageFactor
|
||||||
+ "\tDamage: "
|
+ "\tDamage: "
|
||||||
+ damage
|
+ damage
|
||||||
+ "\tNewHP: "
|
+ "\tNewHP: "
|
||||||
+ newHP);
|
+ newHP);
|
||||||
} else {
|
} else {
|
||||||
Grasscutter.getLogger().trace(currentHP + "/" + maxHP + "\tLandingSpeed: 0\tNo damage");
|
Grasscutter.getLogger().trace(currentHP + "/" + maxHP + "\tLandingSpeed: 0\tNo damage");
|
||||||
}
|
}
|
||||||
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, newHP);
|
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, newHP);
|
||||||
entity
|
entity
|
||||||
.getWorld()
|
.getWorld()
|
||||||
.broadcastPacket(
|
.broadcastPacket(
|
||||||
new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
|
new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
|
||||||
if (newHP == 0) {
|
if (newHP == 0) {
|
||||||
session
|
session
|
||||||
.getPlayer()
|
.getPlayer()
|
||||||
.getStaminaManager()
|
.getStaminaManager()
|
||||||
.killAvatar(session, entity, PlayerDieTypeOuterClass.PlayerDieType.PLAYER_DIE_TYPE_FALL);
|
.killAvatar(session, entity, PlayerDieTypeOuterClass.PlayerDieType.PLAYER_DIE_TYPE_FALL);
|
||||||
}
|
}
|
||||||
cachedLandingSpeed = 0;
|
cachedLandingSpeed = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.game.quest.enums.QuestContent;
|
import emu.grasscutter.game.quest.enums.QuestContent;
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.EvtDoSkillSuccNotifyOuterClass.EvtDoSkillSuccNotify;
|
import emu.grasscutter.net.proto.EvtDoSkillSuccNotifyOuterClass.EvtDoSkillSuccNotify;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.EvtDoSkillSuccNotify)
|
@Opcodes(PacketOpcodes.EvtDoSkillSuccNotify)
|
||||||
public class HandlerEvtDoSkillSuccNotify extends PacketHandler {
|
public class HandlerEvtDoSkillSuccNotify 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 {
|
||||||
EvtDoSkillSuccNotify notify = EvtDoSkillSuccNotify.parseFrom(payload);
|
EvtDoSkillSuccNotify notify = EvtDoSkillSuccNotify.parseFrom(payload);
|
||||||
|
|
||||||
var player = session.getPlayer();
|
var player = session.getPlayer();
|
||||||
int skillId = notify.getSkillId();
|
int skillId = notify.getSkillId();
|
||||||
int casterId = notify.getCasterId();
|
int casterId = notify.getCasterId();
|
||||||
|
|
||||||
// Call skill perform in the player's ability manager.
|
// Call skill perform in the player's ability manager.
|
||||||
player.getAbilityManager().onSkillStart(session.getPlayer(), skillId, casterId);
|
player.getAbilityManager().onSkillStart(session.getPlayer(), skillId, casterId);
|
||||||
|
|
||||||
// Handle skill notify in other managers.
|
// Handle skill notify in other managers.
|
||||||
player.getStaminaManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
|
player.getStaminaManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
|
||||||
player.getEnergyManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
|
player.getEnergyManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
|
||||||
player.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_SKILL, skillId, 0);
|
player.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_SKILL, skillId, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
import emu.grasscutter.game.entity.GameEntity;
|
import emu.grasscutter.game.entity.GameEntity;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.ExecuteGadgetLuaReqOuterClass.ExecuteGadgetLuaReq;
|
import emu.grasscutter.net.proto.ExecuteGadgetLuaReqOuterClass.ExecuteGadgetLuaReq;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.PacketExecuteGadgetLuaRsp;
|
import emu.grasscutter.server.packet.send.PacketExecuteGadgetLuaRsp;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.ExecuteGadgetLuaReq)
|
@Opcodes(PacketOpcodes.ExecuteGadgetLuaReq)
|
||||||
public class HandlerExecuteGadgetLuaReq extends PacketHandler {
|
public class HandlerExecuteGadgetLuaReq 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 {
|
||||||
ExecuteGadgetLuaReq req = ExecuteGadgetLuaReq.parseFrom(payload);
|
ExecuteGadgetLuaReq req = ExecuteGadgetLuaReq.parseFrom(payload);
|
||||||
|
|
||||||
Player player = session.getPlayer();
|
Player player = session.getPlayer();
|
||||||
GameEntity entity = player.getScene().getEntities().get(req.getSourceEntityId());
|
GameEntity entity = player.getScene().getEntities().get(req.getSourceEntityId());
|
||||||
|
|
||||||
int result = 1;
|
int result = 1;
|
||||||
if (entity instanceof EntityGadget gadget)
|
if (entity instanceof EntityGadget gadget)
|
||||||
result = gadget.onClientExecuteRequest(req.getParam1(), req.getParam2(), req.getParam3());
|
result = gadget.onClientExecuteRequest(req.getParam1(), req.getParam2(), req.getParam3());
|
||||||
|
|
||||||
player.sendPacket(new PacketExecuteGadgetLuaRsp(result));
|
player.sendPacket(new PacketExecuteGadgetLuaRsp(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.game.quest.enums.QuestContent;
|
import emu.grasscutter.game.quest.enums.QuestContent;
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.GadgetInteractReq)
|
@Opcodes(PacketOpcodes.GadgetInteractReq)
|
||||||
public class HandlerGadgetInteractReq extends PacketHandler {
|
public class HandlerGadgetInteractReq 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 {
|
||||||
GadgetInteractReq req = GadgetInteractReq.parseFrom(payload);
|
GadgetInteractReq req = GadgetInteractReq.parseFrom(payload);
|
||||||
|
|
||||||
session
|
session
|
||||||
.getPlayer()
|
.getPlayer()
|
||||||
.getQuestManager()
|
.getQuestManager()
|
||||||
.queueEvent(QuestContent.QUEST_CONTENT_INTERACT_GADGET, req.getGadgetId());
|
.queueEvent(QuestContent.QUEST_CONTENT_INTERACT_GADGET, req.getGadgetId());
|
||||||
session.getPlayer().interactWith(req.getGadgetEntityId(), req);
|
session.getPlayer().interactWith(req.getGadgetEntityId(), req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.GetAllMailNotifyOuterClass.GetAllMailNotify;
|
import emu.grasscutter.net.proto.GetAllMailNotifyOuterClass.GetAllMailNotify;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.PacketGetAllMailResultNotify;
|
import emu.grasscutter.server.packet.send.PacketGetAllMailResultNotify;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.GetAllMailNotify)
|
@Opcodes(PacketOpcodes.GetAllMailNotify)
|
||||||
public final class HandlerGetAllMailNotify extends PacketHandler {
|
public final class HandlerGetAllMailNotify 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 {
|
||||||
var req = GetAllMailNotify.parseFrom(payload);
|
var req = GetAllMailNotify.parseFrom(payload);
|
||||||
session.send(new PacketGetAllMailResultNotify(session.getPlayer(), req.getIsCollected()));
|
session.send(new PacketGetAllMailResultNotify(session.getPlayer(), req.getIsCollected()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
//package emu.grasscutter.server.packet.recv;
|
// package emu.grasscutter.server.packet.recv;
|
||||||
//
|
//
|
||||||
//import emu.grasscutter.net.packet.Opcodes;
|
// import emu.grasscutter.net.packet.Opcodes;
|
||||||
//import emu.grasscutter.net.packet.PacketHandler;
|
// import emu.grasscutter.net.packet.PacketHandler;
|
||||||
//import emu.grasscutter.net.packet.PacketOpcodes;
|
// import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
//import emu.grasscutter.server.game.GameSession;
|
// import emu.grasscutter.server.game.GameSession;
|
||||||
//import emu.grasscutter.server.packet.send.PacketHomeUnknown2Rsp;
|
// import emu.grasscutter.server.packet.send.PacketHomeUnknown2Rsp;
|
||||||
//
|
//
|
||||||
//@Opcodes(PacketOpcodes.Unk2700_ACILPONNGGK_ClientReq)
|
// @Opcodes(PacketOpcodes.Unk2700_ACILPONNGGK_ClientReq)
|
||||||
//public class HandlerHomeUnknown2Req extends PacketHandler {
|
// public class HandlerHomeUnknown2Req 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 {
|
||||||
// /*
|
// /*
|
||||||
// * This packet is about the edit mode
|
// * This packet is about the edit mode
|
||||||
// */
|
// */
|
||||||
// session.send(new PacketHomeUnknown2Rsp());
|
// session.send(new PacketHomeUnknown2Rsp());
|
||||||
// }
|
// }
|
||||||
//}
|
// }
|
||||||
|
@ -1,66 +1,75 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.game.activity.musicgame.MusicGameActivityHandler;
|
import emu.grasscutter.game.activity.musicgame.MusicGameActivityHandler;
|
||||||
import emu.grasscutter.game.activity.musicgame.MusicGamePlayerData;
|
import emu.grasscutter.game.activity.musicgame.MusicGamePlayerData;
|
||||||
import emu.grasscutter.game.props.ActivityType;
|
import emu.grasscutter.game.props.ActivityType;
|
||||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.MusicGameSettleReqOuterClass.MusicGameSettleReq;
|
import emu.grasscutter.net.proto.MusicGameSettleReqOuterClass.MusicGameSettleReq;
|
||||||
import emu.grasscutter.net.proto.RetcodeOuterClass;
|
import emu.grasscutter.net.proto.RetcodeOuterClass;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.PacketActivityInfoNotify;
|
import emu.grasscutter.server.packet.send.PacketActivityInfoNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketMusicGameSettleRsp;
|
import emu.grasscutter.server.packet.send.PacketMusicGameSettleRsp;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.MusicGameSettleReq)
|
@Opcodes(PacketOpcodes.MusicGameSettleReq)
|
||||||
public class HandlerMusicGameSettleReq extends PacketHandler {
|
public class HandlerMusicGameSettleReq 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 {
|
||||||
val req = MusicGameSettleReq.parseFrom(payload);
|
val req = MusicGameSettleReq.parseFrom(payload);
|
||||||
|
|
||||||
val activityManager = session.getPlayer().getActivityManager();
|
val activityManager = session.getPlayer().getActivityManager();
|
||||||
|
|
||||||
val playerDataOpt = activityManager.getPlayerActivityDataByActivityType(ActivityType.NEW_ACTIVITY_MUSIC_GAME);
|
val playerDataOpt =
|
||||||
if (playerDataOpt.isEmpty()) {
|
activityManager.getPlayerActivityDataByActivityType(ActivityType.NEW_ACTIVITY_MUSIC_GAME);
|
||||||
session.send(new PacketMusicGameSettleRsp(RetcodeOuterClass.Retcode.RET_MUSIC_GAME_LEVEL_CONFIG_NOT_FOUND, req));
|
if (playerDataOpt.isEmpty()) {
|
||||||
return;
|
session.send(
|
||||||
}
|
new PacketMusicGameSettleRsp(
|
||||||
|
RetcodeOuterClass.Retcode.RET_MUSIC_GAME_LEVEL_CONFIG_NOT_FOUND, req));
|
||||||
val playerData = playerDataOpt.get();
|
return;
|
||||||
val handler = (MusicGameActivityHandler) playerData.getActivityHandler();
|
}
|
||||||
boolean isNewRecord = false;
|
|
||||||
|
val playerData = playerDataOpt.get();
|
||||||
// check if custom beatmap
|
val handler = (MusicGameActivityHandler) playerData.getActivityHandler();
|
||||||
if (req.getUgcGuid() == 0) {
|
boolean isNewRecord = false;
|
||||||
session.getPlayer().getActivityManager().triggerWatcher(
|
|
||||||
WatcherTriggerType.TRIGGER_FLEUR_FAIR_MUSIC_GAME_REACH_SCORE,
|
// check if custom beatmap
|
||||||
String.valueOf(req.getMusicBasicId()),
|
if (req.getUgcGuid() == 0) {
|
||||||
String.valueOf(req.getScore())
|
session
|
||||||
);
|
.getPlayer()
|
||||||
|
.getActivityManager()
|
||||||
isNewRecord = handler.setMusicGameRecord(playerData,
|
.triggerWatcher(
|
||||||
MusicGamePlayerData.MusicGameRecord.of()
|
WatcherTriggerType.TRIGGER_FLEUR_FAIR_MUSIC_GAME_REACH_SCORE,
|
||||||
.musicId(req.getMusicBasicId())
|
String.valueOf(req.getMusicBasicId()),
|
||||||
.maxCombo(req.getMaxCombo())
|
String.valueOf(req.getScore()));
|
||||||
.maxScore(req.getScore())
|
|
||||||
.build());
|
isNewRecord =
|
||||||
|
handler.setMusicGameRecord(
|
||||||
// update activity info
|
playerData,
|
||||||
session.send(new PacketActivityInfoNotify(handler.toProto(playerData, activityManager.getConditionExecutor())));
|
MusicGamePlayerData.MusicGameRecord.of()
|
||||||
} else {
|
.musicId(req.getMusicBasicId())
|
||||||
handler.setMusicGameCustomBeatmapRecord(playerData,
|
.maxCombo(req.getMaxCombo())
|
||||||
MusicGamePlayerData.CustomBeatmapRecord.of()
|
.maxScore(req.getScore())
|
||||||
.musicShareId(req.getUgcGuid())
|
.build());
|
||||||
.score(req.getMaxCombo())
|
|
||||||
.settle(req.getIsSaveScore())
|
// update activity info
|
||||||
.build());
|
session.send(
|
||||||
}
|
new PacketActivityInfoNotify(
|
||||||
|
handler.toProto(playerData, activityManager.getConditionExecutor())));
|
||||||
|
} else {
|
||||||
session.send(new PacketMusicGameSettleRsp(req.getMusicBasicId(), req.getUgcGuid(), isNewRecord));
|
handler.setMusicGameCustomBeatmapRecord(
|
||||||
}
|
playerData,
|
||||||
|
MusicGamePlayerData.CustomBeatmapRecord.of()
|
||||||
}
|
.musicShareId(req.getUgcGuid())
|
||||||
|
.score(req.getMaxCombo())
|
||||||
|
.settle(req.getIsSaveScore())
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
session.send(
|
||||||
|
new PacketMusicGameSettleRsp(req.getMusicBasicId(), req.getUgcGuid(), isNewRecord));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,67 +1,67 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.binout.MainQuestData;
|
import emu.grasscutter.data.binout.MainQuestData;
|
||||||
import emu.grasscutter.data.binout.MainQuestData.TalkData;
|
import emu.grasscutter.data.binout.MainQuestData.TalkData;
|
||||||
import emu.grasscutter.game.quest.enums.QuestContent;
|
import emu.grasscutter.game.quest.enums.QuestContent;
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.NpcTalkReqOuterClass.NpcTalkReq;
|
import emu.grasscutter.net.proto.NpcTalkReqOuterClass.NpcTalkReq;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.PacketNpcTalkRsp;
|
import emu.grasscutter.server.packet.send.PacketNpcTalkRsp;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.NpcTalkReq)
|
@Opcodes(PacketOpcodes.NpcTalkReq)
|
||||||
public class HandlerNpcTalkReq extends PacketHandler {
|
public class HandlerNpcTalkReq 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 {
|
||||||
NpcTalkReq req = NpcTalkReq.parseFrom(payload);
|
NpcTalkReq req = NpcTalkReq.parseFrom(payload);
|
||||||
|
|
||||||
// Check if mainQuest exists
|
// Check if mainQuest exists
|
||||||
// remove last 2 digits to get a mainQuestId
|
// remove last 2 digits to get a mainQuestId
|
||||||
int talkId = req.getTalkId();
|
int talkId = req.getTalkId();
|
||||||
int mainQuestId = talkId / 100;
|
int mainQuestId = talkId / 100;
|
||||||
MainQuestData mainQuestData = GameData.getMainQuestDataMap().get(mainQuestId);
|
MainQuestData mainQuestData = GameData.getMainQuestDataMap().get(mainQuestId);
|
||||||
|
|
||||||
if (mainQuestData != null) {
|
if (mainQuestData != null) {
|
||||||
// This talk is associated with a quest. Handle it.
|
// This talk is associated with a quest. Handle it.
|
||||||
// If the quest has no talk data defined on it, create one.
|
// If the quest has no talk data defined on it, create one.
|
||||||
TalkData talkForQuest = new TalkData(talkId, "");
|
TalkData talkForQuest = new TalkData(talkId, "");
|
||||||
if (mainQuestData.getTalks() != null) {
|
if (mainQuestData.getTalks() != null) {
|
||||||
var talks = mainQuestData.getTalks().stream().filter(p -> p.getId() == talkId).toList();
|
var talks = mainQuestData.getTalks().stream().filter(p -> p.getId() == talkId).toList();
|
||||||
|
|
||||||
if (talks.size() > 0) {
|
if (talks.size() > 0) {
|
||||||
talkForQuest = talks.get(0);
|
talkForQuest = talks.get(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to the list of done talks for this quest.
|
// Add to the list of done talks for this quest.
|
||||||
var mainQuest = session.getPlayer().getQuestManager().getMainQuestById(mainQuestId);
|
var mainQuest = session.getPlayer().getQuestManager().getMainQuestById(mainQuestId);
|
||||||
if (mainQuest != null) {
|
if (mainQuest != null) {
|
||||||
session
|
session
|
||||||
.getPlayer()
|
.getPlayer()
|
||||||
.getQuestManager()
|
.getQuestManager()
|
||||||
.getMainQuestById(mainQuestId)
|
.getMainQuestById(mainQuestId)
|
||||||
.getTalks()
|
.getTalks()
|
||||||
.put(talkId, talkForQuest);
|
.put(talkId, talkForQuest);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fire quest triggers.
|
// Fire quest triggers.
|
||||||
session
|
session
|
||||||
.getPlayer()
|
.getPlayer()
|
||||||
.getQuestManager()
|
.getQuestManager()
|
||||||
.queueEvent(
|
.queueEvent(
|
||||||
QuestContent.QUEST_CONTENT_COMPLETE_ANY_TALK, String.valueOf(req.getTalkId()), 0, 0);
|
QuestContent.QUEST_CONTENT_COMPLETE_ANY_TALK, String.valueOf(req.getTalkId()), 0, 0);
|
||||||
session
|
session
|
||||||
.getPlayer()
|
.getPlayer()
|
||||||
.getQuestManager()
|
.getQuestManager()
|
||||||
.queueEvent(QuestContent.QUEST_CONTENT_COMPLETE_TALK, req.getTalkId(), 0);
|
.queueEvent(QuestContent.QUEST_CONTENT_COMPLETE_TALK, req.getTalkId(), 0);
|
||||||
session
|
session
|
||||||
.getPlayer()
|
.getPlayer()
|
||||||
.getQuestManager()
|
.getQuestManager()
|
||||||
.queueEvent(QuestContent.QUEST_CONTENT_FINISH_PLOT, req.getTalkId(), 0);
|
.queueEvent(QuestContent.QUEST_CONTENT_FINISH_PLOT, req.getTalkId(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
session.send(new PacketNpcTalkRsp(req.getNpcEntityId(), req.getTalkId(), req.getEntityId()));
|
session.send(new PacketNpcTalkRsp(req.getNpcEntityId(), req.getTalkId(), req.getEntityId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.game.props.SceneType;
|
import emu.grasscutter.game.props.SceneType;
|
||||||
import emu.grasscutter.game.quest.enums.QuestContent;
|
import emu.grasscutter.game.quest.enums.QuestContent;
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.PacketPostEnterSceneRsp;
|
import emu.grasscutter.server.packet.send.PacketPostEnterSceneRsp;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.PostEnterSceneReq)
|
@Opcodes(PacketOpcodes.PostEnterSceneReq)
|
||||||
public class HandlerPostEnterSceneReq extends PacketHandler {
|
public class HandlerPostEnterSceneReq 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 {
|
||||||
if (session.getPlayer().getScene().getSceneType() == SceneType.SCENE_ROOM) {
|
if (session.getPlayer().getScene().getSceneType() == SceneType.SCENE_ROOM) {
|
||||||
session
|
session
|
||||||
.getPlayer()
|
.getPlayer()
|
||||||
.getQuestManager()
|
.getQuestManager()
|
||||||
.queueEvent(QuestContent.QUEST_CONTENT_ENTER_ROOM, session.getPlayer().getSceneId(), 0);
|
.queueEvent(QuestContent.QUEST_CONTENT_ENTER_ROOM, session.getPlayer().getSceneId(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
session.send(new PacketPostEnterSceneRsp(session.getPlayer()));
|
session.send(new PacketPostEnterSceneRsp(session.getPlayer()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
//package emu.grasscutter.server.packet.recv;
|
// package emu.grasscutter.server.packet.recv;
|
||||||
//
|
//
|
||||||
//import emu.grasscutter.net.packet.Opcodes;
|
// import emu.grasscutter.net.packet.Opcodes;
|
||||||
//import emu.grasscutter.net.packet.PacketHandler;
|
// import emu.grasscutter.net.packet.PacketHandler;
|
||||||
//import emu.grasscutter.net.packet.PacketOpcodes;
|
// import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
//import emu.grasscutter.net.proto.RemoveCustomTeamReqOuterClass.RemoveCustomTeamReq;
|
// import emu.grasscutter.net.proto.RemoveCustomTeamReqOuterClass.RemoveCustomTeamReq;
|
||||||
//import emu.grasscutter.server.game.GameSession;
|
// import emu.grasscutter.server.game.GameSession;
|
||||||
//
|
//
|
||||||
//@Opcodes(PacketOpcodes.RemoveCustomTeamReq)
|
// @Opcodes(PacketOpcodes.RemoveCustomTeamReq)
|
||||||
//public class HandlerRemoveCustomTeamReq extends PacketHandler {
|
// public class HandlerRemoveCustomTeamReq 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 {
|
||||||
// RemoveCustomTeamReq req = RemoveCustomTeamReq.parseFrom(payload);
|
// RemoveCustomTeamReq req = RemoveCustomTeamReq.parseFrom(payload);
|
||||||
// session.getPlayer().getTeamManager().removeCustomTeam(req.getId());
|
// session.getPlayer().getTeamManager().removeCustomTeam(req.getId());
|
||||||
// }
|
// }
|
||||||
//}
|
// }
|
||||||
|
@ -1,97 +1,102 @@
|
|||||||
//package emu.grasscutter.server.packet.recv;
|
// package emu.grasscutter.server.packet.recv;
|
||||||
//
|
//
|
||||||
//import emu.grasscutter.database.DatabaseHelper;
|
// import emu.grasscutter.database.DatabaseHelper;
|
||||||
//import emu.grasscutter.game.activity.musicgame.MusicGameActivityHandler;
|
// import emu.grasscutter.game.activity.musicgame.MusicGameActivityHandler;
|
||||||
//import emu.grasscutter.game.activity.musicgame.MusicGameBeatmap;
|
// import emu.grasscutter.game.activity.musicgame.MusicGameBeatmap;
|
||||||
//import emu.grasscutter.game.activity.musicgame.MusicGamePlayerData;
|
// import emu.grasscutter.game.activity.musicgame.MusicGamePlayerData;
|
||||||
//import emu.grasscutter.game.props.ActivityType;
|
// import emu.grasscutter.game.props.ActivityType;
|
||||||
//import emu.grasscutter.net.packet.Opcodes;
|
// import emu.grasscutter.net.packet.Opcodes;
|
||||||
//import emu.grasscutter.net.packet.PacketHandler;
|
// import emu.grasscutter.net.packet.PacketHandler;
|
||||||
//import emu.grasscutter.net.packet.PacketOpcodes;
|
// import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
//import emu.grasscutter.net.proto.RetcodeOuterClass;
|
// import emu.grasscutter.net.proto.RetcodeOuterClass;
|
||||||
//import emu.grasscutter.net.proto.SaveUgcReqOuterClass;
|
// import emu.grasscutter.net.proto.SaveUgcReqOuterClass;
|
||||||
//import emu.grasscutter.net.proto.UgcTypeOuterClass;
|
// import emu.grasscutter.net.proto.UgcTypeOuterClass;
|
||||||
//import emu.grasscutter.server.game.GameSession;
|
// import emu.grasscutter.server.game.GameSession;
|
||||||
//import emu.grasscutter.server.packet.send.PacketActivityInfoNotify;
|
// import emu.grasscutter.server.packet.send.PacketActivityInfoNotify;
|
||||||
//import emu.grasscutter.server.packet.send.PacketMusicGameCreateBeatmapRsp;
|
// import emu.grasscutter.server.packet.send.PacketMusicGameCreateBeatmapRsp;
|
||||||
//import emu.grasscutter.utils.Utils;
|
// import emu.grasscutter.utils.Utils;
|
||||||
//import java.util.Objects;
|
// import java.util.Objects;
|
||||||
//import lombok.val;
|
// import lombok.val;
|
||||||
//
|
//
|
||||||
//@Opcodes(PacketOpcodes.SaveUgcReq)
|
// @Opcodes(PacketOpcodes.SaveUgcReq)
|
||||||
//public class HandlerSaveUgcReq extends PacketHandler {
|
// public class HandlerSaveUgcReq 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 {
|
||||||
// val req = SaveUgcReqOuterClass.SaveUgcReq.parseFrom(payload);
|
// val req = SaveUgcReqOuterClass.SaveUgcReq.parseFrom(payload);
|
||||||
//
|
//
|
||||||
// // We only support music game user generated content
|
// // We only support music game user generated content
|
||||||
// if (req.getUgcType() != UgcTypeOuterClass.UgcType.UGC_TYPE_MUSIC_GAME) {
|
// if (req.getUgcType() != UgcTypeOuterClass.UgcType.UGC_TYPE_MUSIC_GAME) {
|
||||||
// session.send(
|
// session.send(
|
||||||
// new PacketMusicGameCreateBeatmapRsp(
|
// new PacketMusicGameCreateBeatmapRsp(
|
||||||
// RetcodeOuterClass.Retcode.RET_UGC_DISABLED, req.getUgcType()));
|
// RetcodeOuterClass.Retcode.RET_UGC_DISABLED, req.getUgcType()));
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
// val briefInfo = req.getMusicBriefInfo();
|
// val briefInfo = req.getMusicBriefInfo();
|
||||||
//
|
//
|
||||||
// val musicGameBeatmap =
|
// val musicGameBeatmap =
|
||||||
// MusicGameBeatmap.of()
|
// MusicGameBeatmap.of()
|
||||||
// .musicId(briefInfo.getMusicId())
|
// .musicId(briefInfo.getMusicId())
|
||||||
// .musicNoteCount(briefInfo.getNoteCount())
|
// .musicNoteCount(briefInfo.getNoteCount())
|
||||||
// .savePosition(briefInfo.getSaveIdx())
|
// .savePosition(briefInfo.getSaveIdx())
|
||||||
// .savePageType(briefInfo.getSavePageType())
|
// .savePageType(briefInfo.getSavePageType())
|
||||||
// .version(briefInfo.getVersion())
|
// .version(briefInfo.getVersion())
|
||||||
// .afterNoteList(briefInfo.getAfterNoteListList())
|
// .afterNoteList(briefInfo.getAfterNoteListList())
|
||||||
// .beforeNoteList(briefInfo.getBeforeNoteListList())
|
// .beforeNoteList(briefInfo.getBeforeNoteListList())
|
||||||
// .timeLineEditTime(briefInfo.getTimeLineEditTime())
|
// .timeLineEditTime(briefInfo.getTimeLineEditTime())
|
||||||
// .publishTime(briefInfo.getPublishTime())
|
// .publishTime(briefInfo.getPublishTime())
|
||||||
// .realTimeEditTime(briefInfo.getRealTimeEditTime())
|
// .realTimeEditTime(briefInfo.getRealTimeEditTime())
|
||||||
// .maxScore(briefInfo.getMaxScore())
|
// .maxScore(briefInfo.getMaxScore())
|
||||||
// .authorUid(session.getPlayer().getUid())
|
// .authorUid(session.getPlayer().getUid())
|
||||||
// .beatmap(MusicGameBeatmap.parse(req.getMusicRecord().getMusicTrackListList()))
|
//
|
||||||
// .createTime(Utils.getCurrentSeconds())
|
// .beatmap(MusicGameBeatmap.parse(req.getMusicRecord().getMusicTrackListList()))
|
||||||
// .build();
|
// .createTime(Utils.getCurrentSeconds())
|
||||||
//
|
// .build();
|
||||||
// musicGameBeatmap.save();
|
//
|
||||||
//
|
// musicGameBeatmap.save();
|
||||||
// val playerData =
|
//
|
||||||
// session
|
// val playerData =
|
||||||
// .getPlayer()
|
// session
|
||||||
// .getActivityManager()
|
// .getPlayer()
|
||||||
// .getPlayerActivityDataByActivityType(ActivityType.NEW_ACTIVITY_MUSIC_GAME);
|
// .getActivityManager()
|
||||||
// if (playerData.isEmpty()) {
|
//
|
||||||
// session.send(
|
// .getPlayerActivityDataByActivityType(ActivityType.NEW_ACTIVITY_MUSIC_GAME);
|
||||||
// new PacketMusicGameCreateBeatmapRsp(
|
// if (playerData.isEmpty()) {
|
||||||
// RetcodeOuterClass.Retcode.RET_UGC_DATA_NOT_FOUND, req.getUgcType()));
|
// session.send(
|
||||||
// return;
|
// new PacketMusicGameCreateBeatmapRsp(
|
||||||
// }
|
// RetcodeOuterClass.Retcode.RET_UGC_DATA_NOT_FOUND, req.getUgcType()));
|
||||||
//
|
// return;
|
||||||
// val handler = (MusicGameActivityHandler) playerData.get().getActivityHandler();
|
// }
|
||||||
// val musicGamePlayerData = handler.getMusicGamePlayerData(playerData.get());
|
//
|
||||||
//
|
// val handler = (MusicGameActivityHandler) playerData.get().getActivityHandler();
|
||||||
// val oldBeatmap =
|
// val musicGamePlayerData = handler.getMusicGamePlayerData(playerData.get());
|
||||||
// musicGamePlayerData.getPersonalCustomBeatmapRecord().values().stream()
|
//
|
||||||
// .map(MusicGamePlayerData.CustomBeatmapRecord::getMusicShareId)
|
// val oldBeatmap =
|
||||||
// .map(DatabaseHelper::getMusicGameBeatmap)
|
// musicGamePlayerData.getPersonalCustomBeatmapRecord().values().stream()
|
||||||
// .filter(Objects::nonNull)
|
// .map(MusicGamePlayerData.CustomBeatmapRecord::getMusicShareId)
|
||||||
// .filter(item -> item.getAuthorUid() == session.getPlayer().getUid())
|
// .map(DatabaseHelper::getMusicGameBeatmap)
|
||||||
// .filter(item -> item.getMusicId() == req.getMusicBriefInfo().getMusicId())
|
// .filter(Objects::nonNull)
|
||||||
// .filter(item -> item.getSavePosition() == req.getMusicBriefInfo().getSaveIdx())
|
// .filter(item -> item.getAuthorUid() == session.getPlayer().getUid())
|
||||||
// .findFirst();
|
// .filter(item -> item.getMusicId() == req.getMusicBriefInfo().getMusicId())
|
||||||
//
|
// .filter(item -> item.getSavePosition() ==
|
||||||
// // delete old beatmap for player
|
// req.getMusicBriefInfo().getSaveIdx())
|
||||||
// // the old beatmap is still in database so that others can still play.
|
// .findFirst();
|
||||||
// oldBeatmap.ifPresent(i -> handler.removePersonalBeatmap(playerData.get(), i));
|
//
|
||||||
//
|
// // delete old beatmap for player
|
||||||
// // link this beatmap to player's personal data
|
// // the old beatmap is still in database so that others can still play.
|
||||||
// handler.addPersonalBeatmap(playerData.get(), musicGameBeatmap);
|
// oldBeatmap.ifPresent(i -> handler.removePersonalBeatmap(playerData.get(), i));
|
||||||
//
|
//
|
||||||
// session.send(
|
// // link this beatmap to player's personal data
|
||||||
// new PacketActivityInfoNotify(
|
// handler.addPersonalBeatmap(playerData.get(), musicGameBeatmap);
|
||||||
// handler.toProto(
|
//
|
||||||
// playerData.get(),
|
// session.send(
|
||||||
// session.getPlayer().getActivityManager().getConditionExecutor())));
|
// new PacketActivityInfoNotify(
|
||||||
// session.send(
|
// handler.toProto(
|
||||||
// new PacketMusicGameCreateBeatmapRsp(musicGameBeatmap.getMusicShareId(), req.getUgcType()));
|
// playerData.get(),
|
||||||
// }
|
//
|
||||||
//}
|
// session.getPlayer().getActivityManager().getConditionExecutor())));
|
||||||
|
// session.send(
|
||||||
|
// new PacketMusicGameCreateBeatmapRsp(musicGameBeatmap.getMusicShareId(),
|
||||||
|
// req.getUgcType()));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
@ -1,39 +1,49 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
import emu.grasscutter.game.entity.GameEntity;
|
import emu.grasscutter.game.entity.GameEntity;
|
||||||
import emu.grasscutter.game.quest.enums.QuestContent;
|
import emu.grasscutter.game.quest.enums.QuestContent;
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.proto.SelectWorktopOptionReqOuterClass.SelectWorktopOptionReq;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.scripts.constants.EventType;
|
import emu.grasscutter.net.proto.SelectWorktopOptionReqOuterClass.SelectWorktopOptionReq;
|
||||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.PacketSelectWorktopOptionRsp;
|
import emu.grasscutter.server.packet.send.PacketSelectWorktopOptionRsp;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.SelectWorktopOptionReq)
|
@Opcodes(PacketOpcodes.SelectWorktopOptionReq)
|
||||||
public class HandlerSelectWorktopOptionReq extends PacketHandler {
|
public class HandlerSelectWorktopOptionReq 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 {
|
||||||
SelectWorktopOptionReq req = SelectWorktopOptionReq.parseFrom(payload);
|
SelectWorktopOptionReq req = SelectWorktopOptionReq.parseFrom(payload);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
GameEntity entity = session.getPlayer().getScene().getEntityById(req.getGadgetEntityId());
|
GameEntity entity = session.getPlayer().getScene().getEntityById(req.getGadgetEntityId());
|
||||||
|
|
||||||
if (!(entity instanceof EntityGadget)) {
|
if (!(entity instanceof EntityGadget)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.getPlayer().getScene().selectWorktopOptionWith(req);
|
session.getPlayer().getScene().selectWorktopOptionWith(req);
|
||||||
session.getPlayer().getScene().getScriptManager().callEvent(
|
session
|
||||||
new ScriptArgs(entity.getGroupId(), EventType.EVENT_SELECT_OPTION, entity.getConfigId(), req.getOptionId())
|
.getPlayer()
|
||||||
);
|
.getScene()
|
||||||
session.getPlayer().getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_WORKTOP_SELECT, entity.getConfigId(), req.getOptionId());
|
.getScriptManager()
|
||||||
} finally {
|
.callEvent(
|
||||||
// Always send packet
|
new ScriptArgs(
|
||||||
session.send(new PacketSelectWorktopOptionRsp(req.getGadgetEntityId(), req.getOptionId()));
|
entity.getGroupId(),
|
||||||
}
|
EventType.EVENT_SELECT_OPTION,
|
||||||
}
|
entity.getConfigId(),
|
||||||
|
req.getOptionId()));
|
||||||
}
|
session
|
||||||
|
.getPlayer()
|
||||||
|
.getQuestManager()
|
||||||
|
.queueEvent(
|
||||||
|
QuestContent.QUEST_CONTENT_WORKTOP_SELECT, entity.getConfigId(), req.getOptionId());
|
||||||
|
} finally {
|
||||||
|
// Always send packet
|
||||||
|
session.send(new PacketSelectWorktopOptionRsp(req.getGadgetEntityId(), req.getOptionId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.SkipPlayerGameTimeReqOuterClass;
|
import emu.grasscutter.net.proto.SkipPlayerGameTimeReqOuterClass;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.PacketPlayerGameTimeNotify;
|
import emu.grasscutter.server.packet.send.PacketPlayerGameTimeNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketSkipPlayerGameTimeRsp;
|
import emu.grasscutter.server.packet.send.PacketSkipPlayerGameTimeRsp;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.SkipPlayerGameTimeReq)
|
@Opcodes(PacketOpcodes.SkipPlayerGameTimeReq)
|
||||||
public class HandlerSkipPlayerGameTimeReq extends PacketHandler {
|
public class HandlerSkipPlayerGameTimeReq 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 {
|
||||||
var req = SkipPlayerGameTimeReqOuterClass.SkipPlayerGameTimeReq.parseFrom(payload);
|
var req = SkipPlayerGameTimeReqOuterClass.SkipPlayerGameTimeReq.parseFrom(payload);
|
||||||
var player = session.getPlayer();
|
var player = session.getPlayer();
|
||||||
player.updatePlayerGameTime(req.getGameTime());
|
player.updatePlayerGameTime(req.getGameTime());
|
||||||
player.getScene().broadcastPacket(new PacketPlayerGameTimeNotify(player));
|
player.getScene().broadcastPacket(new PacketPlayerGameTimeNotify(player));
|
||||||
player.sendPacket(new PacketSkipPlayerGameTimeRsp(req));
|
player.sendPacket(new PacketSkipPlayerGameTimeRsp(req));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,28 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
import emu.grasscutter.game.entity.gadget.platform.AbilityRoute;
|
import emu.grasscutter.game.entity.gadget.platform.AbilityRoute;
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.UpdateAbilityCreatedMovingPlatformNotifyOuterClass.UpdateAbilityCreatedMovingPlatformNotify;
|
import emu.grasscutter.net.proto.UpdateAbilityCreatedMovingPlatformNotifyOuterClass.UpdateAbilityCreatedMovingPlatformNotify;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.UpdateAbilityCreatedMovingPlatformNotify)
|
@Opcodes(PacketOpcodes.UpdateAbilityCreatedMovingPlatformNotify)
|
||||||
public class HandlerUpdateAbilityCreatedMovingPlatformNotify extends PacketHandler {
|
public class HandlerUpdateAbilityCreatedMovingPlatformNotify 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 {
|
||||||
var notify = UpdateAbilityCreatedMovingPlatformNotify.parseFrom(payload);
|
var notify = UpdateAbilityCreatedMovingPlatformNotify.parseFrom(payload);
|
||||||
var entity = session.getPlayer().getScene().getEntityById(notify.getEntityId());
|
var entity = session.getPlayer().getScene().getEntityById(notify.getEntityId());
|
||||||
|
|
||||||
if (!(entity instanceof EntityGadget entityGadget) || !(entityGadget.getRouteConfig() instanceof AbilityRoute)) {
|
if (!(entity instanceof EntityGadget entityGadget)
|
||||||
return;
|
|| !(entityGadget.getRouteConfig() instanceof AbilityRoute)) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
switch (notify.getOpType()) {
|
|
||||||
case OP_TYPE_ACTIVATE -> entityGadget.startPlatform();
|
switch (notify.getOpType()) {
|
||||||
case OP_TYPE_DEACTIVATE -> entityGadget.stopPlatform();
|
case OP_TYPE_ACTIVATE -> entityGadget.startPlatform();
|
||||||
}
|
case OP_TYPE_DEACTIVATE -> entityGadget.stopPlatform();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
//package emu.grasscutter.server.packet.send;
|
// package emu.grasscutter.server.packet.send;
|
||||||
//
|
//
|
||||||
//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.AddCustomTeamRspOuterClass.AddCustomTeamRsp;
|
// import emu.grasscutter.net.proto.AddCustomTeamRspOuterClass.AddCustomTeamRsp;
|
||||||
//import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
// import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
||||||
//
|
//
|
||||||
//public class PacketAddCustomTeamRsp extends BasePacket {
|
// public class PacketAddCustomTeamRsp extends BasePacket {
|
||||||
// public PacketAddCustomTeamRsp(Retcode retcode) {
|
// public PacketAddCustomTeamRsp(Retcode retcode) {
|
||||||
// super(PacketOpcodes.AddCustomTeamRsp);
|
// super(PacketOpcodes.AddCustomTeamRsp);
|
||||||
//
|
//
|
||||||
// AddCustomTeamRsp proto = AddCustomTeamRsp.newBuilder().setRetcode(retcode.getNumber()).build();
|
// AddCustomTeamRsp proto =
|
||||||
//
|
// AddCustomTeamRsp.newBuilder().setRetcode(retcode.getNumber()).build();
|
||||||
// this.setData(proto);
|
//
|
||||||
// }
|
// this.setData(proto);
|
||||||
//
|
// }
|
||||||
// public PacketAddCustomTeamRsp() {
|
//
|
||||||
// this(Retcode.RET_SUCC);
|
// public PacketAddCustomTeamRsp() {
|
||||||
// }
|
// this(Retcode.RET_SUCC);
|
||||||
//}
|
// }
|
||||||
|
// }
|
||||||
|
@ -1,61 +1,61 @@
|
|||||||
//package emu.grasscutter.server.packet.send;
|
// package emu.grasscutter.server.packet.send;
|
||||||
//
|
//
|
||||||
//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.BeginCameraSceneLookNotifyOuterClass.BeginCameraSceneLookNotify;
|
// import emu.grasscutter.net.proto.BeginCameraSceneLookNotifyOuterClass.BeginCameraSceneLookNotify;
|
||||||
//import emu.grasscutter.utils.Position;
|
// import emu.grasscutter.utils.Position;
|
||||||
//import java.util.ArrayList;
|
// import java.util.ArrayList;
|
||||||
//import java.util.Collection;
|
// import java.util.Collection;
|
||||||
//import lombok.Data;
|
// import lombok.Data;
|
||||||
//import lombok.NoArgsConstructor;
|
// import lombok.NoArgsConstructor;
|
||||||
//
|
//
|
||||||
//public class PacketBeginCameraSceneLookNotify extends BasePacket {
|
// public class PacketBeginCameraSceneLookNotify extends BasePacket {
|
||||||
//
|
//
|
||||||
// public PacketBeginCameraSceneLookNotify(CameraSceneLookNotify parameters) {
|
// public PacketBeginCameraSceneLookNotify(CameraSceneLookNotify parameters) {
|
||||||
// super(PacketOpcodes.BeginCameraSceneLookNotify);
|
// super(PacketOpcodes.BeginCameraSceneLookNotify);
|
||||||
// var builder =
|
// var builder =
|
||||||
// BeginCameraSceneLookNotify.newBuilder()
|
// BeginCameraSceneLookNotify.newBuilder()
|
||||||
// .setLookPos(parameters.lookPos.toProto())
|
// .setLookPos(parameters.lookPos.toProto())
|
||||||
// .setFollowPos(parameters.followPos.toProto())
|
// .setFollowPos(parameters.followPos.toProto())
|
||||||
// .setDuration(parameters.duration)
|
// .setDuration(parameters.duration)
|
||||||
// .setIsAllowInput(parameters.isAllowInput)
|
// .setIsAllowInput(parameters.isAllowInput)
|
||||||
// .setIsSetFollowPos(parameters.setFollowPos)
|
// .setIsSetFollowPos(parameters.setFollowPos)
|
||||||
// .setIsSetScreenXy(parameters.isScreenXY)
|
// .setIsSetScreenXy(parameters.isScreenXY)
|
||||||
// .setIsRecoverKeepCurrent(parameters.recoverKeepCurrent)
|
// .setIsRecoverKeepCurrent(parameters.recoverKeepCurrent)
|
||||||
// .setIsChangePlayMode(parameters.isChangePlayMode)
|
// .setIsChangePlayMode(parameters.isChangePlayMode)
|
||||||
// .setScreenY(parameters.screenY)
|
// .setScreenY(parameters.screenY)
|
||||||
// .setScreenX(parameters.screenX)
|
// .setScreenX(parameters.screenX)
|
||||||
// .setIsForce(parameters.isForce)
|
// .setIsForce(parameters.isForce)
|
||||||
// .setIsForce(parameters.isForceWalk)
|
// .setIsForce(parameters.isForceWalk)
|
||||||
// .setEntityId(parameters.entityId)
|
// .setEntityId(parameters.entityId)
|
||||||
// .addAllOtherParams(parameters.otherParams);
|
// .addAllOtherParams(parameters.otherParams);
|
||||||
// this.setData(builder);
|
// this.setData(builder);
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// // TODO check default values
|
// // TODO check default values
|
||||||
// // todo find missing field usages:
|
// // todo find missing field usages:
|
||||||
// // enum Unk2700_HIAKNNCKHJB (Unk2700_LNCHDDOOECD)
|
// // enum Unk2700_HIAKNNCKHJB (Unk2700_LNCHDDOOECD)
|
||||||
// // Unk3000_MNLLCJMPMNH (uint32)
|
// // Unk3000_MNLLCJMPMNH (uint32)
|
||||||
// // Unk2700_DHAHEKOGHBJ (float)
|
// // Unk2700_DHAHEKOGHBJ (float)
|
||||||
// // Unk3000_IEFIKMHCKDH (uint32)
|
// // Unk3000_IEFIKMHCKDH (uint32)
|
||||||
// // Unk3000_OGCLMFFADBD (float)
|
// // Unk3000_OGCLMFFADBD (float)
|
||||||
//
|
//
|
||||||
// @Data
|
// @Data
|
||||||
// @NoArgsConstructor
|
// @NoArgsConstructor
|
||||||
// public static class CameraSceneLookNotify {
|
// public static class CameraSceneLookNotify {
|
||||||
// Position lookPos = new Position();
|
// Position lookPos = new Position();
|
||||||
// Position followPos = new Position();
|
// Position followPos = new Position();
|
||||||
// float duration = 0.0f;
|
// float duration = 0.0f;
|
||||||
// boolean isAllowInput = true;
|
// boolean isAllowInput = true;
|
||||||
// boolean setFollowPos = false;
|
// boolean setFollowPos = false;
|
||||||
// boolean isScreenXY = false;
|
// boolean isScreenXY = false;
|
||||||
// boolean recoverKeepCurrent = true;
|
// boolean recoverKeepCurrent = true;
|
||||||
// boolean isForceWalk = false;
|
// boolean isForceWalk = false;
|
||||||
// boolean isForce = false;
|
// boolean isForce = false;
|
||||||
// boolean isChangePlayMode = false;
|
// boolean isChangePlayMode = false;
|
||||||
// float screenY = 0.0f;
|
// float screenY = 0.0f;
|
||||||
// float screenX = 0.0f;
|
// float screenX = 0.0f;
|
||||||
// int entityId = 0;
|
// int entityId = 0;
|
||||||
// Collection<String> otherParams = new ArrayList<>(0);
|
// Collection<String> otherParams = new ArrayList<>(0);
|
||||||
// }
|
// }
|
||||||
//}
|
// }
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
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.ChangeGameTimeRspOuterClass.ChangeGameTimeRsp;
|
import emu.grasscutter.net.proto.ChangeGameTimeRspOuterClass.ChangeGameTimeRsp;
|
||||||
|
|
||||||
public class PacketChangeGameTimeRsp extends BasePacket {
|
public class PacketChangeGameTimeRsp extends BasePacket {
|
||||||
|
|
||||||
public PacketChangeGameTimeRsp(Player player) {
|
public PacketChangeGameTimeRsp(Player player) {
|
||||||
super(PacketOpcodes.ChangeGameTimeRsp);
|
super(PacketOpcodes.ChangeGameTimeRsp);
|
||||||
|
|
||||||
ChangeGameTimeRsp proto =
|
ChangeGameTimeRsp proto =
|
||||||
ChangeGameTimeRsp.newBuilder().setCurGameTime(player.getWorld().getGameTime()).build();
|
ChangeGameTimeRsp.newBuilder().setCurGameTime(player.getWorld().getGameTime()).build();
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
//package emu.grasscutter.server.packet.send;
|
// package emu.grasscutter.server.packet.send;
|
||||||
//
|
//
|
||||||
//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.Unk2700FJEHHCPCBLGServerNotify;
|
// import emu.grasscutter.net.proto.Unk2700FJEHHCPCBLGServerNotify;
|
||||||
//
|
//
|
||||||
//public class PacketChangeHomeBgmNotify extends BasePacket {
|
// public class PacketChangeHomeBgmNotify extends BasePacket {
|
||||||
// public PacketChangeHomeBgmNotify(int homeBgmId) {
|
// public PacketChangeHomeBgmNotify(int homeBgmId) {
|
||||||
// super(PacketOpcodes.Unk2700_FJEHHCPCBLG_ServerNotify);
|
// super(PacketOpcodes.Unk2700_FJEHHCPCBLG_ServerNotify);
|
||||||
//
|
//
|
||||||
// var notify =
|
// var notify =
|
||||||
// Unk2700FJEHHCPCBLGServerNotify.Unk2700_FJEHHCPCBLG_ServerNotify.newBuilder()
|
// Unk2700FJEHHCPCBLGServerNotify.Unk2700_FJEHHCPCBLG_ServerNotify.newBuilder()
|
||||||
// .setUnk2700BJHAMKKECEI(homeBgmId)
|
// .setUnk2700BJHAMKKECEI(homeBgmId)
|
||||||
// .build();
|
// .build();
|
||||||
//
|
//
|
||||||
// this.setData(notify);
|
// this.setData(notify);
|
||||||
// }
|
// }
|
||||||
//}
|
// }
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
//package emu.grasscutter.server.packet.send;
|
// package emu.grasscutter.server.packet.send;
|
||||||
//
|
//
|
||||||
//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.Unk2700OGHMHELMBNNServerRsp;
|
// import emu.grasscutter.net.proto.Unk2700OGHMHELMBNNServerRsp;
|
||||||
//
|
//
|
||||||
//public class PacketChangeHomeBgmRsp extends BasePacket {
|
// public class PacketChangeHomeBgmRsp extends BasePacket {
|
||||||
// public PacketChangeHomeBgmRsp() {
|
// public PacketChangeHomeBgmRsp() {
|
||||||
// super(PacketOpcodes.Unk2700_OGHMHELMBNN_ServerRsp);
|
// super(PacketOpcodes.Unk2700_OGHMHELMBNN_ServerRsp);
|
||||||
//
|
//
|
||||||
// var rsp =
|
// var rsp =
|
||||||
// Unk2700OGHMHELMBNNServerRsp.Unk2700_OGHMHELMBNN_ServerRsp.newBuilder()
|
// Unk2700OGHMHELMBNNServerRsp.Unk2700_OGHMHELMBNN_ServerRsp.newBuilder()
|
||||||
// .setRetcode(0)
|
// .setRetcode(0)
|
||||||
// .build();
|
// .build();
|
||||||
//
|
//
|
||||||
// this.setData(rsp);
|
// this.setData(rsp);
|
||||||
// }
|
// }
|
||||||
//}
|
// }
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
//package emu.grasscutter.server.packet.send;
|
// package emu.grasscutter.server.packet.send;
|
||||||
//
|
//
|
||||||
//import emu.grasscutter.game.player.Player;
|
// import emu.grasscutter.game.player.Player;
|
||||||
//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.CustomTeamListNotifyOuterClass.CustomTeamListNotify;
|
// import emu.grasscutter.net.proto.CustomTeamListNotifyOuterClass.CustomTeamListNotify;
|
||||||
//
|
//
|
||||||
//public class PacketCustomTeamListNotify extends BasePacket {
|
// public class PacketCustomTeamListNotify extends BasePacket {
|
||||||
// public PacketCustomTeamListNotify(Player player) {
|
// public PacketCustomTeamListNotify(Player player) {
|
||||||
// super(PacketOpcodes.CustomTeamListNotify);
|
// super(PacketOpcodes.CustomTeamListNotify);
|
||||||
//
|
//
|
||||||
// CustomTeamListNotify.Builder proto = CustomTeamListNotify.newBuilder();
|
// CustomTeamListNotify.Builder proto = CustomTeamListNotify.newBuilder();
|
||||||
//
|
//
|
||||||
// // Add the id list for custom teams.
|
// // Add the id list for custom teams.
|
||||||
// for (int id : player.getTeamManager().getTeams().keySet()) {
|
// for (int id : player.getTeamManager().getTeams().keySet()) {
|
||||||
// if (id > 4) {
|
// if (id > 4) {
|
||||||
// proto.addCustomTeamIds(id);
|
// proto.addCustomTeamIds(id);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// // Add the avatar lists for all the teams the player has.
|
// // Add the avatar lists for all the teams the player has.
|
||||||
// player
|
// player
|
||||||
// .getTeamManager()
|
// .getTeamManager()
|
||||||
// .getTeams()
|
// .getTeams()
|
||||||
// .forEach((id, teamInfo) -> proto.putAvatarTeamMap(id, teamInfo.toProto(player)));
|
// .forEach((id, teamInfo) -> proto.putAvatarTeamMap(id, teamInfo.toProto(player)));
|
||||||
//
|
//
|
||||||
// this.setData(proto);
|
// this.setData(proto);
|
||||||
// }
|
// }
|
||||||
//}
|
// }
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
|
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
|
||||||
import emu.grasscutter.net.packet.BasePacket;
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
|
|
||||||
public class PacketDungeonSettleNotify extends BasePacket {
|
public class PacketDungeonSettleNotify extends BasePacket {
|
||||||
public PacketDungeonSettleNotify(BaseDungeonResult result) {
|
public PacketDungeonSettleNotify(BaseDungeonResult result) {
|
||||||
super(PacketOpcodes.DungeonSettleNotify);
|
super(PacketOpcodes.DungeonSettleNotify);
|
||||||
|
|
||||||
this.setData(result.getProto());
|
this.setData(result.getProto());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,31 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.GameEntity;
|
import emu.grasscutter.game.entity.GameEntity;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
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.EntityFightPropUpdateNotifyOuterClass.EntityFightPropUpdateNotify;
|
import emu.grasscutter.net.proto.EntityFightPropUpdateNotifyOuterClass.EntityFightPropUpdateNotify;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collection;
|
|
||||||
|
public class PacketEntityFightPropUpdateNotify extends BasePacket {
|
||||||
public class PacketEntityFightPropUpdateNotify extends BasePacket {
|
public PacketEntityFightPropUpdateNotify(GameEntity entity, FightProperty prop) {
|
||||||
public PacketEntityFightPropUpdateNotify(GameEntity entity, FightProperty prop) {
|
super(PacketOpcodes.EntityFightPropUpdateNotify);
|
||||||
super(PacketOpcodes.EntityFightPropUpdateNotify);
|
|
||||||
|
EntityFightPropUpdateNotify proto =
|
||||||
EntityFightPropUpdateNotify proto =
|
EntityFightPropUpdateNotify.newBuilder()
|
||||||
EntityFightPropUpdateNotify.newBuilder()
|
.setEntityId(entity.getId())
|
||||||
.setEntityId(entity.getId())
|
.putFightPropMap(prop.getId(), entity.getFightProperty(prop))
|
||||||
.putFightPropMap(prop.getId(), entity.getFightProperty(prop))
|
.build();
|
||||||
.build();
|
|
||||||
|
this.setData(proto);
|
||||||
this.setData(proto);
|
}
|
||||||
}
|
|
||||||
|
public PacketEntityFightPropUpdateNotify(GameEntity entity, Collection<FightProperty> props) {
|
||||||
public PacketEntityFightPropUpdateNotify(GameEntity entity, Collection<FightProperty> props) {
|
super(PacketOpcodes.EntityFightPropUpdateNotify);
|
||||||
super(PacketOpcodes.EntityFightPropUpdateNotify);
|
|
||||||
|
var protoBuilder = EntityFightPropUpdateNotify.newBuilder().setEntityId(entity.getId());
|
||||||
var protoBuilder = EntityFightPropUpdateNotify.newBuilder()
|
props.forEach(p -> protoBuilder.putFightPropMap(p.getId(), entity.getFightProperty(p)));
|
||||||
.setEntityId(entity.getId());
|
|
||||||
props.forEach(p -> protoBuilder.putFightPropMap(p.getId(), entity.getFightProperty(p)));
|
this.setData(protoBuilder);
|
||||||
|
}
|
||||||
this.setData(protoBuilder);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.quest.GameMainQuest;
|
import emu.grasscutter.game.quest.GameMainQuest;
|
||||||
import emu.grasscutter.game.quest.enums.ParentQuestState;
|
import emu.grasscutter.game.quest.enums.ParentQuestState;
|
||||||
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.FinishedParentQuestNotifyOuterClass.FinishedParentQuestNotify;
|
import emu.grasscutter.net.proto.FinishedParentQuestNotifyOuterClass.FinishedParentQuestNotify;
|
||||||
|
|
||||||
public class PacketFinishedParentQuestNotify extends BasePacket {
|
public class PacketFinishedParentQuestNotify extends BasePacket {
|
||||||
|
|
||||||
public PacketFinishedParentQuestNotify(Player player) {
|
public PacketFinishedParentQuestNotify(Player player) {
|
||||||
super(PacketOpcodes.FinishedParentQuestNotify, true);
|
super(PacketOpcodes.FinishedParentQuestNotify, true);
|
||||||
|
|
||||||
FinishedParentQuestNotify.Builder proto = FinishedParentQuestNotify.newBuilder();
|
FinishedParentQuestNotify.Builder proto = FinishedParentQuestNotify.newBuilder();
|
||||||
|
|
||||||
for (GameMainQuest mainQuest : player.getQuestManager().getMainQuests().values()) {
|
for (GameMainQuest mainQuest : player.getQuestManager().getMainQuests().values()) {
|
||||||
//Canceled Quests do not appear in this packet
|
// Canceled Quests do not appear in this packet
|
||||||
if (mainQuest.getState() != ParentQuestState.PARENT_QUEST_STATE_CANCELED) {
|
if (mainQuest.getState() != ParentQuestState.PARENT_QUEST_STATE_CANCELED) {
|
||||||
proto.addParentQuestList(mainQuest.toProto(false));
|
proto.addParentQuestList(mainQuest.toProto(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,33 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.game.quest.GameMainQuest;
|
import emu.grasscutter.game.quest.GameMainQuest;
|
||||||
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.FinishedParentQuestUpdateNotifyOuterClass.FinishedParentQuestUpdateNotify;
|
import emu.grasscutter.net.proto.FinishedParentQuestUpdateNotifyOuterClass.FinishedParentQuestUpdateNotify;
|
||||||
|
import java.util.List;
|
||||||
import java.util.List;
|
|
||||||
|
public class PacketFinishedParentQuestUpdateNotify extends BasePacket {
|
||||||
public class PacketFinishedParentQuestUpdateNotify extends BasePacket {
|
|
||||||
|
public PacketFinishedParentQuestUpdateNotify(GameMainQuest quest) {
|
||||||
public PacketFinishedParentQuestUpdateNotify(GameMainQuest quest) {
|
super(PacketOpcodes.FinishedParentQuestUpdateNotify);
|
||||||
super(PacketOpcodes.FinishedParentQuestUpdateNotify);
|
|
||||||
|
FinishedParentQuestUpdateNotify proto =
|
||||||
FinishedParentQuestUpdateNotify proto = FinishedParentQuestUpdateNotify.newBuilder()
|
FinishedParentQuestUpdateNotify.newBuilder()
|
||||||
.addParentQuestList(quest.toProto(true))
|
.addParentQuestList(quest.toProto(true))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PacketFinishedParentQuestUpdateNotify(List<GameMainQuest> quests) {
|
public PacketFinishedParentQuestUpdateNotify(List<GameMainQuest> quests) {
|
||||||
super(PacketOpcodes.FinishedParentQuestUpdateNotify);
|
super(PacketOpcodes.FinishedParentQuestUpdateNotify);
|
||||||
|
|
||||||
var proto = FinishedParentQuestUpdateNotify.newBuilder();
|
var proto = FinishedParentQuestUpdateNotify.newBuilder();
|
||||||
|
|
||||||
for (GameMainQuest mainQuest : quests) {
|
for (GameMainQuest mainQuest : quests) {
|
||||||
proto.addParentQuestList(mainQuest.toProto(true));
|
proto.addParentQuestList(mainQuest.toProto(true));
|
||||||
}
|
}
|
||||||
proto.build();
|
proto.build();
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,40 +1,42 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
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.GetAllMailResultNotifyOuterClass.GetAllMailResultNotify;
|
import emu.grasscutter.net.proto.GetAllMailResultNotifyOuterClass.GetAllMailResultNotify;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
|
import java.time.Instant;
|
||||||
import java.time.Instant;
|
import java.util.List;
|
||||||
import java.util.List;
|
|
||||||
|
public final class PacketGetAllMailResultNotify extends BasePacket {
|
||||||
public final class PacketGetAllMailResultNotify extends BasePacket {
|
/**
|
||||||
/**
|
* @param player The player to fetch the mail for.
|
||||||
* @param player The player to fetch the mail for.
|
* @param gifts Is the mail for gifts?
|
||||||
* @param gifts Is the mail for gifts?
|
*/
|
||||||
*/
|
public PacketGetAllMailResultNotify(Player player, boolean gifts) {
|
||||||
public PacketGetAllMailResultNotify(Player player, boolean gifts) {
|
super(PacketOpcodes.GetAllMailResultNotify);
|
||||||
super(PacketOpcodes.GetAllMailResultNotify);
|
|
||||||
|
var packet =
|
||||||
var packet = GetAllMailResultNotify.newBuilder()
|
GetAllMailResultNotify.newBuilder()
|
||||||
.setTransaction(player.getUid() + "-" + Utils.getCurrentSeconds() + "-" + 0)
|
.setTransaction(player.getUid() + "-" + Utils.getCurrentSeconds() + "-" + 0)
|
||||||
.setIsCollected(gifts)
|
.setIsCollected(gifts)
|
||||||
.setPacketBeSentNum(1)
|
.setPacketBeSentNum(1)
|
||||||
.setPacketNum(1);
|
.setPacketNum(1);
|
||||||
|
|
||||||
var inbox = player.getAllMail();
|
var inbox = player.getAllMail();
|
||||||
if (!gifts && inbox.size() > 0) {
|
if (!gifts && inbox.size() > 0) {
|
||||||
packet.addAllMailList(inbox.stream()
|
packet.addAllMailList(
|
||||||
.filter(mail -> mail.stateValue == 1)
|
inbox.stream()
|
||||||
.filter(mail -> mail.expireTime > Instant.now().getEpochSecond())
|
.filter(mail -> mail.stateValue == 1)
|
||||||
.map(mail -> mail.toProto(player)).toList());
|
.filter(mail -> mail.expireTime > Instant.now().getEpochSecond())
|
||||||
} else {
|
.map(mail -> mail.toProto(player))
|
||||||
// Empty mailbox.
|
.toList());
|
||||||
// TODO: Implement the gift mailbox.
|
} else {
|
||||||
packet.addAllMailList(List.of());
|
// Empty mailbox.
|
||||||
}
|
// TODO: Implement the gift mailbox.
|
||||||
|
packet.addAllMailList(List.of());
|
||||||
this.setData(packet.build());
|
}
|
||||||
}
|
|
||||||
}
|
this.setData(packet.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
//package emu.grasscutter.server.packet.send;
|
// package emu.grasscutter.server.packet.send;
|
||||||
//
|
//
|
||||||
//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.HomeUnknown1NotifyOuterClass;
|
// import emu.grasscutter.net.proto.HomeUnknown1NotifyOuterClass;
|
||||||
//
|
//
|
||||||
//public class PacketHomeUnknown1Notify extends BasePacket {
|
// public class PacketHomeUnknown1Notify extends BasePacket {
|
||||||
//
|
//
|
||||||
// public PacketHomeUnknown1Notify(boolean isEnterEditMode) {
|
// public PacketHomeUnknown1Notify(boolean isEnterEditMode) {
|
||||||
// super(PacketOpcodes.Unk2700_JDMPECKFGIG_ServerNotify);
|
// super(PacketOpcodes.Unk2700_JDMPECKFGIG_ServerNotify);
|
||||||
//
|
//
|
||||||
// var proto = HomeUnknown1NotifyOuterClass.HomeUnknown1Notify.newBuilder();
|
// var proto = HomeUnknown1NotifyOuterClass.HomeUnknown1Notify.newBuilder();
|
||||||
//
|
//
|
||||||
// proto.setIsEnterEditMode(isEnterEditMode);
|
// proto.setIsEnterEditMode(isEnterEditMode);
|
||||||
//
|
//
|
||||||
// this.setData(proto);
|
// this.setData(proto);
|
||||||
// }
|
// }
|
||||||
//}
|
// }
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
//package emu.grasscutter.server.packet.send;
|
// package emu.grasscutter.server.packet.send;
|
||||||
//
|
//
|
||||||
//import emu.grasscutter.net.packet.BasePacket;
|
// import emu.grasscutter.net.packet.BasePacket;
|
||||||
//import emu.grasscutter.net.packet.PacketOpcodes;
|
// import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
//
|
//
|
||||||
//public class PacketHomeUnknown2Rsp extends BasePacket {
|
// public class PacketHomeUnknown2Rsp extends BasePacket {
|
||||||
//
|
//
|
||||||
// public PacketHomeUnknown2Rsp() {
|
// public PacketHomeUnknown2Rsp() {
|
||||||
// super(PacketOpcodes.Unk2700_KIIOGMKFNNP_ServerRsp);
|
// super(PacketOpcodes.Unk2700_KIIOGMKFNNP_ServerRsp);
|
||||||
// }
|
// }
|
||||||
//}
|
// }
|
||||||
|
@ -1,32 +1,33 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
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.MusicGameSettleReqOuterClass;
|
import emu.grasscutter.net.proto.MusicGameSettleReqOuterClass;
|
||||||
import emu.grasscutter.net.proto.MusicGameSettleRspOuterClass;
|
import emu.grasscutter.net.proto.MusicGameSettleRspOuterClass;
|
||||||
import emu.grasscutter.net.proto.RetcodeOuterClass;
|
import emu.grasscutter.net.proto.RetcodeOuterClass;
|
||||||
|
|
||||||
public class PacketMusicGameSettleRsp extends BasePacket {
|
public class PacketMusicGameSettleRsp extends BasePacket {
|
||||||
|
|
||||||
public PacketMusicGameSettleRsp(int musicBasicId, long musicShareId, boolean isNewRecord) {
|
public PacketMusicGameSettleRsp(int musicBasicId, long musicShareId, boolean isNewRecord) {
|
||||||
super(PacketOpcodes.MusicGameSettleRsp);
|
super(PacketOpcodes.MusicGameSettleRsp);
|
||||||
|
|
||||||
var proto = MusicGameSettleRspOuterClass.MusicGameSettleRsp.newBuilder();
|
var proto = MusicGameSettleRspOuterClass.MusicGameSettleRsp.newBuilder();
|
||||||
|
|
||||||
proto.setMusicBasicId(musicBasicId).setUgcGuid(musicShareId).setIsNewRecord(isNewRecord);
|
proto.setMusicBasicId(musicBasicId).setUgcGuid(musicShareId).setIsNewRecord(isNewRecord);
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PacketMusicGameSettleRsp(RetcodeOuterClass.Retcode errorCode, MusicGameSettleReqOuterClass.MusicGameSettleReq req) {
|
public PacketMusicGameSettleRsp(
|
||||||
super(PacketOpcodes.MusicGameSettleRsp);
|
RetcodeOuterClass.Retcode errorCode, MusicGameSettleReqOuterClass.MusicGameSettleReq req) {
|
||||||
|
super(PacketOpcodes.MusicGameSettleRsp);
|
||||||
var proto = MusicGameSettleRspOuterClass.MusicGameSettleRsp.newBuilder()
|
|
||||||
.setRetcode(errorCode.getNumber())
|
var proto =
|
||||||
.setMusicBasicId(req.getMusicBasicId())
|
MusicGameSettleRspOuterClass.MusicGameSettleRsp.newBuilder()
|
||||||
.setUgcGuid(req.getUgcGuid());
|
.setRetcode(errorCode.getNumber())
|
||||||
|
.setMusicBasicId(req.getMusicBasicId())
|
||||||
|
.setUgcGuid(req.getUgcGuid());
|
||||||
this.setData(proto);
|
|
||||||
}
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
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.PlatformStartRouteNotifyOuterClass.PlatformStartRouteNotify;
|
import emu.grasscutter.net.proto.PlatformStartRouteNotifyOuterClass.PlatformStartRouteNotify;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
public class PacketPlatformStartRouteNotify extends BasePacket {
|
public class PacketPlatformStartRouteNotify extends BasePacket {
|
||||||
public PacketPlatformStartRouteNotify(EntityGadget gadgetEntity) {
|
public PacketPlatformStartRouteNotify(EntityGadget gadgetEntity) {
|
||||||
super(PacketOpcodes.PlatformStartRouteNotify);
|
super(PacketOpcodes.PlatformStartRouteNotify);
|
||||||
|
|
||||||
val notify = PlatformStartRouteNotify.newBuilder()
|
val notify =
|
||||||
.setEntityId(gadgetEntity.getId())
|
PlatformStartRouteNotify.newBuilder()
|
||||||
.setSceneTime(gadgetEntity.getScene().getSceneTime())
|
.setEntityId(gadgetEntity.getId())
|
||||||
.setPlatform(gadgetEntity.getPlatformInfo());
|
.setSceneTime(gadgetEntity.getScene().getSceneTime())
|
||||||
|
.setPlatform(gadgetEntity.getPlatformInfo());
|
||||||
this.setData(notify);
|
|
||||||
}
|
this.setData(notify);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
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.PlatformStopRouteNotifyOuterClass;
|
import emu.grasscutter.net.proto.PlatformStopRouteNotifyOuterClass;
|
||||||
|
|
||||||
public class PacketPlatformStopRouteNotify extends BasePacket {
|
public class PacketPlatformStopRouteNotify extends BasePacket {
|
||||||
public PacketPlatformStopRouteNotify(EntityGadget gadgetEntity) {
|
public PacketPlatformStopRouteNotify(EntityGadget gadgetEntity) {
|
||||||
super(PacketOpcodes.PlatformStopRouteNotify);
|
super(PacketOpcodes.PlatformStopRouteNotify);
|
||||||
|
|
||||||
var notify = PlatformStopRouteNotifyOuterClass.PlatformStopRouteNotify.newBuilder()
|
var notify =
|
||||||
.setPlatform(gadgetEntity.getPlatformInfo())
|
PlatformStopRouteNotifyOuterClass.PlatformStopRouteNotify.newBuilder()
|
||||||
.setSceneTime(gadgetEntity.getScene().getSceneTime())
|
.setPlatform(gadgetEntity.getPlatformInfo())
|
||||||
.setEntityId(gadgetEntity.getId())
|
.setSceneTime(gadgetEntity.getScene().getSceneTime())
|
||||||
.build();
|
.setEntityId(gadgetEntity.getId())
|
||||||
|
.build();
|
||||||
this.setData(notify);
|
|
||||||
}
|
this.setData(notify);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
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.PlayerGameTimeNotifyOuterClass.PlayerGameTimeNotify;
|
import emu.grasscutter.net.proto.PlayerGameTimeNotifyOuterClass.PlayerGameTimeNotify;
|
||||||
|
|
||||||
public class PacketPlayerGameTimeNotify extends BasePacket {
|
public class PacketPlayerGameTimeNotify extends BasePacket {
|
||||||
|
|
||||||
public PacketPlayerGameTimeNotify(Player player) {
|
public PacketPlayerGameTimeNotify(Player player) {
|
||||||
super(PacketOpcodes.PlayerGameTimeNotify);
|
super(PacketOpcodes.PlayerGameTimeNotify);
|
||||||
|
|
||||||
PlayerGameTimeNotify proto =
|
PlayerGameTimeNotify proto =
|
||||||
PlayerGameTimeNotify.newBuilder()
|
PlayerGameTimeNotify.newBuilder()
|
||||||
.setGameTime(player.getWorld().getGameTime())
|
.setGameTime(player.getWorld().getGameTime())
|
||||||
.setUid(player.getUid())
|
.setUid(player.getUid())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user