Custom Teams (#1731)

* Add support for creating and deleting custom teams.

* Add support for creating and deleting custom teams.

* Move some logic to TeamInfo::toProto
This commit is contained in:
GanyusLeftHorn
2022-09-01 02:21:47 +02:00
committed by GitHub
parent 4f015c1077
commit 712d17631f
17 changed files with 3678 additions and 125 deletions

View File

@@ -8,7 +8,8 @@ import emu.grasscutter.utils.Utils;
public final class GameConstants {
public static String VERSION = "3.0.0";
public static final int MAX_TEAMS = 4;
public static final int DEFAULT_TEAMS = 4;
public static final int MAX_TEAMS = 10;
public static final int MAIN_CHARACTER_MALE = 10000005;
public static final int MAIN_CHARACTER_FEMALE = 10000007;
public static final Position START_POSITION = new Position(2747, 194, -1719);

View File

@@ -7,6 +7,7 @@ import java.util.List;
import dev.morphia.annotations.Entity;
import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.net.proto.AvatarTeamOuterClass.AvatarTeam;
@Entity
public class TeamInfo {
@@ -81,4 +82,16 @@ public class TeamInfo {
this.getAvatars().add(id);
}
}
public AvatarTeam toProto(Player player) {
AvatarTeam.Builder avatarTeam = AvatarTeam.newBuilder()
.setTeamName(this.getName());
for (int i = 0; i < this.getAvatars().size(); i++) {
Avatar avatar = player.getAvatars().getAvatarById(this.getAvatars().get(i));
avatarTeam.addAvatarGuidList(avatar.getGuid());
}
return avatarTeam.build();
}
}

View File

@@ -20,17 +20,20 @@ import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState;
import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType;
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
import emu.grasscutter.server.event.player.PlayerTeamDeathEvent;
import emu.grasscutter.server.packet.send.PacketAddCustomTeamRsp;
import emu.grasscutter.server.packet.send.PacketAvatarDieAnimationEndRsp;
import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify;
import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify;
import emu.grasscutter.server.packet.send.PacketAvatarSkillInfoNotify;
import emu.grasscutter.server.packet.send.PacketAvatarTeamUpdateNotify;
import emu.grasscutter.server.packet.send.PacketChangeAvatarRsp;
import emu.grasscutter.server.packet.send.PacketChangeMpTeamAvatarRsp;
import emu.grasscutter.server.packet.send.PacketChangeTeamNameRsp;
import emu.grasscutter.server.packet.send.PacketChooseCurAvatarTeamRsp;
import emu.grasscutter.server.packet.send.PacketCustomTeamListNotify;
import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify;
import emu.grasscutter.server.packet.send.PacketRemoveCustomTeamRsp;
import emu.grasscutter.server.packet.send.PacketSceneTeamUpdateNotify;
import emu.grasscutter.server.packet.send.PacketSetUpAvatarTeamRsp;
import emu.grasscutter.server.packet.send.PacketWorldPlayerDieNotify;
@@ -44,7 +47,8 @@ import lombok.Setter;
@Entity
public class TeamManager extends BasePlayerDataManager {
@Getter private Map<Integer, TeamInfo> teams;
// This needs to be a LinkedHashMap to guarantee insertion order.
@Getter private LinkedHashMap<Integer, TeamInfo> teams;
private int currentTeamIndex;
@Getter @Setter private int currentCharacterIndex;
@@ -70,9 +74,9 @@ public class TeamManager extends BasePlayerDataManager {
this();
this.setPlayer(player);
this.teams = new HashMap<>();
this.teams = new LinkedHashMap<>();
this.currentTeamIndex = 1;
for (int i = 1; i <= GameConstants.MAX_TEAMS; i++) {
for (int i = 1; i <= GameConstants.DEFAULT_TEAMS; i++) {
this.teams.put(i, new TeamInfo());
}
}
@@ -640,4 +644,42 @@ public class TeamManager extends BasePlayerDataManager {
public void onPlayerLogin() { // Hack for now to fix resonances on login
this.updateTeamResonances();
}
public synchronized void addNewCustomTeam() {
// Sanity check - max number of teams.
if (this.teams.size() == GameConstants.MAX_TEAMS) {
player.sendPacket(new PacketAddCustomTeamRsp(Retcode.RET_FAIL));
return;
}
// The id of the new custom team is the lowest id in [5,MAX_TEAMS] that is not yet taken.
int id = -1;
for (int i = 5; i <= GameConstants.MAX_TEAMS; i++) {
if (!this.teams.keySet().contains(i)) {
id = i;
break;
}
}
// Create the new team.
this.teams.put(id, new TeamInfo());
// Send packets.
player.sendPacket(new PacketCustomTeamListNotify(player));
player.sendPacket(new PacketAddCustomTeamRsp());
}
public synchronized void removeCustomTeam(int id) {
// Check if the target id exists.
if (!this.teams.containsKey(id)) {
player.sendPacket(new PacketRemoveCustomTeamRsp(Retcode.RET_FAIL, id));
}
// Remove team.
this.teams.remove(id);
// Send packets.
player.sendPacket(new PacketCustomTeamListNotify(player));
player.sendPacket(new PacketRemoveCustomTeamRsp(id));
}
}

View File

@@ -1784,9 +1784,9 @@ public class PacketOpcodes {
public static final int Unk3000_CPCMICDDBCH = 20011;
public static final int Unk3000_DCAHJINNNDM = 23107;
public static final int Unk3000_DCLAGIJJEHB = 402;
public static final int Unk3000_DFIIBIGPHGE = 1731;
public static final int RemoveCustomTeamReq = 1731;
public static final int Unk3000_DHEOMDCCMMC = 429;
public static final int Unk3000_DHOFMKPKFMF = 1749;
public static final int CustomTeamListNotify = 1749;
public static final int Unk3000_DJNBNBMIECP = 5588;
public static final int Unk3000_DLCDJPKNGBD = 185;
public static final int Unk3000_DPEJONKFONL = 21750;
@@ -1807,9 +1807,9 @@ public class PacketOpcodes {
public static final int Unk3000_HIJKNFBBCFC = 23948;
public static final int Unk3000_HPFGNOIGNAG = 21961;
public static final int Unk3000_IBMFJMGHCNC = 6060;
public static final int Unk3000_IBNIGBFIEEF = 1735;
public static final int AddCustomTeamRsp = 1735;
public static final int Unk3000_IGCECHKNKOO = 21804;
public static final int Unk3000_IMLAPBGLBFF = 1687;
public static final int AddCustomTeamReq = 1687;
public static final int Unk3000_IPAKLDNKDAO = 6275;
public static final int Unk3000_JDCOHPBDPED = 125;
public static final int Unk3000_JIEPEGAHDNH = 24152;
@@ -1817,7 +1817,7 @@ public class PacketOpcodes {
public static final int Unk3000_KEJGDDMMBLP = 6376;
public static final int Unk3000_KGDKKLOOIPG = 457;
public static final int Unk3000_KHFMBKILMMD = 24081;
public static final int Unk3000_KIDDGDPKBEN = 1729;
public static final int RemoveCustomTeamRsp = 1729;
public static final int Unk3000_KJNIKBPKAED = 461;
public static final int Unk3000_KKHPGFINACH = 24602;
public static final int Unk3000_KOKEHAPLNHF = 6190;

View File

@@ -0,0 +1,14 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.server.game.GameSession;
@Opcodes(PacketOpcodes.AddCustomTeamReq)
public class HandlerAddCustomTeamReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
session.getPlayer().getTeamManager().addNewCustomTeam();
}
}

View File

@@ -0,0 +1,16 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.RemoveCustomTeamReqOuterClass.RemoveCustomTeamReq;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.server.game.GameSession;
@Opcodes(PacketOpcodes.RemoveCustomTeamReq)
public class HandlerRemoveCustomTeamReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
RemoveCustomTeamReq req = RemoveCustomTeamReq.parseFrom(payload);
session.getPlayer().getTeamManager().removeCustomTeam(req.getId());
}
}

View File

@@ -0,0 +1,22 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
import emu.grasscutter.net.proto.AddCustomTeamRspOuterClass.AddCustomTeamRsp;
public class PacketAddCustomTeamRsp extends BasePacket {
public PacketAddCustomTeamRsp(Retcode retcode) {
super(PacketOpcodes.AddCustomTeamRsp);
AddCustomTeamRsp proto = AddCustomTeamRsp.newBuilder()
.setRetcode(retcode.getNumber())
.build();
this.setData(proto);
}
public PacketAddCustomTeamRsp() {
this(Retcode.RET_SUCC);
}
}

View File

@@ -25,17 +25,16 @@ public class PacketAvatarDataNotify extends BasePacket {
proto.addAvatarList(avatar.toProto());
}
// Add the id list for custom teams.
for (int id : player.getTeamManager().getTeams().keySet()) {
if (id > 4) {
proto.addCustomTeamIds(id);
}
}
for (Entry<Integer, TeamInfo> entry : player.getTeamManager().getTeams().entrySet()) {
TeamInfo teamInfo = entry.getValue();
AvatarTeam.Builder avatarTeam = AvatarTeam.newBuilder()
.setTeamName(teamInfo.getName());
for (int i = 0; i < teamInfo.getAvatars().size(); i++) {
Avatar avatar = player.getAvatars().getAvatarById(teamInfo.getAvatars().get(i));
avatarTeam.addAvatarGuidList(avatar.getGuid());
}
proto.putAvatarTeamMap(entry.getKey(), avatarTeam.build());
proto.putAvatarTeamMap(entry.getKey(), teamInfo.toProto(player));
}
// Set main character

View File

@@ -19,15 +19,7 @@ public class PacketAvatarTeamUpdateNotify extends BasePacket {
for (Entry<Integer, TeamInfo> entry : player.getTeamManager().getTeams().entrySet()) {
TeamInfo teamInfo = entry.getValue();
AvatarTeam.Builder avatarTeam = AvatarTeam.newBuilder()
.setTeamName(teamInfo.getName());
for (int i = 0; i < teamInfo.getAvatars().size(); i++) {
Avatar avatar = player.getAvatars().getAvatarById(teamInfo.getAvatars().get(i));
avatarTeam.addAvatarGuidList(avatar.getGuid());
}
proto.putAvatarTeamMap(entry.getKey(), avatarTeam.build());
proto.putAvatarTeamMap(entry.getKey(), teamInfo.toProto(player));
}
this.setData(proto);

View File

@@ -0,0 +1,34 @@
package emu.grasscutter.server.packet.send;
import java.util.Map.Entry;
import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.player.TeamInfo;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.AvatarTeamOuterClass.AvatarTeam;
import emu.grasscutter.net.proto.CustomTeamListNotifyOuterClass.CustomTeamListNotify;
public class PacketCustomTeamListNotify extends BasePacket {
public PacketCustomTeamListNotify(Player player) {
super(PacketOpcodes.CustomTeamListNotify);
CustomTeamListNotify.Builder proto = CustomTeamListNotify.newBuilder();
// Add the id list for custom teams.
for (int id : player.getTeamManager().getTeams().keySet()) {
if (id > 4) {
proto.addCustomTeamIds(id);
}
}
// Add the avatar lists for all the teams the player has.
for (Entry<Integer, TeamInfo> entry : player.getTeamManager().getTeams().entrySet()) {
TeamInfo teamInfo = entry.getValue();
proto.putAvatarTeamMap(entry.getKey(), teamInfo.toProto(player));
}
this.setData(proto);
}
}

View File

@@ -0,0 +1,23 @@
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
import emu.grasscutter.net.proto.RemoveCustomTeamRspOuterClass.RemoveCustomTeamRsp;
public class PacketRemoveCustomTeamRsp extends BasePacket {
public PacketRemoveCustomTeamRsp(Retcode retcode, int id) {
super(PacketOpcodes.RemoveCustomTeamRsp);
RemoveCustomTeamRsp proto = RemoveCustomTeamRsp.newBuilder()
.setRetcode(retcode.getNumber())
.setId(id)
.build();
this.setData(proto);
}
public PacketRemoveCustomTeamRsp(int id) {
this(Retcode.RET_SUCC, id);
}
}