mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-12-14 16:04:40 +01:00
Merge branch 'development' into api
# Conflicts: # src/main/java/emu/grasscutter/Grasscutter.java
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
package emu.grasscutter.game.dungeons;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.MonsterData;
|
||||
import emu.grasscutter.game.entity.EntityMonster;
|
||||
import emu.grasscutter.game.entity.GameEntity;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.scripts.data.SceneGroup;
|
||||
import emu.grasscutter.scripts.data.SceneMonster;
|
||||
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketDungeonChallengeBeginNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify;
|
||||
|
||||
public class DungeonChallenge {
|
||||
private final Scene scene;
|
||||
private final SceneGroup group;
|
||||
|
||||
private int challengeIndex;
|
||||
private int challengeId;
|
||||
private boolean success;
|
||||
private boolean progress;
|
||||
|
||||
private int score;
|
||||
private int objective = 0;
|
||||
|
||||
public DungeonChallenge(Scene scene, SceneGroup group) {
|
||||
this.scene = scene;
|
||||
this.group = group;
|
||||
|
||||
objective += group.monsters.size();
|
||||
}
|
||||
|
||||
public Scene getScene() {
|
||||
return scene;
|
||||
}
|
||||
|
||||
public SceneGroup getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public int getChallengeIndex() {
|
||||
return challengeIndex;
|
||||
}
|
||||
|
||||
public void setChallengeIndex(int challengeIndex) {
|
||||
this.challengeIndex = challengeIndex;
|
||||
}
|
||||
|
||||
public int getChallengeId() {
|
||||
return challengeId;
|
||||
}
|
||||
|
||||
public void setChallengeId(int challengeId) {
|
||||
this.challengeId = challengeId;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public void setSuccess(boolean isSuccess) {
|
||||
this.success = isSuccess;
|
||||
}
|
||||
|
||||
public boolean inProgress() {
|
||||
return progress;
|
||||
}
|
||||
|
||||
public int getScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
this.progress = true;
|
||||
getScene().broadcastPacket(new PacketDungeonChallengeBeginNotify(this));
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
this.progress = false;
|
||||
getScene().broadcastPacket(new PacketDungeonChallengeFinishNotify(this));
|
||||
|
||||
if (this.isSuccess()) {
|
||||
this.getScene().getScriptManager().callEvent(EventType.EVENT_CHALLENGE_SUCCESS, null);
|
||||
} else {
|
||||
this.getScene().getScriptManager().callEvent(EventType.EVENT_CHALLENGE_FAIL, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void onMonsterDie(EntityMonster entity) {
|
||||
score = getScore() + 1;
|
||||
|
||||
getScene().broadcastPacket(new PacketChallengeDataNotify(this, 1, getScore()));
|
||||
|
||||
if (getScore() >= objective) {
|
||||
this.setSuccess(true);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,18 @@
|
||||
package emu.grasscutter.game.dungeons;
|
||||
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.custom.ScenePointEntry;
|
||||
import emu.grasscutter.data.def.DungeonData;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.SceneType;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp;
|
||||
import emu.grasscutter.server.packet.send.PacketPlayerEnterDungeonRsp;
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
public class DungeonManager {
|
||||
private final GameServer server;
|
||||
@@ -12,4 +24,59 @@ public class DungeonManager {
|
||||
public GameServer getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public void getEntryInfo(Player player, int pointId) {
|
||||
ScenePointEntry entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId);
|
||||
|
||||
if (entry == null || entry.getPointData().getDungeonIds() == null) {
|
||||
// Error
|
||||
player.sendPacket(new PacketDungeonEntryInfoRsp());
|
||||
return;
|
||||
}
|
||||
|
||||
player.sendPacket(new PacketDungeonEntryInfoRsp(player, entry.getPointData()));
|
||||
}
|
||||
|
||||
public void enterDungeon(Player player, int pointId, int dungeonId) {
|
||||
DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
|
||||
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Grasscutter.getLogger().info(player.getNickname() + " is trying to enter dungeon " + dungeonId);
|
||||
|
||||
int sceneId = data.getSceneId();
|
||||
player.getScene().setPrevScene(sceneId);
|
||||
|
||||
player.getWorld().transferPlayerToScene(player, sceneId, data);
|
||||
|
||||
player.getScene().setPrevScenePoint(pointId);
|
||||
player.sendPacket(new PacketPlayerEnterDungeonRsp(pointId, dungeonId));
|
||||
}
|
||||
|
||||
public void exitDungeon(Player player) {
|
||||
if (player.getScene().getSceneType() != SceneType.SCENE_DUNGEON) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get previous scene
|
||||
int prevScene = player.getScene().getPrevScene() > 0 ? player.getScene().getPrevScene() : 3;
|
||||
|
||||
// Get previous position
|
||||
DungeonData dungeonData = player.getScene().getDungeonData();
|
||||
Position prevPos = new Position(GameConstants.START_POSITION);
|
||||
|
||||
if (dungeonData != null) {
|
||||
ScenePointEntry entry = GameData.getScenePointEntryById(prevScene, player.getScene().getPrevScenePoint());
|
||||
|
||||
if (entry != null) {
|
||||
prevPos.set(entry.getPointData().getTranPos());
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer player back to world
|
||||
player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
|
||||
player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package emu.grasscutter.game.entity;
|
||||
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.game.world.World;
|
||||
|
||||
public abstract class EntityBaseGadget extends GameEntity {
|
||||
|
||||
public EntityBaseGadget(Scene scene) {
|
||||
super(scene);
|
||||
}
|
||||
|
||||
public abstract int getGadgetId();
|
||||
|
||||
@Override
|
||||
public void onDeath(int killerId) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.ProtoHelper;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
|
||||
public class EntityClientGadget extends EntityGadget {
|
||||
public class EntityClientGadget extends EntityBaseGadget {
|
||||
private final Player owner;
|
||||
|
||||
private final Position pos;
|
||||
|
||||
@@ -1,18 +1,157 @@
|
||||
package emu.grasscutter.game.entity;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.GadgetData;
|
||||
import emu.grasscutter.game.props.EntityIdType;
|
||||
import emu.grasscutter.game.props.EntityType;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.game.world.World;
|
||||
import emu.grasscutter.net.proto.ClientGadgetInfoOuterClass;
|
||||
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
||||
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
|
||||
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
|
||||
import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData;
|
||||
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
|
||||
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
||||
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
|
||||
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
|
||||
import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
|
||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||
import emu.grasscutter.net.proto.WorktopInfoOuterClass.WorktopInfo;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.ProtoHelper;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
|
||||
public abstract class EntityGadget extends GameEntity {
|
||||
public class EntityGadget extends EntityBaseGadget {
|
||||
private final GadgetData data;
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
private int gadgetId;
|
||||
|
||||
private int state;
|
||||
private IntSet worktopOptions;
|
||||
|
||||
public EntityGadget(Scene scene) {
|
||||
public EntityGadget(Scene scene, int gadgetId, Position pos) {
|
||||
super(scene);
|
||||
this.data = GameData.getGadgetDataMap().get(gadgetId);
|
||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||
this.gadgetId = gadgetId;
|
||||
this.pos = pos.clone();
|
||||
this.rot = new Position();
|
||||
}
|
||||
|
||||
public abstract int getGadgetId();
|
||||
public GadgetData getGadgetData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
// TODO Auto-generated method stub
|
||||
return this.pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getRotation() {
|
||||
// TODO Auto-generated method stub
|
||||
return this.rot;
|
||||
}
|
||||
|
||||
public int getGadgetId() {
|
||||
return gadgetId;
|
||||
}
|
||||
|
||||
public void setGadgetId(int gadgetId) {
|
||||
this.gadgetId = gadgetId;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(int state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public IntSet getWorktopOptions() {
|
||||
return worktopOptions;
|
||||
}
|
||||
|
||||
public void addWorktopOptions(int[] options) {
|
||||
if (this.worktopOptions == null) {
|
||||
this.worktopOptions = new IntOpenHashSet();
|
||||
}
|
||||
Arrays.stream(options).forEach(this.worktopOptions::add);
|
||||
}
|
||||
|
||||
public void removeWorktopOption(int option) {
|
||||
if (this.worktopOptions == null) {
|
||||
return;
|
||||
}
|
||||
this.worktopOptions.remove(option);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeath(int killerId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SceneEntityInfo toProto() {
|
||||
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
|
||||
.setBornPos(Vector.newBuilder())
|
||||
.build();
|
||||
|
||||
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_GADGET)
|
||||
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(1);
|
||||
|
||||
PropPair pair = PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
|
||||
.build();
|
||||
entityInfo.addPropList(pair);
|
||||
|
||||
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
|
||||
.setGadgetId(this.getGadgetId())
|
||||
.setGroupId(this.getGroupId())
|
||||
.setConfigId(this.getConfigId())
|
||||
.setGadgetState(this.getState())
|
||||
.setIsEnableInteract(true)
|
||||
.setAuthorityPeerId(this.getScene().getWorld().getHostPeerId());
|
||||
|
||||
if (this.getGadgetData().getType() == EntityType.Worktop && this.getWorktopOptions() != null) {
|
||||
WorktopInfo worktop = WorktopInfo.newBuilder()
|
||||
.addAllOptionList(this.getWorktopOptions())
|
||||
.build();
|
||||
gadgetInfo.setWorktop(worktop);
|
||||
}
|
||||
|
||||
entityInfo.setGadget(gadgetInfo);
|
||||
|
||||
return entityInfo.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.ProtoHelper;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
|
||||
public class EntityItem extends EntityGadget {
|
||||
public class EntityItem extends EntityBaseGadget {
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.common.PropGrowCurve;
|
||||
import emu.grasscutter.data.def.MonsterCurveData;
|
||||
import emu.grasscutter.data.def.MonsterData;
|
||||
import emu.grasscutter.game.dungeons.DungeonChallenge;
|
||||
import emu.grasscutter.game.props.EntityIdType;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
@@ -22,6 +23,7 @@ import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
|
||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||
import emu.grasscutter.net.proto.SceneMonsterInfoOuterClass.SceneMonsterInfo;
|
||||
import emu.grasscutter.net.proto.SceneWeaponInfoOuterClass.SceneWeaponInfo;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.ProtoHelper;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||
@@ -36,9 +38,6 @@ public class EntityMonster extends GameEntity {
|
||||
private final Position bornPos;
|
||||
private final int level;
|
||||
private int weaponEntityId;
|
||||
|
||||
private int groupId;
|
||||
private int configId;
|
||||
private int poseId;
|
||||
|
||||
public EntityMonster(Scene scene, MonsterData monsterData, Position pos, int level) {
|
||||
@@ -103,22 +102,6 @@ public class EntityMonster extends GameEntity {
|
||||
public boolean isAlive() {
|
||||
return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f;
|
||||
}
|
||||
|
||||
public int getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(int groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public int getConfigId() {
|
||||
return configId;
|
||||
}
|
||||
|
||||
public void setConfigId(int configId) {
|
||||
this.configId = configId;
|
||||
}
|
||||
|
||||
public int getPoseId() {
|
||||
return poseId;
|
||||
@@ -127,12 +110,18 @@ public class EntityMonster extends GameEntity {
|
||||
public void setPoseId(int poseId) {
|
||||
this.poseId = poseId;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDeath(int killerId) {
|
||||
if (this.getSpawnEntry() != null) {
|
||||
this.getScene().getDeadSpawnedEntities().add(getSpawnEntry());
|
||||
}
|
||||
if (getScene().getScriptManager().isInit() && this.getGroupId() > 0) {
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, null);
|
||||
}
|
||||
if (getScene().getChallenge() != null && getScene().getChallenge().getGroup().id == this.getGroupId()) {
|
||||
getScene().getChallenge().onMonsterDie(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void recalcStats() {
|
||||
|
||||
@@ -18,24 +18,30 @@ import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||
import emu.grasscutter.net.proto.VehicleInfoOuterClass.*;
|
||||
|
||||
import emu.grasscutter.net.proto.VehicleMemberOuterClass.*;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.ProtoHelper;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
|
||||
public class EntityVehicle extends EntityGadget {
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class EntityVehicle extends EntityBaseGadget {
|
||||
|
||||
private final Player owner;
|
||||
private final Int2FloatOpenHashMap fightProp;
|
||||
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
|
||||
private float curStamina;
|
||||
private final int pointId;
|
||||
private final int gadgetId;
|
||||
|
||||
private float curStamina;
|
||||
private List<VehicleMember> vehicleMembers;
|
||||
|
||||
public EntityVehicle(Scene scene, Player player, int gadgetId, int pointId, Position pos, Position rot) {
|
||||
super(scene);
|
||||
this.owner = player;
|
||||
@@ -46,6 +52,7 @@ public class EntityVehicle extends EntityGadget {
|
||||
this.gadgetId = gadgetId;
|
||||
this.pointId = pointId;
|
||||
this.curStamina = 240;
|
||||
this.vehicleMembers = new ArrayList<VehicleMember>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,6 +68,8 @@ public class EntityVehicle extends EntityGadget {
|
||||
|
||||
public int getPointId() { return pointId; }
|
||||
|
||||
public List<VehicleMember> getVehicleMembers() { return vehicleMembers; }
|
||||
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
return fightProp;
|
||||
|
||||
@@ -17,6 +17,10 @@ public abstract class GameEntity {
|
||||
private final Scene scene;
|
||||
private SpawnDataEntry spawnEntry;
|
||||
|
||||
private int blockId;
|
||||
private int configId;
|
||||
private int groupId;
|
||||
|
||||
private MotionState moveState;
|
||||
private int lastMoveSceneTimeMs;
|
||||
private int lastMoveReliableSeq;
|
||||
@@ -96,6 +100,30 @@ public abstract class GameEntity {
|
||||
return getFightProperties().getOrDefault(prop.getId(), 0f);
|
||||
}
|
||||
|
||||
public int getBlockId() {
|
||||
return blockId;
|
||||
}
|
||||
|
||||
public void setBlockId(int blockId) {
|
||||
this.blockId = blockId;
|
||||
}
|
||||
|
||||
public int getConfigId() {
|
||||
return configId;
|
||||
}
|
||||
|
||||
public void setConfigId(int configId) {
|
||||
this.configId = configId;
|
||||
}
|
||||
|
||||
public int getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(int groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
protected MotionInfo getMotionInfo() {
|
||||
MotionInfo proto = MotionInfo.newBuilder()
|
||||
.setPos(getPosition().toProto())
|
||||
|
||||
@@ -244,6 +244,10 @@ public class GameItem {
|
||||
return mainPropId;
|
||||
}
|
||||
|
||||
public void setMainPropId(int mainPropId) {
|
||||
this.mainPropId = mainPropId;
|
||||
}
|
||||
|
||||
public List<Integer> getAppendPropIdList() {
|
||||
return appendPropIdList;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.def.AvatarSkillDepotData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.game.entity.EntityBaseGadget;
|
||||
import emu.grasscutter.game.props.ElementType;
|
||||
import emu.grasscutter.game.props.EnterReason;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
@@ -54,7 +54,7 @@ public class TeamManager {
|
||||
@Transient private TeamInfo mpTeam;
|
||||
@Transient private int entityId;
|
||||
@Transient private final List<EntityAvatar> avatars;
|
||||
@Transient private final Set<EntityGadget> gadgets;
|
||||
@Transient private final Set<EntityBaseGadget> gadgets;
|
||||
@Transient private final IntSet teamResonances;
|
||||
@Transient private final IntSet teamResonancesConfig;
|
||||
|
||||
@@ -141,7 +141,7 @@ public class TeamManager {
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
public Set<EntityGadget> getGadgets() {
|
||||
public Set<EntityBaseGadget> getGadgets() {
|
||||
return gadgets;
|
||||
}
|
||||
|
||||
|
||||
93
src/main/java/emu/grasscutter/game/props/EntityType.java
Normal file
93
src/main/java/emu/grasscutter/game/props/EntityType.java
Normal file
@@ -0,0 +1,93 @@
|
||||
package emu.grasscutter.game.props;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
public enum EntityType {
|
||||
None (0),
|
||||
Avatar (1),
|
||||
Monster (2),
|
||||
Bullet (3),
|
||||
AttackPhyisicalUnit (4),
|
||||
AOE (5),
|
||||
Camera (6),
|
||||
EnviroArea (7),
|
||||
Equip (8),
|
||||
MonsterEquip (9),
|
||||
Grass (10),
|
||||
Level (11),
|
||||
NPC (12),
|
||||
TransPointFirst (13),
|
||||
TransPointFirstGadget (14),
|
||||
TransPointSecond (15),
|
||||
TransPointSecondGadget (16),
|
||||
DropItem (17),
|
||||
Field (18),
|
||||
Gadget (19),
|
||||
Water (20),
|
||||
GatherPoint (21),
|
||||
GatherObject (22),
|
||||
AirflowField (23),
|
||||
SpeedupField (24),
|
||||
Gear (25),
|
||||
Chest (26),
|
||||
EnergyBall (27),
|
||||
ElemCrystal (28),
|
||||
Timeline (29),
|
||||
Worktop (30),
|
||||
Team (31),
|
||||
Platform (32),
|
||||
AmberWind (33),
|
||||
EnvAnimal (34),
|
||||
SealGadget (35),
|
||||
Tree (36),
|
||||
Bush (37),
|
||||
QuestGadget (38),
|
||||
Lightning (39),
|
||||
RewardPoint (40),
|
||||
RewardStatue (41),
|
||||
MPLevel (42),
|
||||
WindSeed (43),
|
||||
MpPlayRewardPoint (44),
|
||||
ViewPoint (45),
|
||||
RemoteAvatar (46),
|
||||
GeneralRewardPoint (47),
|
||||
PlayTeam (48),
|
||||
OfferingGadget (49),
|
||||
EyePoint (50),
|
||||
MiracleRing (51),
|
||||
Foundation (52),
|
||||
WidgetGadget (53),
|
||||
PlaceHolder (99);
|
||||
|
||||
private final int value;
|
||||
private static final Int2ObjectMap<EntityType> map = new Int2ObjectOpenHashMap<>();
|
||||
private static final Map<String, EntityType> stringMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
Stream.of(values()).forEach(e -> {
|
||||
map.put(e.getValue(), e);
|
||||
stringMap.put(e.name(), e);
|
||||
});
|
||||
}
|
||||
|
||||
private EntityType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static EntityType getTypeByValue(int value) {
|
||||
return map.getOrDefault(value, None);
|
||||
}
|
||||
|
||||
public static EntityType getTypeByName(String name) {
|
||||
return stringMap.getOrDefault(name, None);
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,11 @@ package emu.grasscutter.game.world;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.GameDepot;
|
||||
import emu.grasscutter.data.def.DungeonData;
|
||||
import emu.grasscutter.data.def.MonsterData;
|
||||
import emu.grasscutter.data.def.SceneData;
|
||||
import emu.grasscutter.data.def.WorldLevelData;
|
||||
import emu.grasscutter.game.dungeons.DungeonChallenge;
|
||||
import emu.grasscutter.game.entity.*;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.player.TeamInfo;
|
||||
@@ -17,6 +19,13 @@ import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
||||
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
|
||||
import emu.grasscutter.scripts.SceneScriptManager;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.scripts.data.SceneBlock;
|
||||
import emu.grasscutter.scripts.data.SceneGadget;
|
||||
import emu.grasscutter.scripts.data.SceneGroup;
|
||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||
import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify;
|
||||
@@ -36,12 +45,19 @@ public class Scene {
|
||||
|
||||
private final Set<SpawnDataEntry> spawnedEntities;
|
||||
private final Set<SpawnDataEntry> deadSpawnedEntities;
|
||||
private final Set<SceneBlock> loadedBlocks;
|
||||
private boolean dontDestroyWhenEmpty;
|
||||
|
||||
private int time;
|
||||
private ClimateType climate;
|
||||
private int weather;
|
||||
|
||||
|
||||
private SceneScriptManager scriptManager;
|
||||
private DungeonChallenge challenge;
|
||||
private DungeonData dungeonData;
|
||||
private int prevScene; // Id of the previous scene
|
||||
private int prevScenePoint;
|
||||
|
||||
public Scene(World world, SceneData sceneData) {
|
||||
this.world = world;
|
||||
this.sceneData = sceneData;
|
||||
@@ -50,9 +66,12 @@ public class Scene {
|
||||
|
||||
this.time = 8 * 60;
|
||||
this.climate = ClimateType.CLIMATE_SUNNY;
|
||||
this.prevScene = 3;
|
||||
|
||||
this.spawnedEntities = new HashSet<>();
|
||||
this.deadSpawnedEntities = new HashSet<>();
|
||||
this.loadedBlocks = new HashSet<>();
|
||||
this.scriptManager = new SceneScriptManager(this);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
@@ -111,6 +130,22 @@ public class Scene {
|
||||
this.weather = weather;
|
||||
}
|
||||
|
||||
public int getPrevScene() {
|
||||
return prevScene;
|
||||
}
|
||||
|
||||
public void setPrevScene(int prevScene) {
|
||||
this.prevScene = prevScene;
|
||||
}
|
||||
|
||||
public int getPrevScenePoint() {
|
||||
return prevScenePoint;
|
||||
}
|
||||
|
||||
public void setPrevScenePoint(int prevPoint) {
|
||||
this.prevScenePoint = prevPoint;
|
||||
}
|
||||
|
||||
public boolean dontDestroyWhenEmpty() {
|
||||
return dontDestroyWhenEmpty;
|
||||
}
|
||||
@@ -119,6 +154,10 @@ public class Scene {
|
||||
this.dontDestroyWhenEmpty = dontDestroyWhenEmpty;
|
||||
}
|
||||
|
||||
public Set<SceneBlock> getLoadedBlocks() {
|
||||
return loadedBlocks;
|
||||
}
|
||||
|
||||
public Set<SpawnDataEntry> getSpawnedEntities() {
|
||||
return spawnedEntities;
|
||||
}
|
||||
@@ -127,6 +166,29 @@ public class Scene {
|
||||
return deadSpawnedEntities;
|
||||
}
|
||||
|
||||
public SceneScriptManager getScriptManager() {
|
||||
return scriptManager;
|
||||
}
|
||||
|
||||
public DungeonData getDungeonData() {
|
||||
return dungeonData;
|
||||
}
|
||||
|
||||
public void setDungeonData(DungeonData dungeonData) {
|
||||
if (this.dungeonData != null || this.getSceneType() != SceneType.SCENE_DUNGEON || dungeonData.getSceneId() != this.getId()) {
|
||||
return;
|
||||
}
|
||||
this.dungeonData = dungeonData;
|
||||
}
|
||||
|
||||
public DungeonChallenge getChallenge() {
|
||||
return challenge;
|
||||
}
|
||||
|
||||
public void setChallenge(DungeonChallenge challenge) {
|
||||
this.challenge = challenge;
|
||||
}
|
||||
|
||||
public boolean isInScene(GameEntity entity) {
|
||||
return this.entities.containsKey(entity.getId());
|
||||
}
|
||||
@@ -151,6 +213,11 @@ public class Scene {
|
||||
}
|
||||
|
||||
public synchronized void removePlayer(Player player) {
|
||||
// Remove from challenge if leaving
|
||||
if (this.getChallenge() != null && this.getChallenge().inProgress()) {
|
||||
player.sendPacket(new PacketDungeonChallengeFinishNotify(this.getChallenge()));
|
||||
}
|
||||
|
||||
// Remove player from scene
|
||||
getPlayers().remove(player);
|
||||
player.setScene(null);
|
||||
@@ -159,12 +226,12 @@ public class Scene {
|
||||
this.removePlayerAvatars(player);
|
||||
|
||||
// Remove player gadgets
|
||||
for (EntityGadget gadget : player.getTeamManager().getGadgets()) {
|
||||
for (EntityBaseGadget gadget : player.getTeamManager().getGadgets()) {
|
||||
this.removeEntity(gadget);
|
||||
}
|
||||
|
||||
// Deregister scene if not in use
|
||||
if (this.getEntities().size() <= 0 && !this.dontDestroyWhenEmpty()) {
|
||||
if (this.getPlayerCount() <= 0 && !this.dontDestroyWhenEmpty()) {
|
||||
this.getWorld().deregisterScene(this);
|
||||
}
|
||||
}
|
||||
@@ -279,6 +346,11 @@ public class Scene {
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if (target.getFightProperties() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Lose hp
|
||||
target.addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, -result.getDamage());
|
||||
|
||||
@@ -314,7 +386,15 @@ public class Scene {
|
||||
}
|
||||
|
||||
public void onTick() {
|
||||
this.checkSpawns();
|
||||
if (this.getScriptManager().isInit()) {
|
||||
this.checkBlocks();
|
||||
} else {
|
||||
// TEMPORARY
|
||||
this.checkSpawns();
|
||||
}
|
||||
|
||||
// Triggers
|
||||
this.getScriptManager().onTick();
|
||||
}
|
||||
|
||||
// TODO - Test
|
||||
@@ -387,6 +467,68 @@ public class Scene {
|
||||
}
|
||||
}
|
||||
|
||||
public void checkBlocks() {
|
||||
Set<SceneBlock> visible = new HashSet<>();
|
||||
|
||||
for (Player player : this.getPlayers()) {
|
||||
for (SceneBlock block : getScriptManager().getBlocks()) {
|
||||
if (!block.contains(player.getPos())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
visible.add(block);
|
||||
}
|
||||
}
|
||||
|
||||
Iterator<SceneBlock> it = this.getLoadedBlocks().iterator();
|
||||
while (it.hasNext()) {
|
||||
SceneBlock block = it.next();
|
||||
|
||||
if (!visible.contains(block)) {
|
||||
it.remove();
|
||||
|
||||
onUnloadBlock(block);
|
||||
}
|
||||
}
|
||||
|
||||
for (SceneBlock block : visible) {
|
||||
if (!this.getLoadedBlocks().contains(block)) {
|
||||
this.onLoadBlock(block);
|
||||
this.getLoadedBlocks().add(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO optimize
|
||||
public void onLoadBlock(SceneBlock block) {
|
||||
for (SceneGroup group : block.groups) {
|
||||
// We load the script files for the groups here
|
||||
if (!group.isLoaded()) {
|
||||
this.getScriptManager().loadGroupFromScript(group);
|
||||
}
|
||||
|
||||
group.triggers.forEach(getScriptManager()::registerTrigger);
|
||||
}
|
||||
|
||||
// Spawn gadgets AFTER triggers are added
|
||||
for (SceneGroup group : block.groups) {
|
||||
this.getScriptManager().spawnGadgetsInGroup(group);
|
||||
}
|
||||
}
|
||||
|
||||
public void onUnloadBlock(SceneBlock block) {
|
||||
List<GameEntity> toRemove = this.getEntities().values().stream().filter(e -> e.getBlockId() == block.id).toList();
|
||||
|
||||
if (toRemove.size() > 0) {
|
||||
toRemove.stream().forEach(this::removeEntityDirectly);
|
||||
this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, VisionType.VISION_REMOVE));
|
||||
}
|
||||
|
||||
for (SceneGroup group : block.groups) {
|
||||
group.triggers.forEach(getScriptManager()::deregisterTrigger);
|
||||
}
|
||||
}
|
||||
|
||||
// Gadgets
|
||||
|
||||
public void onPlayerCreateGadget(EntityClientGadget gadget) {
|
||||
|
||||
@@ -17,14 +17,16 @@ import emu.grasscutter.game.props.EntityIdType;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.props.LifeState;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.DungeonData;
|
||||
import emu.grasscutter.data.def.SceneData;
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.entity.EntityClientGadget;
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.game.entity.EntityBaseGadget;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
||||
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
|
||||
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
|
||||
import emu.grasscutter.scripts.data.SceneConfig;
|
||||
import emu.grasscutter.server.packet.send.PacketDelTeamEntityNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify;
|
||||
@@ -212,6 +214,14 @@ public class World implements Iterable<Player> {
|
||||
}
|
||||
|
||||
public boolean transferPlayerToScene(Player player, int sceneId, Position pos) {
|
||||
return transferPlayerToScene(player, sceneId, null, pos);
|
||||
}
|
||||
|
||||
public boolean transferPlayerToScene(Player player, int sceneId, DungeonData data) {
|
||||
return transferPlayerToScene(player, sceneId, data, null);
|
||||
}
|
||||
|
||||
public boolean transferPlayerToScene(Player player, int sceneId, DungeonData dungeonData, Position pos) {
|
||||
if (GameData.getSceneDataMap().get(sceneId) == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -224,25 +234,51 @@ public class World implements Iterable<Player> {
|
||||
// Dont deregister scenes if the player is going to tp back into them
|
||||
if (oldScene.getId() == sceneId) {
|
||||
oldScene.setDontDestroyWhenEmpty(true);
|
||||
}
|
||||
}
|
||||
|
||||
oldScene.removePlayer(player);
|
||||
}
|
||||
|
||||
Scene newScene = this.getSceneById(sceneId);
|
||||
newScene.setDungeonData(dungeonData);
|
||||
newScene.addPlayer(player);
|
||||
player.getPos().set(pos);
|
||||
|
||||
// Dungeon
|
||||
SceneConfig config = newScene.getScriptManager().getConfig();
|
||||
if (pos == null && config != null) {
|
||||
if (config.born_pos != null) {
|
||||
pos = newScene.getScriptManager().getConfig().born_pos;
|
||||
}
|
||||
if (config.born_rot != null) {
|
||||
player.getRotation().set(config.born_rot);
|
||||
}
|
||||
}
|
||||
|
||||
// Set player position
|
||||
if (pos == null) {
|
||||
pos = player.getPos();
|
||||
}
|
||||
|
||||
player.getPos().set(pos);
|
||||
|
||||
if (oldScene != null) {
|
||||
newScene.setPrevScene(oldScene.getId());
|
||||
oldScene.setDontDestroyWhenEmpty(false);
|
||||
}
|
||||
|
||||
// Teleport packet
|
||||
if (oldScene == newScene) {
|
||||
player.sendPacket(new PacketPlayerEnterSceneNotify(player, EnterType.ENTER_GOTO, EnterReason.TransPoint, sceneId, pos));
|
||||
} else {
|
||||
player.sendPacket(new PacketPlayerEnterSceneNotify(player, EnterType.ENTER_JUMP, EnterReason.TransPoint, sceneId, pos));
|
||||
// Get enter types
|
||||
EnterType enterType = EnterType.ENTER_JUMP;
|
||||
EnterReason enterReason = EnterReason.TransPoint;
|
||||
|
||||
if (dungeonData != null) {
|
||||
enterType = EnterType.ENTER_DUNGEON;
|
||||
enterReason = EnterReason.DungeonEnter;
|
||||
} else if (oldScene == newScene) {
|
||||
enterType = EnterType.ENTER_GOTO;
|
||||
}
|
||||
|
||||
// Teleport packet
|
||||
player.sendPacket(new PacketPlayerEnterSceneNotify(player, enterType, enterReason, sceneId, pos));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user