mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-23 13:37:42 +00:00
add region entity
This commit is contained in:
parent
e499601283
commit
7e7f1e11e0
74
src/main/java/emu/grasscutter/game/entity/EntityRegion.java
Normal file
74
src/main/java/emu/grasscutter/game/entity/EntityRegion.java
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package emu.grasscutter.game.entity;
|
||||||
|
|
||||||
|
import emu.grasscutter.game.props.EntityIdType;
|
||||||
|
import emu.grasscutter.game.world.Scene;
|
||||||
|
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass;
|
||||||
|
import emu.grasscutter.scripts.data.SceneRegion;
|
||||||
|
import emu.grasscutter.utils.Position;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class EntityRegion extends GameEntity{
|
||||||
|
private final Position position;
|
||||||
|
private boolean hasNewEntities;
|
||||||
|
private final Set<Integer> entities; // Ids of entities inside this region
|
||||||
|
private final SceneRegion metaRegion;
|
||||||
|
|
||||||
|
public EntityRegion(Scene scene, SceneRegion region) {
|
||||||
|
super(scene);
|
||||||
|
this.id = getScene().getWorld().getNextEntityId(EntityIdType.REGION);
|
||||||
|
setGroupId(region.group.id);
|
||||||
|
setBlockId(region.group.block_id);
|
||||||
|
setConfigId(region.config_id);
|
||||||
|
this.position = region.pos.clone();
|
||||||
|
this.entities = ConcurrentHashMap.newKeySet();
|
||||||
|
this.metaRegion = region;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addEntity(GameEntity entity) {
|
||||||
|
if (this.getEntities().contains(entity.getId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.getEntities().add(entity.getId());
|
||||||
|
this.hasNewEntities = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNewEntities() {
|
||||||
|
return hasNewEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetNewEntities() {
|
||||||
|
hasNewEntities = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeEntity(GameEntity entity) {
|
||||||
|
this.getEntities().remove(entity.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Int2FloatOpenHashMap getFightProperties() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Position getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Position getRotation() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SceneEntityInfoOuterClass.SceneEntityInfo toProto() {
|
||||||
|
/**
|
||||||
|
* The Region Entity would not be sent to client.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -5,10 +5,11 @@ public enum EntityIdType {
|
|||||||
MONSTER (0x02),
|
MONSTER (0x02),
|
||||||
NPC (0x03),
|
NPC (0x03),
|
||||||
GADGET (0x04),
|
GADGET (0x04),
|
||||||
WEAPON (0x06),
|
REGION (0x05),
|
||||||
|
WEAPON (0x06),
|
||||||
TEAM (0x09),
|
TEAM (0x09),
|
||||||
MPLEVEL (0x0b);
|
MPLEVEL (0x0b);
|
||||||
|
|
||||||
private final int id;
|
private final int id;
|
||||||
|
|
||||||
private EntityIdType(int id) {
|
private EntityIdType(int id) {
|
||||||
|
@ -30,24 +30,25 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
|||||||
import org.danilopianini.util.SpatialIndex;
|
import org.danilopianini.util.SpatialIndex;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class Scene {
|
public class Scene {
|
||||||
private final World world;
|
private final World world;
|
||||||
private final SceneData sceneData;
|
private final SceneData sceneData;
|
||||||
private final List<Player> players;
|
private final List<Player> players;
|
||||||
private final Int2ObjectMap<GameEntity> entities;
|
private final Map<Integer, GameEntity> entities;
|
||||||
|
|
||||||
private final Set<SpawnDataEntry> spawnedEntities;
|
private final Set<SpawnDataEntry> spawnedEntities;
|
||||||
private final Set<SpawnDataEntry> deadSpawnedEntities;
|
private final Set<SpawnDataEntry> deadSpawnedEntities;
|
||||||
private final Set<SceneBlock> loadedBlocks;
|
private final Set<SceneBlock> loadedBlocks;
|
||||||
private boolean dontDestroyWhenEmpty;
|
private boolean dontDestroyWhenEmpty;
|
||||||
|
|
||||||
private int autoCloseTime;
|
private int autoCloseTime;
|
||||||
private int time;
|
private int time;
|
||||||
private ClimateType climate;
|
private ClimateType climate;
|
||||||
private int weather;
|
private int weather;
|
||||||
|
|
||||||
private SceneScriptManager scriptManager;
|
private SceneScriptManager scriptManager;
|
||||||
private WorldChallenge challenge;
|
private WorldChallenge challenge;
|
||||||
private List<DungeonSettleListener> dungeonSettleListeners;
|
private List<DungeonSettleListener> dungeonSettleListeners;
|
||||||
@ -57,19 +58,19 @@ public class Scene {
|
|||||||
public Scene(World world, SceneData sceneData) {
|
public Scene(World world, SceneData sceneData) {
|
||||||
this.world = world;
|
this.world = world;
|
||||||
this.sceneData = sceneData;
|
this.sceneData = sceneData;
|
||||||
this.players = Collections.synchronizedList(new ArrayList<>());
|
this.players = new CopyOnWriteArrayList<>();
|
||||||
this.entities = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>());
|
this.entities = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
this.time = 8 * 60;
|
this.time = 8 * 60;
|
||||||
this.climate = ClimateType.CLIMATE_SUNNY;
|
this.climate = ClimateType.CLIMATE_SUNNY;
|
||||||
this.prevScene = 3;
|
this.prevScene = 3;
|
||||||
|
|
||||||
this.spawnedEntities = new HashSet<>();
|
this.spawnedEntities = ConcurrentHashMap.newKeySet();
|
||||||
this.deadSpawnedEntities = new HashSet<>();
|
this.deadSpawnedEntities = ConcurrentHashMap.newKeySet();
|
||||||
this.loadedBlocks = new HashSet<>();
|
this.loadedBlocks = ConcurrentHashMap.newKeySet();
|
||||||
this.scriptManager = new SceneScriptManager(this);
|
this.scriptManager = new SceneScriptManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return sceneData.getId();
|
return sceneData.getId();
|
||||||
}
|
}
|
||||||
@ -89,15 +90,15 @@ public class Scene {
|
|||||||
public List<Player> getPlayers() {
|
public List<Player> getPlayers() {
|
||||||
return players;
|
return players;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPlayerCount() {
|
public int getPlayerCount() {
|
||||||
return this.getPlayers().size();
|
return this.getPlayers().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Int2ObjectMap<GameEntity> getEntities() {
|
public Map<Integer, GameEntity> getEntities() {
|
||||||
return entities;
|
return entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameEntity getEntityById(int id) {
|
public GameEntity getEntityById(int id) {
|
||||||
return this.entities.get(id);
|
return this.entities.get(id);
|
||||||
}
|
}
|
||||||
@ -629,15 +630,10 @@ public class Scene {
|
|||||||
var suiteData = group.getSuiteByIndex(suite);
|
var suiteData = group.getSuiteByIndex(suite);
|
||||||
suiteData.sceneTriggers.forEach(getScriptManager()::registerTrigger);
|
suiteData.sceneTriggers.forEach(getScriptManager()::registerTrigger);
|
||||||
|
|
||||||
entities.addAll(suiteData.sceneGadgets.stream()
|
entities.addAll(scriptManager.getGadgetsInGroupSuite(group, suiteData));
|
||||||
.map(g -> scriptManager.createGadget(group.id, group.block_id, g))
|
entities.addAll(scriptManager.getMonstersInGroupSuite(group, suiteData));
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.toList());
|
|
||||||
entities.addAll(suiteData.sceneMonsters.stream()
|
|
||||||
.map(mob -> scriptManager.createMonster(group.id, group.block_id, mob))
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.toList());
|
|
||||||
|
|
||||||
|
scriptManager.registerRegionInGroupSuite(group, suiteData);
|
||||||
}
|
}
|
||||||
|
|
||||||
scriptManager.meetEntities(entities);
|
scriptManager.meetEntities(entities);
|
||||||
@ -654,19 +650,18 @@ public class Scene {
|
|||||||
toRemove.forEach(this::removeEntityDirectly);
|
toRemove.forEach(this::removeEntityDirectly);
|
||||||
this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, VisionType.VISION_TYPE_REMOVE));
|
this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, VisionType.VISION_TYPE_REMOVE));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (SceneGroup group : block.groups.values()) {
|
for (SceneGroup group : block.groups.values()) {
|
||||||
if(group.triggers != null){
|
if(group.triggers != null){
|
||||||
group.triggers.values().forEach(getScriptManager()::deregisterTrigger);
|
group.triggers.values().forEach(getScriptManager()::deregisterTrigger);
|
||||||
}
|
}
|
||||||
if(group.regions != null){
|
if(group.regions != null){
|
||||||
group.regions.forEach(getScriptManager()::deregisterRegion);
|
group.regions.values().forEach(getScriptManager()::deregisterRegion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scriptManager.getLoadedGroupSetPerBlock().remove(block.id);
|
scriptManager.getLoadedGroupSetPerBlock().remove(block.id);
|
||||||
Grasscutter.getLogger().info("Scene {} Block {} is unloaded.", this.getId(), block.id);
|
Grasscutter.getLogger().info("Scene {} Block {} is unloaded.", this.getId(), block.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gadgets
|
// Gadgets
|
||||||
|
|
||||||
public void onPlayerCreateGadget(EntityClientGadget gadget) {
|
public void onPlayerCreateGadget(EntityClientGadget gadget) {
|
||||||
|
@ -6,10 +6,7 @@ import emu.grasscutter.Grasscutter;
|
|||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.excels.MonsterData;
|
import emu.grasscutter.data.excels.MonsterData;
|
||||||
import emu.grasscutter.data.excels.WorldLevelData;
|
import emu.grasscutter.data.excels.WorldLevelData;
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.*;
|
||||||
import emu.grasscutter.game.entity.EntityMonster;
|
|
||||||
import emu.grasscutter.game.entity.EntityNPC;
|
|
||||||
import emu.grasscutter.game.entity.GameEntity;
|
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.net.proto.VisionTypeOuterClass;
|
import emu.grasscutter.net.proto.VisionTypeOuterClass;
|
||||||
import emu.grasscutter.scripts.constants.EventType;
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
@ -17,17 +14,12 @@ import emu.grasscutter.scripts.data.*;
|
|||||||
import emu.grasscutter.scripts.service.ScriptMonsterSpawnService;
|
import emu.grasscutter.scripts.service.ScriptMonsterSpawnService;
|
||||||
import emu.grasscutter.scripts.service.ScriptMonsterTideService;
|
import emu.grasscutter.scripts.service.ScriptMonsterTideService;
|
||||||
import io.netty.util.concurrent.FastThreadLocalThread;
|
import io.netty.util.concurrent.FastThreadLocalThread;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
|
||||||
import org.luaj.vm2.LuaError;
|
import org.luaj.vm2.LuaError;
|
||||||
import org.luaj.vm2.LuaValue;
|
import org.luaj.vm2.LuaValue;
|
||||||
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
|
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.LinkedBlockingDeque;
|
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class SceneScriptManager {
|
public class SceneScriptManager {
|
||||||
@ -38,15 +30,15 @@ public class SceneScriptManager {
|
|||||||
/**
|
/**
|
||||||
* current triggers controlled by RefreshGroup
|
* current triggers controlled by RefreshGroup
|
||||||
*/
|
*/
|
||||||
private final Int2ObjectOpenHashMap<Set<SceneTrigger>> currentTriggers;
|
private final Map<Integer, Set<SceneTrigger>> currentTriggers;
|
||||||
private final Int2ObjectOpenHashMap<SceneRegion> regions;
|
private final Map<Integer, EntityRegion> regions; // <EntityId-Region>
|
||||||
private Map<Integer,SceneGroup> sceneGroups;
|
private final Map<Integer,SceneGroup> sceneGroups;
|
||||||
private ScriptMonsterTideService scriptMonsterTideService;
|
private ScriptMonsterTideService scriptMonsterTideService;
|
||||||
private ScriptMonsterSpawnService scriptMonsterSpawnService;
|
private ScriptMonsterSpawnService scriptMonsterSpawnService;
|
||||||
/**
|
/**
|
||||||
* blockid - loaded groupSet
|
* blockid - loaded groupSet
|
||||||
*/
|
*/
|
||||||
private Int2ObjectMap<Set<SceneGroup>> loadedGroupSetPerBlock;
|
private final Map<Integer, Set<SceneGroup>> loadedGroupSetPerBlock;
|
||||||
public static final ExecutorService eventExecutor;
|
public static final ExecutorService eventExecutor;
|
||||||
static {
|
static {
|
||||||
eventExecutor = new ThreadPoolExecutor(4, 4,
|
eventExecutor = new ThreadPoolExecutor(4, 4,
|
||||||
@ -55,23 +47,23 @@ public class SceneScriptManager {
|
|||||||
}
|
}
|
||||||
public SceneScriptManager(Scene scene) {
|
public SceneScriptManager(Scene scene) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.currentTriggers = new Int2ObjectOpenHashMap<>();
|
this.currentTriggers = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
this.regions = new Int2ObjectOpenHashMap<>();
|
this.regions = new ConcurrentHashMap<>();
|
||||||
this.variables = new HashMap<>();
|
this.variables = new ConcurrentHashMap<>();
|
||||||
this.sceneGroups = new HashMap<>();
|
this.sceneGroups = new ConcurrentHashMap<>();
|
||||||
this.scriptMonsterSpawnService = new ScriptMonsterSpawnService(this);
|
this.scriptMonsterSpawnService = new ScriptMonsterSpawnService(this);
|
||||||
this.loadedGroupSetPerBlock = new Int2ObjectOpenHashMap<>();
|
this.loadedGroupSetPerBlock = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
// TEMPORARY
|
// TEMPORARY
|
||||||
if (this.getScene().getId() < 10 && !Grasscutter.getConfig().server.game.enableScriptInBigWorld) {
|
if (this.getScene().getId() < 10 && !Grasscutter.getConfig().server.game.enableScriptInBigWorld) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Scene getScene() {
|
public Scene getScene() {
|
||||||
return scene;
|
return scene;
|
||||||
}
|
}
|
||||||
@ -123,19 +115,25 @@ public class SceneScriptManager {
|
|||||||
spawnMonstersInGroup(group, suite);
|
spawnMonstersInGroup(group, suite);
|
||||||
spawnGadgetsInGroup(group, suite);
|
spawnGadgetsInGroup(group, suite);
|
||||||
}
|
}
|
||||||
public SceneRegion getRegionById(int id) {
|
public EntityRegion getRegionById(int id) {
|
||||||
return regions.get(id);
|
return regions.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerRegion(SceneRegion region) {
|
public void registerRegion(EntityRegion region) {
|
||||||
regions.put(region.config_id, region);
|
regions.put(region.getId(), region);
|
||||||
}
|
}
|
||||||
|
public void registerRegionInGroupSuite(SceneGroup group, SceneSuite suite){
|
||||||
public void deregisterRegion(SceneRegion region) {
|
suite.sceneRegions.stream().map(region -> new EntityRegion(this.getScene(), region))
|
||||||
regions.remove(region.config_id);
|
.forEach(this::registerRegion);
|
||||||
|
}
|
||||||
|
public synchronized void deregisterRegion(SceneRegion region) {
|
||||||
|
var instance = regions.values().stream()
|
||||||
|
.filter(r -> r.getConfigId() == region.config_id)
|
||||||
|
.findFirst();
|
||||||
|
instance.ifPresent(entityRegion -> regions.remove(entityRegion.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Int2ObjectMap<Set<SceneGroup>> getLoadedGroupSetPerBlock() {
|
public Map<Integer, Set<SceneGroup>> getLoadedGroupSetPerBlock() {
|
||||||
return loadedGroupSetPerBlock;
|
return loadedGroupSetPerBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,53 +180,61 @@ public class SceneScriptManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.sceneGroups.put(group.id, group);
|
this.sceneGroups.put(group.id, group);
|
||||||
|
|
||||||
if(group.regions != null){
|
|
||||||
group.regions.forEach(this::registerRegion);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkRegions() {
|
public void checkRegions() {
|
||||||
if (this.regions.size() == 0) {
|
if (this.regions.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (SceneRegion region : this.regions.values()) {
|
for (var region : this.regions.values()) {
|
||||||
getScene().getEntities().values()
|
getScene().getEntities().values()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(e -> e.getEntityType() <= 2 && region.contains(e.getPosition()))
|
.filter(e -> e.getEntityType() <= 2 && region.getMetaRegion().contains(e.getPosition()))
|
||||||
.forEach(region::addEntity);
|
.forEach(region::addEntity);
|
||||||
|
|
||||||
if (region.hasNewEntities()) {
|
if (region.hasNewEntities()) {
|
||||||
// This is not how it works, source_eid should be region entity id, but we dont have an entity for regions yet
|
callEvent(EventType.EVENT_ENTER_REGION, new ScriptArgs(region.getConfigId()).setSourceEntityId(region.getId()));
|
||||||
callEvent(EventType.EVENT_ENTER_REGION, new ScriptArgs(region.config_id).setSourceEntityId(region.config_id));
|
|
||||||
|
|
||||||
region.resetNewEntities();
|
region.resetNewEntities();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<EntityGadget> getGadgetsInGroupSuite(SceneGroup group, SceneSuite suite){
|
||||||
|
return suite.sceneGadgets.stream()
|
||||||
|
.map(g -> createGadget(group.id, group.block_id, g))
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
public List<EntityMonster> getMonstersInGroupSuite(SceneGroup group, SceneSuite suite){
|
||||||
|
return suite.sceneMonsters.stream()
|
||||||
|
.map(mob -> createMonster(group.id, group.block_id, mob))
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
public void addGroupSuite(SceneGroup group, SceneSuite suite){
|
public void addGroupSuite(SceneGroup group, SceneSuite suite){
|
||||||
spawnMonstersInGroup(group, suite);
|
// we added trigger first
|
||||||
spawnGadgetsInGroup(group, suite);
|
registerTrigger(suite.sceneTriggers);
|
||||||
registerTrigger(suite.sceneTriggers);
|
|
||||||
|
var toCreate = new ArrayList<GameEntity>();
|
||||||
|
toCreate.addAll(getGadgetsInGroupSuite(group, suite));
|
||||||
|
toCreate.addAll(getMonstersInGroupSuite(group, suite));
|
||||||
|
addEntities(toCreate);
|
||||||
|
|
||||||
|
registerRegionInGroupSuite(group, suite);
|
||||||
}
|
}
|
||||||
public void removeGroupSuite(SceneGroup group, SceneSuite suite){
|
public void removeGroupSuite(SceneGroup group, SceneSuite suite){
|
||||||
|
deregisterTrigger(suite.sceneTriggers);
|
||||||
removeMonstersInGroup(group, suite);
|
removeMonstersInGroup(group, suite);
|
||||||
removeGadgetsInGroup(group, suite);
|
removeGadgetsInGroup(group, suite);
|
||||||
deregisterTrigger(suite.sceneTriggers);
|
|
||||||
|
suite.sceneRegions.forEach(this::deregisterRegion);
|
||||||
}
|
}
|
||||||
public void spawnGadgetsInGroup(SceneGroup group, int suiteIndex) {
|
|
||||||
spawnGadgetsInGroup(group, group.getSuiteByIndex(suiteIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void spawnGadgetsInGroup(SceneGroup group) {
|
|
||||||
spawnGadgetsInGroup(group, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void spawnGadgetsInGroup(SceneGroup group, SceneSuite suite) {
|
public void spawnGadgetsInGroup(SceneGroup group, SceneSuite suite) {
|
||||||
var gadgets = group.gadgets.values();
|
var gadgets = group.gadgets.values();
|
||||||
|
|
||||||
if (suite != null) {
|
if (suite != null) {
|
||||||
gadgets = suite.sceneGadgets;
|
gadgets = suite.sceneGadgets;
|
||||||
}
|
}
|
||||||
@ -240,13 +246,6 @@ public class SceneScriptManager {
|
|||||||
this.addEntities(toCreate);
|
this.addEntities(toCreate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void spawnMonstersInGroup(SceneGroup group, int suiteIndex) {
|
|
||||||
var suite = group.getSuiteByIndex(suiteIndex);
|
|
||||||
if(suite == null){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
spawnMonstersInGroup(group, suite);
|
|
||||||
}
|
|
||||||
public void spawnMonstersInGroup(SceneGroup group, SceneSuite suite) {
|
public void spawnMonstersInGroup(SceneGroup group, SceneSuite suite) {
|
||||||
if(suite == null || suite.sceneMonsters.size() <= 0){
|
if(suite == null || suite.sceneMonsters.size() <= 0){
|
||||||
return;
|
return;
|
||||||
@ -254,11 +253,6 @@ public class SceneScriptManager {
|
|||||||
this.addEntities(suite.sceneMonsters.stream()
|
this.addEntities(suite.sceneMonsters.stream()
|
||||||
.map(mob -> createMonster(group.id, group.block_id, mob)).toList());
|
.map(mob -> createMonster(group.id, group.block_id, mob)).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void spawnMonstersInGroup(SceneGroup group) {
|
|
||||||
this.addEntities(group.monsters.values().stream()
|
|
||||||
.map(mob -> createMonster(group.id, group.block_id, mob)).toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startMonsterTideInGroup(SceneGroup group, Integer[] ordersConfigId, int tideCount, int sceneLimit) {
|
public void startMonsterTideInGroup(SceneGroup group, Integer[] ordersConfigId, int tideCount, int sceneLimit) {
|
||||||
this.scriptMonsterTideService =
|
this.scriptMonsterTideService =
|
||||||
|
@ -309,22 +309,22 @@ public class ScriptLib {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetRegionEntityCount(LuaTable table) {
|
public int GetRegionEntityCount(LuaTable table) {
|
||||||
logger.debug("[LUA] Call GetRegionEntityCount with {}",
|
logger.debug("[LUA] Call GetRegionEntityCount with {}",
|
||||||
printTable(table));
|
printTable(table));
|
||||||
int regionId = table.get("region_eid").toint();
|
int regionId = table.get("region_eid").toint();
|
||||||
int entityType = table.get("entity_type").toint();
|
int entityType = table.get("entity_type").toint();
|
||||||
|
|
||||||
SceneRegion region = this.getSceneScriptManager().getRegionById(regionId);
|
var region = this.getSceneScriptManager().getRegionById(regionId);
|
||||||
|
|
||||||
if (region == null) {
|
if (region == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int) region.getEntities().intStream().filter(e -> e >> 24 == entityType).count();
|
return (int) region.getEntities().stream().filter(e -> e >> 24 == entityType).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PrintContextLog(String msg) {
|
public void PrintContextLog(String msg) {
|
||||||
logger.info("[LUA] " + msg);
|
logger.info("[LUA] " + msg);
|
||||||
}
|
}
|
||||||
|
@ -34,10 +34,10 @@ public class SceneGroup {
|
|||||||
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, SceneNPC> npc; // <NpcId, NPC>
|
public Map<Integer, SceneNPC> npc; // <NpcId, NPC>
|
||||||
public List<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;
|
||||||
@ -115,9 +115,12 @@ public class SceneGroup {
|
|||||||
triggers.values().forEach(t -> t.currentGroup = this);
|
triggers.values().forEach(t -> t.currentGroup = this);
|
||||||
|
|
||||||
suites = ScriptLoader.getSerializer().toList(SceneSuite.class, bindings.get("suites"));
|
suites = ScriptLoader.getSerializer().toList(SceneSuite.class, bindings.get("suites"));
|
||||||
regions = ScriptLoader.getSerializer().toList(SceneRegion.class, bindings.get("regions"));
|
regions = ScriptLoader.getSerializer().toList(SceneRegion.class, bindings.get("regions")).stream()
|
||||||
|
.collect(Collectors.toMap(x -> x.config_id, y -> y));
|
||||||
|
regions.values().forEach(m -> m.group = this);
|
||||||
|
|
||||||
init_config = ScriptLoader.getSerializer().toObject(SceneInitConfig.class, bindings.get("init_config"));
|
init_config = ScriptLoader.getSerializer().toObject(SceneInitConfig.class, bindings.get("init_config"));
|
||||||
|
|
||||||
// Garbages TODO fix properly later
|
// Garbages TODO fix properly later
|
||||||
Object garbagesValue = bindings.get("garbages");
|
Object garbagesValue = bindings.get("garbages");
|
||||||
if (garbagesValue != null && garbagesValue instanceof LuaValue garbagesTable) {
|
if (garbagesValue != null && garbagesValue instanceof LuaValue garbagesTable) {
|
||||||
@ -157,12 +160,19 @@ public class SceneGroup {
|
|||||||
.map(triggers::get)
|
.map(triggers::get)
|
||||||
.toList()
|
.toList()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
suite.sceneRegions = new ArrayList<>(
|
||||||
|
suite.regions.stream()
|
||||||
|
.filter(regions::containsKey)
|
||||||
|
.map(regions::get)
|
||||||
|
.toList()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (ScriptException e) {
|
} catch (ScriptException e) {
|
||||||
Grasscutter.getLogger().error("Error loading group " + id + " in scene " + sceneId, e);
|
Grasscutter.getLogger().error("Error loading group " + id + " in scene " + sceneId, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Grasscutter.getLogger().info("group {} in scene {} is loaded successfully.", id, sceneId);
|
Grasscutter.getLogger().info("group {} in scene {} is loaded successfully.", id, sceneId);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -1,62 +1,34 @@
|
|||||||
package emu.grasscutter.scripts.data;
|
package emu.grasscutter.scripts.data;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.GameEntity;
|
|
||||||
import emu.grasscutter.scripts.constants.ScriptRegionShape;
|
import emu.grasscutter.scripts.constants.ScriptRegionShape;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
@ToString
|
|
||||||
@Setter
|
@Setter
|
||||||
public class SceneRegion {
|
public class SceneRegion {
|
||||||
public int config_id;
|
public int config_id;
|
||||||
public int shape;
|
public int shape;
|
||||||
public Position pos;
|
public Position pos;
|
||||||
|
// for CUBIC
|
||||||
public Position size;
|
public Position size;
|
||||||
|
// for SPHERE
|
||||||
private boolean hasNewEntities;
|
public int radius;
|
||||||
private final IntSet entities; // Ids of entities inside this region
|
|
||||||
|
|
||||||
public SceneRegion() {
|
|
||||||
this.entities = new IntOpenHashSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IntSet getEntities() {
|
|
||||||
return entities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addEntity(GameEntity entity) {
|
public transient SceneGroup group;
|
||||||
if (this.getEntities().contains(entity.getId())) {
|
public boolean contains(Position position) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.getEntities().add(entity.getId());
|
|
||||||
this.hasNewEntities = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeEntity(GameEntity entity) {
|
|
||||||
this.getEntities().remove(entity.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(Position p) {
|
|
||||||
switch (shape) {
|
switch (shape) {
|
||||||
case ScriptRegionShape.CUBIC:
|
case ScriptRegionShape.CUBIC:
|
||||||
return (Math.abs(pos.getX() - p.getX()) <= size.getX()) &&
|
return (Math.abs(pos.getX() - position.getX()) <= size.getX()) &&
|
||||||
(Math.abs(pos.getZ() - p.getZ()) <= size.getZ());
|
(Math.abs(pos.getY() - position.getY()) <= size.getY()) &&
|
||||||
|
(Math.abs(pos.getZ() - position.getZ()) <= size.getZ());
|
||||||
case ScriptRegionShape.SPHERE:
|
case ScriptRegionShape.SPHERE:
|
||||||
return false;
|
var x = Math.pow(pos.getX() - position.getX(), 2);
|
||||||
|
var y = Math.pow(pos.getY() - position.getY(), 2);
|
||||||
|
var z = Math.pow(pos.getZ() - position.getZ(), 2);
|
||||||
|
return x + y + z <= (radius ^ 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasNewEntities() {
|
|
||||||
return hasNewEntities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetNewEntities() {
|
|
||||||
hasNewEntities = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,12 @@ public class SceneSuite {
|
|||||||
public List<Integer> monsters;
|
public List<Integer> monsters;
|
||||||
public List<Integer> gadgets;
|
public List<Integer> gadgets;
|
||||||
public List<String> triggers;
|
public List<String> triggers;
|
||||||
public int rand_weight;
|
public List<Integer> regions;
|
||||||
|
public int rand_weight;
|
||||||
|
|
||||||
public transient List<SceneMonster> sceneMonsters;
|
public transient List<SceneMonster> sceneMonsters;
|
||||||
public transient List<SceneGadget> sceneGadgets;
|
public transient List<SceneGadget> sceneGadgets;
|
||||||
public transient List<SceneTrigger> sceneTriggers;
|
public transient List<SceneTrigger> sceneTriggers;
|
||||||
|
public transient List<SceneRegion> sceneRegions;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user