mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-12-14 07:55:57 +01:00
feat: implement home animals (#2329)
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
package emu.grasscutter.game.entity;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.HomeWorldAnimalData;
|
||||
import emu.grasscutter.game.props.ElementType;
|
||||
import emu.grasscutter.game.world.Position;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.proto.VisionTypeOuterClass;
|
||||
import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketSceneEntityDisappearNotify;
|
||||
import lombok.Getter;
|
||||
|
||||
public class EntityHomeAnimal extends EntityMonster implements Rebornable {
|
||||
private int rebornCDTickCount;
|
||||
private final Position rebornPos;
|
||||
@Getter
|
||||
private final int rebirth;
|
||||
@Getter
|
||||
private final int rebirthCD;
|
||||
private boolean disappeared;
|
||||
|
||||
public EntityHomeAnimal(Scene scene, HomeWorldAnimalData data, Position pos) {
|
||||
super(scene, GameData.getMonsterDataMap().get(data.getMonsterID()), pos, 1);
|
||||
|
||||
this.rebornPos = pos.clone();
|
||||
this.rebirth = data.getIsRebirth();
|
||||
this.rebirthCD = data.getRebirthCD();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage(float amount, int killerId, ElementType attackType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTick(int sceneTime) {
|
||||
super.onTick(sceneTime);
|
||||
|
||||
if (this.isInCD()) {
|
||||
this.rebornCDTickCount--;
|
||||
if (this.rebornCDTickCount <= 0) {
|
||||
this.reborn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getRebornPos() {
|
||||
return this.rebornPos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRebornCD() {
|
||||
return this.rebirthCD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAiKillSelf() {
|
||||
this.getScene().broadcastPacket(new PacketSceneEntityDisappearNotify(this, VisionTypeOuterClass.VisionType.VISION_TYPE_REMOVE));
|
||||
this.rebornCDTickCount = this.getRebornCD();
|
||||
this.disappeared = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reborn() {
|
||||
if (this.disappeared) {
|
||||
this.disappeared = false;
|
||||
this.getPosition().set(this.getRebornPos());
|
||||
this.getScene().broadcastPacket(new PacketSceneEntityAppearNotify(this));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInCD() {
|
||||
return this.disappeared;
|
||||
}
|
||||
}
|
||||
15
src/main/java/emu/grasscutter/game/entity/Rebornable.java
Normal file
15
src/main/java/emu/grasscutter/game/entity/Rebornable.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package emu.grasscutter.game.entity;
|
||||
|
||||
import emu.grasscutter.game.world.Position;
|
||||
|
||||
public interface Rebornable {
|
||||
Position getRebornPos();
|
||||
|
||||
int getRebornCD();
|
||||
|
||||
void onAiKillSelf();
|
||||
|
||||
void reborn();
|
||||
|
||||
boolean isInCD();
|
||||
}
|
||||
61
src/main/java/emu/grasscutter/game/home/HomeScene.java
Normal file
61
src/main/java/emu/grasscutter/game/home/HomeScene.java
Normal file
@@ -0,0 +1,61 @@
|
||||
package emu.grasscutter.game.home;
|
||||
|
||||
import emu.grasscutter.data.excels.scene.SceneData;
|
||||
import emu.grasscutter.game.entity.GameEntity;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.server.packet.send.PacketSceneTimeNotify;
|
||||
|
||||
public class HomeScene extends Scene {
|
||||
public HomeScene(HomeWorld world, SceneData sceneData) {
|
||||
super(world, sceneData);
|
||||
this.setDontDestroyWhenEmpty(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPaused() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HomeWorld getWorld() {
|
||||
return (HomeWorld) super.getWorld();
|
||||
}
|
||||
|
||||
public GameHome getHome() {
|
||||
return this.getWorld().getHome();
|
||||
}
|
||||
|
||||
public HomeSceneItem getSceneItem() {
|
||||
return this.getHome().getHomeSceneItem(this.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPaused(boolean paused) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTick() {
|
||||
this.getEntities().values().forEach(gameEntity -> gameEntity.onTick(this.getSceneTimeSeconds()));
|
||||
|
||||
this.finishLoading();
|
||||
this.checkPlayerRespawn();
|
||||
if (this.tickCount++ % 10 == 0) this.broadcastPacket(new PacketSceneTimeNotify(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkNpcGroup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkSpawns() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addItemEntity(int itemId, int amount, GameEntity bornForm) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadNpcForPlayerEnter(Player player) {
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,17 @@
|
||||
package emu.grasscutter.game.home;
|
||||
|
||||
import dev.morphia.annotations.*;
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Id;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.binout.HomeworldDefaultSaveData;
|
||||
import emu.grasscutter.game.entity.EntityHomeAnimal;
|
||||
import emu.grasscutter.game.world.Position;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.proto.HomeSceneArrangementInfoOuterClass.HomeSceneArrangementInfo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.*;
|
||||
@@ -71,6 +78,19 @@ public class HomeSceneItem {
|
||||
return mainHouse == null || mainHouse.getAsItem() == null;
|
||||
}
|
||||
|
||||
public List<EntityHomeAnimal> getAnimals(Scene scene) {
|
||||
return this.blockItems.values().stream()
|
||||
.map(HomeBlockItem::getDeployAnimalList)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(homeAnimalItem -> GameData.getHomeWorldAnimalDataMap().containsKey(homeAnimalItem.getFurnitureId()))
|
||||
.map(homeAnimalItem -> {
|
||||
return new EntityHomeAnimal(scene,
|
||||
GameData.getHomeWorldAnimalDataMap().get(homeAnimalItem.getFurnitureId()),
|
||||
homeAnimalItem.getSpawnPos());
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
public int calComfort() {
|
||||
return this.blockItems.values().stream().mapToInt(HomeBlockItem::calComfort).sum();
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package emu.grasscutter.game.home;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.game.entity.EntityTeam;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.world.*;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.game.world.World;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.proto.ChatInfoOuterClass;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
|
||||
import emu.grasscutter.server.packet.send.*;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
@@ -20,6 +23,21 @@ public class HomeWorld extends World {
|
||||
server.registerHomeWorld(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerScene(Scene scene) {
|
||||
this.addAnimalsToScene((HomeScene) scene);
|
||||
super.registerScene(scene);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deregisterScene(Scene scene) {
|
||||
super.deregisterScene(scene);
|
||||
}
|
||||
|
||||
private void addAnimalsToScene(HomeScene scene) {
|
||||
scene.getSceneItem().getAnimals(scene).forEach(scene::addEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addPlayer(Player player) {
|
||||
// Check if player already in
|
||||
@@ -117,6 +135,23 @@ public class HomeWorld extends World {
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HomeScene getSceneById(int sceneId) {
|
||||
var scene = this.getScenes().get(sceneId);
|
||||
if (scene instanceof HomeScene homeScene) {
|
||||
return homeScene;
|
||||
}
|
||||
|
||||
var sceneData = GameData.getSceneDataMap().get(sceneId);
|
||||
if (sceneData != null) {
|
||||
scene = new HomeScene(this, sceneData);
|
||||
this.registerScene(scene);
|
||||
return (HomeScene) scene;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextPeerId() {
|
||||
return this.getPlayers().size() + 1;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package emu.grasscutter.game.world;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.*;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.GameDepot;
|
||||
import emu.grasscutter.data.binout.SceneNpcBornEntry;
|
||||
import emu.grasscutter.data.binout.routes.Route;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
@@ -11,14 +12,16 @@ import emu.grasscutter.data.excels.scene.SceneData;
|
||||
import emu.grasscutter.data.excels.world.WorldLevelData;
|
||||
import emu.grasscutter.data.server.Grid;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.dungeons.*;
|
||||
import emu.grasscutter.game.dungeons.DungeonManager;
|
||||
import emu.grasscutter.game.dungeons.DungeonSettleListener;
|
||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
|
||||
import emu.grasscutter.game.entity.*;
|
||||
import emu.grasscutter.game.entity.gadget.GadgetWorktop;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.managers.blossom.BlossomManager;
|
||||
import emu.grasscutter.game.player.*;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.player.TeamInfo;
|
||||
import emu.grasscutter.game.props.*;
|
||||
import emu.grasscutter.game.quest.QuestGroupSuite;
|
||||
import emu.grasscutter.game.world.data.TeleportProperties;
|
||||
@@ -26,22 +29,27 @@ import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.proto.*;
|
||||
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
||||
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
|
||||
import emu.grasscutter.scripts.*;
|
||||
import emu.grasscutter.scripts.SceneIndexManager;
|
||||
import emu.grasscutter.scripts.SceneScriptManager;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.scripts.data.*;
|
||||
import emu.grasscutter.scripts.data.SceneBlock;
|
||||
import emu.grasscutter.scripts.data.SceneGroup;
|
||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||
import emu.grasscutter.server.event.entity.EntityCreationEvent;
|
||||
import emu.grasscutter.server.event.player.PlayerTeleportEvent;
|
||||
import emu.grasscutter.server.packet.send.*;
|
||||
import emu.grasscutter.server.scheduler.ServerTaskScheduler;
|
||||
import emu.grasscutter.utils.objects.KahnsSort;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nullable;
|
||||
import lombok.*;
|
||||
|
||||
public final class Scene {
|
||||
public class Scene {
|
||||
@Getter private final World world;
|
||||
@Getter private final SceneData sceneData;
|
||||
@Getter private final List<Player> players;
|
||||
@@ -66,7 +74,7 @@ public final class Scene {
|
||||
@Getter @Setter private int killedMonsterCount;
|
||||
private Set<SceneNpcBornEntry> npcBornEntrySet;
|
||||
@Getter private boolean finishedLoading = false;
|
||||
@Getter private int tickCount = 0;
|
||||
@Getter protected int tickCount = 0;
|
||||
@Getter private boolean isPaused = false;
|
||||
|
||||
private final List<Runnable> afterLoadedCallbacks = new ArrayList<>();
|
||||
@@ -456,7 +464,10 @@ public final class Scene {
|
||||
public void showOtherEntities(Player player) {
|
||||
GameEntity currentEntity = player.getTeamManager().getCurrentAvatarEntity();
|
||||
List<GameEntity> entities =
|
||||
this.getEntities().values().stream().filter(entity -> entity != currentEntity).toList();
|
||||
this.getEntities().values().stream()
|
||||
.filter(entity -> entity != currentEntity)
|
||||
.filter(gameEntity -> !(gameEntity instanceof Rebornable rebornable) || !rebornable.isInCD())
|
||||
.toList();
|
||||
|
||||
player.sendPacket(new PacketSceneEntityAppearNotify(entities, VisionType.VISION_TYPE_MEET));
|
||||
}
|
||||
@@ -583,7 +594,7 @@ public final class Scene {
|
||||
}
|
||||
|
||||
/** Validates a player's current position. Teleports the player if the player is out of bounds. */
|
||||
private void checkPlayerRespawn() {
|
||||
protected void checkPlayerRespawn() {
|
||||
if (this.getScriptManager().getConfig() == null) return;
|
||||
var diePos = this.getScriptManager().getConfig().die_y;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user