Merge branch 'dev-world-scripts' of https://github.com/Grasscutters/Grasscutter into dev-world-scripts

This commit is contained in:
Melledy 2022-05-18 02:24:00 -07:00
commit 73a88b2da2
14 changed files with 382 additions and 64 deletions

135
data/ChestReward.json Normal file
View File

@ -0,0 +1,135 @@
[
{
"objNames" : [
"SceneObj_Chest_Default_Lv1",
"SceneObj_Chest_Locked_Lv1",
"SceneObj_Chest_Bramble_Lv1",
"SceneObj_Chest_Frozen_Lv1",
"SceneObj_Chest_Rock_Lv1",
"SceneObj_EssenceChest_Default_Lv1",
"SceneObj_EssenceChest_Locked_Lv1"
],
"advExp" : 10,
"resin" : 0,
"mora" : 257,
"sigil" : 1,
"content" : [
{
"itemId" : 104011,
"count": 3
},
{
"itemId" : 104001,
"count": 1
}
],
"randomCount": 4,
"randomContent": [
{
"itemId" : 11101,
"count": 1
},
{
"itemId" : 11201,
"count": 1
},
{
"itemId" : 12101,
"count": 1
},
{
"itemId" : 12201,
"count": 1
},
{
"itemId" : 13101,
"count": 1
},
{
"itemId" : 13201,
"count": 1
},
{
"itemId" : 14101,
"count": 1
},
{
"itemId" : 14201,
"count": 1
},
{
"itemId" : 15101,
"count": 1
},
{
"itemId" : 15201,
"count": 1
}
]
},
{
"objNames" : [
"SceneObj_Chest_Default_Lv2",
"SceneObj_Chest_Locked_Lv2",
"SceneObj_Chest_Bramble_Lv2",
"SceneObj_Chest_Frozen_Lv2"
],
"advExp" : 20,
"resin" : 2,
"mora" : 756,
"sigil" : 2,
"content" : [
{
"itemId" : 104012,
"count": 3
},
{
"itemId" : 104002,
"count": 1
}
],
"randomCount": 4,
"randomContent": [
{
"itemId" : 11201,
"count": 1
},
{
"itemId" : 11301,
"count": 1
},
{
"itemId" : 12201,
"count": 1
},
{
"itemId" : 12301,
"count": 1
},
{
"itemId" : 13201,
"count": 1
},
{
"itemId" : 13301,
"count": 1
},
{
"itemId" : 14201,
"count": 1
},
{
"itemId" : 14301,
"count": 1
},
{
"itemId" : 15201,
"count": 1
},
{
"itemId" : 15301,
"count": 1
}
]
}
]

View File

@ -1,23 +1,21 @@
package emu.grasscutter.game.entity; package emu.grasscutter.game.entity;
import java.util.Arrays; import emu.grasscutter.Grasscutter;
import java.util.List;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.def.GadgetData; import emu.grasscutter.data.def.GadgetData;
import emu.grasscutter.game.entity.gadget.GadgetContent; import emu.grasscutter.game.entity.gadget.GadgetContent;
import emu.grasscutter.game.entity.gadget.GadgetGatherPoint; import emu.grasscutter.game.entity.gadget.GadgetGatherPoint;
import emu.grasscutter.game.entity.gadget.GadgetRewardStatue; import emu.grasscutter.game.entity.gadget.GadgetRewardStatue;
import emu.grasscutter.game.entity.gadget.GadgetWorktop; import emu.grasscutter.game.entity.gadget.GadgetWorktop;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.EntityIdType; import emu.grasscutter.game.props.EntityIdType;
import emu.grasscutter.game.props.EntityType; import emu.grasscutter.game.props.EntityType;
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.game.world.World;
import emu.grasscutter.net.proto.ClientGadgetInfoOuterClass;
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.BossChestInfoOuterClass;
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;
@ -32,11 +30,14 @@ import emu.grasscutter.net.proto.WorktopInfoOuterClass.WorktopInfo;
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.Int2FloatOpenHashMap; 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.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.IntSet;
import lombok.ToString;
import java.util.Arrays;
import java.util.Random;
@ToString(callSuper = true)
public class EntityGadget extends EntityBaseGadget { public class EntityGadget extends EntityBaseGadget {
private final GadgetData data; private final GadgetData data;
private final Position pos; private final Position pos;
@ -175,4 +176,30 @@ public class EntityGadget extends EntityBaseGadget {
return entityInfo.build(); return entityInfo.build();
} }
public void openChest(Player player) {
var chestRewardMap = getScene().getWorld().getServer().getWorldDataManager().getChestRewardMap();
var chestReward = chestRewardMap.get(this.getGadgetData().getJsonName());
if(chestReward == null){
Grasscutter.getLogger().warn("Could not found the config of this type of Chests {}", this.getGadgetData().getJsonName());
return;
}
player.earnExp(chestReward.getAdvExp());
player.getInventory().addItem(201, chestReward.getResin());
var mora = chestReward.getMora() * (1 + (player.getWorldLevel() - 1) * 0.5);
player.getInventory().addItem(202, (int)mora);
for(int i=0;i<chestReward.getContent().size();i++){
getScene().addItemEntity(chestReward.getContent().get(i).getItemId(), chestReward.getContent().get(i).getCount(), this);
}
var random = new Random(System.currentTimeMillis());
for(int i=0;i<chestReward.getRandomCount();i++){
var index = random.nextInt(chestReward.getRandomContent().size());
var item = chestReward.getRandomContent().get(index);
getScene().addItemEntity(item.getItemId(), item.getCount(), this);
}
}
} }

View File

@ -4,12 +4,10 @@ import emu.grasscutter.data.GameData;
import emu.grasscutter.data.common.PropGrowCurve; import emu.grasscutter.data.common.PropGrowCurve;
import emu.grasscutter.data.def.MonsterCurveData; import emu.grasscutter.data.def.MonsterCurveData;
import emu.grasscutter.data.def.MonsterData; import emu.grasscutter.data.def.MonsterData;
import emu.grasscutter.game.dungeons.DungeonChallenge;
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.game.world.World;
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;
@ -24,6 +22,7 @@ import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
import emu.grasscutter.net.proto.SceneMonsterInfoOuterClass.SceneMonsterInfo; import emu.grasscutter.net.proto.SceneMonsterInfoOuterClass.SceneMonsterInfo;
import emu.grasscutter.net.proto.SceneWeaponInfoOuterClass.SceneWeaponInfo; import emu.grasscutter.net.proto.SceneWeaponInfoOuterClass.SceneWeaponInfo;
import emu.grasscutter.scripts.constants.EventType; import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.ScriptArgs;
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;
@ -126,7 +125,9 @@ public class EntityMonster extends GameEntity {
} }
// prevent spawn monster after success // prevent spawn monster after success
if(getScene().getChallenge() != null && getScene().getChallenge().inProgress()){ if(getScene().getChallenge() != null && getScene().getChallenge().inProgress()){
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, null); getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, new ScriptArgs().setParam1(this.getConfigId()));
}else if(getScene().getChallenge() == null){
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, new ScriptArgs().setParam1(this.getConfigId()));
} }
} }
} }

View File

@ -47,6 +47,7 @@ import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo;
import emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo; import emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo;
import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture; import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture;
import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail; import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
import emu.grasscutter.scripts.constants.ScriptGadgetState;
import emu.grasscutter.server.event.player.PlayerJoinEvent; import emu.grasscutter.server.event.player.PlayerJoinEvent;
import emu.grasscutter.server.event.player.PlayerQuitEvent; import emu.grasscutter.server.event.player.PlayerQuitEvent;
import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.game.GameServer;
@ -927,6 +928,13 @@ public class Player {
if (shouldDelete) { if (shouldDelete) {
entity.getScene().removeEntity(entity); entity.getScene().removeEntity(entity);
} }
else if (gadget.getGadgetData().getType() == EntityType.Chest) {
getScene().updateGadgetState(gadget, ScriptGadgetState.ChestOpened);
gadget.openChest(this);
this.sendPacket(new PacketGadgetInteractRsp(gadget, InteractType.INTERACT_OPEN_CHEST));
getScene().killEntity(gadget, 0);
}
} else { } else {
// Delete directly // Delete directly
entity.getScene().removeEntity(entity); entity.getScene().removeEntity(entity);

View File

@ -0,0 +1,22 @@
package emu.grasscutter.game.world;
import emu.grasscutter.game.inventory.ItemDef;
import lombok.AccessLevel;
import lombok.Data;
import lombok.experimental.FieldDefaults;
import java.util.List;
@Data
@FieldDefaults(level = AccessLevel.PRIVATE)
public class ChestReward {
List<String> objNames;
int advExp;
int resin;
int mora;
int sigil;
List<ItemDef> content;
int randomCount;
List<ItemDef> randomContent;
}

View File

@ -3,10 +3,7 @@ package emu.grasscutter.game.world;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameDepot; import emu.grasscutter.data.GameDepot;
import emu.grasscutter.data.def.DungeonData; import emu.grasscutter.data.def.*;
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.dungeons.DungeonChallenge;
import emu.grasscutter.game.dungeons.DungeonSettleListener; import emu.grasscutter.game.dungeons.DungeonSettleListener;
import emu.grasscutter.game.entity.*; import emu.grasscutter.game.entity.*;
@ -25,11 +22,8 @@ import emu.grasscutter.scripts.SceneScriptManager;
import emu.grasscutter.scripts.data.SceneBlock; import emu.grasscutter.scripts.data.SceneBlock;
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.server.packet.send.PacketAvatarSkillInfoNotify; import emu.grasscutter.server.packet.send.*;
import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify; import emu.grasscutter.utils.Position;
import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify;
import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify;
import emu.grasscutter.server.packet.send.PacketSceneEntityDisappearNotify;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
@ -38,6 +32,8 @@ import org.danilopianini.util.SpatialIndex;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static emu.grasscutter.utils.Language.translate;
public class Scene { public class Scene {
private final World world; private final World world;
private final SceneData sceneData; private final SceneData sceneData;
@ -595,8 +591,10 @@ public class Scene {
do { do {
var suiteData = group.getSuiteByIndex(suite); var suiteData = group.getSuiteByIndex(suite);
suiteData.sceneTriggers.forEach(getScriptManager()::registerTrigger);
entities.addAll(suiteData.sceneGadgets.stream() entities.addAll(suiteData.sceneGadgets.stream()
.map(g -> scriptManager.createGadgets(group.id, group.block_id, g)).toList()); .map(g -> scriptManager.createGadget(group.id, group.block_id, g)).toList());
entities.addAll(suiteData.sceneMonsters.stream() entities.addAll(suiteData.sceneMonsters.stream()
.map(mob -> scriptManager.createMonster(group.id, group.block_id, mob)).toList()); .map(mob -> scriptManager.createMonster(group.id, group.block_id, mob)).toList());
suite++; suite++;
@ -618,7 +616,7 @@ public class Scene {
for (SceneGroup group : block.groups) { for (SceneGroup group : block.groups) {
if(group.triggers != null){ if(group.triggers != null){
group.triggers.forEach(getScriptManager()::deregisterTrigger); group.triggers.values().forEach(getScriptManager()::deregisterTrigger);
} }
if(group.regions != null){ if(group.regions != null){
group.regions.forEach(getScriptManager()::deregisterRegion); group.regions.forEach(getScriptManager()::deregisterRegion);
@ -690,4 +688,27 @@ public class Scene {
player.getSession().send(packet); player.getSession().send(packet);
} }
} }
public void addItemEntity(int itemId, int amount, GameEntity bornForm){
ItemData itemData = GameData.getItemDataMap().get(itemId);
if (itemData == null) {
return;
}
if (itemData.isEquip()) {
float range = (3f + (.1f * amount));
for (int i = 0; i < amount; i++) {
Position pos = bornForm.getPosition().clone().addX((float) (Math.random() * range) - (range / 2)).addZ((float) (Math.random() * range) - (range / 2)).addZ(.9f);
EntityItem entity = new EntityItem(this, null, itemData, pos, 1);
addEntity(entity);
}
} else {
EntityItem entity = new EntityItem(this, null, itemData, bornForm.getPosition().clone().addZ(.9f), amount);
addEntity(entity);
}
}
public void updateGadgetState(EntityGadget gadget, int state){
gadget.setState(state);
broadcastPacket(new PacketGadgetStateNotify(gadget, state));
}
} }

View File

@ -0,0 +1,41 @@
package emu.grasscutter.game.world;
import com.google.gson.reflect.TypeToken;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.server.game.GameServer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static emu.grasscutter.Configuration.DATA;
public class WorldDataManager {
private final GameServer gameServer;
private final Map<String, ChestReward> chestRewardMap;
public WorldDataManager(GameServer gameServer){
this.gameServer = gameServer;
this.chestRewardMap = new HashMap<>();
load();
}
public synchronized void load(){
try {
List<ChestReward> chestReward = Grasscutter.getGsonFactory().fromJson(
Files.readString(Path.of(DATA("ChestReward.json"))),
TypeToken.getParameterized(List.class, ChestReward.class).getType());
chestReward.forEach(reward ->
reward.getObjNames().forEach(name -> chestRewardMap.put(name, reward)));
} catch (Exception e) {
Grasscutter.getLogger().error("Unable to load chest reward config.", e);
}
}
public Map<String, ChestReward> getChestRewardMap() {
return chestRewardMap;
}
}

View File

@ -42,7 +42,6 @@ public class SceneScriptManager {
private final Int2ObjectOpenHashMap<Set<SceneTrigger>> currentTriggers; private final Int2ObjectOpenHashMap<Set<SceneTrigger>> currentTriggers;
private final Int2ObjectOpenHashMap<SceneRegion> regions; private final Int2ObjectOpenHashMap<SceneRegion> regions;
private Map<Integer,SceneGroup> sceneGroups; private Map<Integer,SceneGroup> sceneGroups;
private SceneGroup currentGroup;
private ScriptMonsterTideService scriptMonsterTideService; private ScriptMonsterTideService scriptMonsterTideService;
private ScriptMonsterSpawnService scriptMonsterSpawnService; private ScriptMonsterSpawnService scriptMonsterSpawnService;
/** /**
@ -94,10 +93,6 @@ public class SceneScriptManager {
return meta.config; return meta.config;
} }
public SceneGroup getCurrentGroup() {
return currentGroup;
}
public Map<Integer, SceneBlock> getBlocks() { public Map<Integer, SceneBlock> getBlocks() {
return meta.blocks; return meta.blocks;
} }
@ -118,20 +113,19 @@ public class SceneScriptManager {
this.triggers.remove(trigger.name); this.triggers.remove(trigger.name);
getTriggersByEvent(trigger.event).remove(trigger); getTriggersByEvent(trigger.event).remove(trigger);
} }
public void resetTriggers(List<String> triggerNames) { public void resetTriggers(int eventId) {
for(var name : triggerNames){ currentTriggers.put(eventId, new HashSet<>());
var instance = triggers.get(name);
this.currentTriggers.get(instance.event).clear();
this.currentTriggers.get(instance.event).add(instance);
}
} }
public void refreshGroup(SceneGroup group, int suiteIndex){ public void refreshGroup(SceneGroup group, int suiteIndex){
var suite = group.getSuiteByIndex(suiteIndex); var suite = group.getSuiteByIndex(suiteIndex);
if(suite == null){ if(suite == null){
return; return;
} }
if(suite.triggers.size() > 0){ if(suite.sceneTriggers.size() > 0){
resetTriggers(suite.triggers); for(var trigger : suite.sceneTriggers){
resetTriggers(trigger.event);
this.currentTriggers.get(trigger.event).add(trigger);
}
} }
spawnMonstersInGroup(group, suite); spawnMonstersInGroup(group, suite);
spawnGadgetsInGroup(group, suite); spawnGadgetsInGroup(group, suite);
@ -158,7 +152,7 @@ public class SceneScriptManager {
for (SceneGroup group : block.groups) { for (SceneGroup group : block.groups) {
if (group.id == groupId) { if (group.id == groupId) {
if(!group.isLoaded()){ if(!group.isLoaded()){
loadGroupFromScript(group); getScene().onLoadGroup(List.of(group));
} }
return group; return group;
} }
@ -204,9 +198,6 @@ public class SceneScriptManager {
group.variables.forEach(var -> this.getVariables().put(var.name, var.value)); group.variables.forEach(var -> this.getVariables().put(var.name, var.value));
this.sceneGroups.put(group.id, group); this.sceneGroups.put(group.id, group);
if(group.triggers != null){
group.triggers.forEach(this::registerTrigger);
}
if(group.regions != null){ if(group.regions != null){
group.regions.forEach(this::registerRegion); group.regions.forEach(this::registerRegion);
} }
@ -248,7 +239,7 @@ public class SceneScriptManager {
} }
var toCreate = gadgets.stream() var toCreate = gadgets.stream()
.map(g -> createGadgets(g.groupId, group.block_id, g)) .map(g -> createGadget(g.groupId, group.block_id, g))
.filter(Objects::nonNull) .filter(Objects::nonNull)
.toList(); .toList();
this.addEntities(toCreate); this.addEntities(toCreate);
@ -265,20 +256,17 @@ public class SceneScriptManager {
if(suite == null || suite.sceneMonsters.size() <= 0){ if(suite == null || suite.sceneMonsters.size() <= 0){
return; return;
} }
this.currentGroup = group;
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) { public void spawnMonstersInGroup(SceneGroup group) {
this.currentGroup = group;
this.addEntities(group.monsters.values().stream() this.addEntities(group.monsters.values().stream()
.map(mob -> createMonster(group.id, group.block_id, mob)).toList()); .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.currentGroup = group;
this.scriptMonsterTideService = this.scriptMonsterTideService =
new ScriptMonsterTideService(this, group, tideCount, sceneLimit, ordersConfigId); new ScriptMonsterTideService(this, group, tideCount, sceneLimit, ordersConfigId);
@ -289,15 +277,15 @@ public class SceneScriptManager {
} }
this.getScriptMonsterTideService().unload(); this.getScriptMonsterTideService().unload();
} }
public void spawnMonstersByConfigId(int configId, int delayTime) { public void spawnMonstersByConfigId(SceneGroup group, int configId, int delayTime) {
// TODO delay // TODO delay
getScene().addEntity( getScene().addEntity(createMonster(group.id, group.block_id, group.monsters.get(configId)));
createMonster(this.currentGroup.id, this.currentGroup.block_id, this.currentGroup.monsters.get(configId)));
} }
// Events // Events
public void callEvent(int eventType, ScriptArgs params) { public void callEvent(int eventType, ScriptArgs params) {
for (SceneTrigger trigger : this.getTriggersByEvent(eventType)) { for (SceneTrigger trigger : this.getTriggersByEvent(eventType)) {
scriptLib.setCurrentGroup(trigger.currentGroup);
LuaValue condition = null; LuaValue condition = null;
if (trigger.condition != null && !trigger.condition.isEmpty()) { if (trigger.condition != null && !trigger.condition.isEmpty()) {
@ -330,6 +318,7 @@ public class SceneScriptManager {
safetyCall(trigger.action, action, args); safetyCall(trigger.action, action, args);
} }
//TODO some ret may not bool //TODO some ret may not bool
scriptLib.removeCurrentGroup();
} }
} }
@ -337,7 +326,7 @@ public class SceneScriptManager {
try{ try{
return func.call(this.getScriptLibLua(), args); return func.call(this.getScriptLibLua(), args);
}catch (LuaError error){ }catch (LuaError error){
ScriptLib.logger.error("[LUA] call trigger failed {},{}",name,args,error); ScriptLib.logger.error("[LUA] call trigger failed {},{},{}",name,args,error.getMessage());
return LuaValue.valueOf(-1); return LuaValue.valueOf(-1);
} }
} }
@ -350,7 +339,7 @@ public class SceneScriptManager {
return scriptMonsterSpawnService; return scriptMonsterSpawnService;
} }
public EntityGadget createGadgets(int groupId, int blockId, SceneGadget g) { public EntityGadget createGadget(int groupId, int blockId, SceneGadget g) {
EntityGadget entity = new EntityGadget(getScene(), g.gadget_id, g.pos); EntityGadget entity = new EntityGadget(getScene(), g.gadget_id, g.pos);
if (entity.getGadgetData() == null){ if (entity.getGadgetData() == null){

View File

@ -24,6 +24,7 @@ public class ScriptLib {
public ScriptLib(SceneScriptManager sceneScriptManager) { public ScriptLib(SceneScriptManager sceneScriptManager) {
this.sceneScriptManager = sceneScriptManager; this.sceneScriptManager = sceneScriptManager;
this.currentGroup = new ThreadLocal<>();
} }
public SceneScriptManager getSceneScriptManager() { public SceneScriptManager getSceneScriptManager() {
@ -39,7 +40,17 @@ public class ScriptLib {
sb.append("}"); sb.append("}");
return sb.toString(); return sb.toString();
} }
private final ThreadLocal<SceneGroup> currentGroup;
public void setCurrentGroup(SceneGroup currentGroup){
logger.debug("current {}", currentGroup);
this.currentGroup.set(currentGroup);
}
public Optional<SceneGroup> getCurrentGroup(){
return Optional.ofNullable(this.currentGroup.get());
}
public void removeCurrentGroup(){
this.currentGroup.remove();
}
public int SetGadgetStateByConfigId(int configId, int gadgetState) { public int SetGadgetStateByConfigId(int configId, int gadgetState) {
logger.debug("[LUA] Call SetGadgetStateByConfigId with {},{}", logger.debug("[LUA] Call SetGadgetStateByConfigId with {},{}",
configId,gadgetState); configId,gadgetState);
@ -103,6 +114,11 @@ public class ScriptLib {
return 0; return 0;
} }
public int SetWorktopOptions(LuaTable table){
logger.debug("[LUA] Call SetWorktopOptions with {}", printTable(table));
// TODO
return 0;
}
public int DelWorktopOptionByGroupId(int groupId, int configId, int option) { public int DelWorktopOptionByGroupId(int groupId, int configId, int option) {
logger.debug("[LUA] Call DelWorktopOptionByGroupId with {},{},{}",groupId,configId,option); logger.debug("[LUA] Call DelWorktopOptionByGroupId with {},{},{}",groupId,configId,option);
@ -273,7 +289,8 @@ public class ScriptLib {
var1); var1);
return (int) getSceneScriptManager().getScene().getEntities().values().stream() return (int) getSceneScriptManager().getScene().getEntities().values().stream()
.filter(e -> e instanceof EntityMonster && e.getGroupId() == getSceneScriptManager().getCurrentGroup().id) .filter(e -> e instanceof EntityMonster &&
e.getGroupId() == getCurrentGroup().map(sceneGroup -> sceneGroup.id).orElse(-1))
.count(); .count();
} }
public int SetMonsterBattleByGroup(int var1, int var2, int var3){ public int SetMonsterBattleByGroup(int var1, int var2, int var3){
@ -335,7 +352,11 @@ public class ScriptLib {
var configId = table.get("config_id").toint(); var configId = table.get("config_id").toint();
var delayTime = table.get("delay_time").toint(); var delayTime = table.get("delay_time").toint();
getSceneScriptManager().spawnMonstersByConfigId(configId, delayTime); if(getCurrentGroup().isEmpty()){
return 1;
}
getSceneScriptManager().spawnMonstersByConfigId(getCurrentGroup().get(), configId, delayTime);
return 0; return 0;
} }
@ -354,7 +375,13 @@ public class ScriptLib {
printTable(table)); printTable(table));
var configId = table.get("config_id").toint(); var configId = table.get("config_id").toint();
//TODO var group = getCurrentGroup();
if(group.isEmpty()){
return 1;
}
var gadget = group.get().gadgets.get(configId);
var entity = getSceneScriptManager().createGadget(group.get().id, group.get().block_id, gadget);
getSceneScriptManager().addEntity(entity);
return 0; return 0;
} }
@ -377,14 +404,42 @@ public class ScriptLib {
.filter(g -> g.getConfigId() == configId) .filter(g -> g.getConfigId() == configId)
.findFirst(); .findFirst();
if(gadget.isEmpty()){ if(gadget.isEmpty()){
return 1;
}
return ((EntityGadget)gadget.get()).getState();
}
public int MarkPlayerAction(int var1, int var2, int var3, int var4){
logger.debug("[LUA] Call MarkPlayerAction with {},{}",
var1, var2);
return 0; return 0;
} }
var stat = ((EntityGadget)gadget.get()).getState();
return stat; public int AddQuestProgress(String var1){
logger.debug("[LUA] Call AddQuestProgress with {}",
var1);
return 0;
}
/**
* change the state of gadget
*/
public int ChangeGroupGadget(LuaTable table){
logger.debug("[LUA] Call ChangeGroupGadget with {}",
printTable(table));
var configId = table.get("config_id").toint();
var state = table.get("state").toint();
var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId);
if(entity == null){
return 1;
}
if(entity instanceof EntityGadget entityGadget){
getSceneScriptManager().getScene().updateGadgetState(entityGadget, state);
} }
public int SetGadgetStateByConfigId(int configId, LuaTable gadgetState){
logger.debug("[LUA] Call SetGadgetStateByConfigId with {},{}",
configId, printTable(gadgetState));
return 0; return 0;
} }

View File

@ -2,6 +2,9 @@ package emu.grasscutter.scripts.constants;
public class EventType { public class EventType {
public static final int EVENT_NONE = 0; public static final int EVENT_NONE = 0;
/**
* param1: monster.configId
*/
public static final int EVENT_ANY_MONSTER_DIE = 1; public static final int EVENT_ANY_MONSTER_DIE = 1;
public static final int EVENT_ANY_GADGET_DIE = 2; public static final int EVENT_ANY_GADGET_DIE = 2;
public static final int EVENT_VARIABLE_CHANGE = 3; public static final int EVENT_VARIABLE_CHANGE = 3;

View File

@ -28,8 +28,8 @@ public class SceneGroup {
public Map<Integer,SceneMonster> monsters; // <ConfigId, Monster> public Map<Integer,SceneMonster> monsters; // <ConfigId, Monster>
public Map<Integer, SceneGadget> gadgets; // <ConfigId, Gadgets> public Map<Integer, SceneGadget> gadgets; // <ConfigId, Gadgets>
public Map<String, SceneTrigger> triggers;
public List<SceneTrigger> triggers;
public List<SceneRegion> regions; public List<SceneRegion> regions;
public List<SceneSuite> suites; public List<SceneSuite> suites;
public List<SceneVar> variables; public List<SceneVar> variables;
@ -94,8 +94,9 @@ public class SceneGroup {
.collect(Collectors.toMap(x -> x.config_id, y -> y)); .collect(Collectors.toMap(x -> x.config_id, y -> y));
gadgets.values().forEach(m -> m.groupId = id); gadgets.values().forEach(m -> m.groupId = id);
triggers = ScriptLoader.getSerializer().toList(SceneTrigger.class, bindings.get("triggers")); triggers = ScriptLoader.getSerializer().toList(SceneTrigger.class, bindings.get("triggers")).stream()
triggers.forEach(t -> t.currentGroup = this); .collect(Collectors.toMap(x -> x.name, y -> y));
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"));
@ -120,6 +121,13 @@ public class SceneGroup {
.map(gadgets::get) .map(gadgets::get)
.toList() .toList()
); );
suite.sceneTriggers = new ArrayList<>(
suite.triggers.stream()
.filter(triggers::containsKey)
.map(triggers::get)
.toList()
);
} }
} catch (ScriptException e) { } catch (ScriptException e) {

View File

@ -15,4 +15,5 @@ public class SceneSuite {
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;
} }

View File

@ -11,7 +11,7 @@ public class SceneTrigger {
public String condition; public String condition;
public String action; public String action;
public 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){

View File

@ -19,6 +19,7 @@ import emu.grasscutter.game.quest.ServerQuestHandler;
import emu.grasscutter.game.shop.ShopManager; import emu.grasscutter.game.shop.ShopManager;
import emu.grasscutter.game.tower.TowerScheduleManager; import emu.grasscutter.game.tower.TowerScheduleManager;
import emu.grasscutter.game.world.World; import emu.grasscutter.game.world.World;
import emu.grasscutter.game.world.WorldDataManager;
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.netty.KcpServer; import emu.grasscutter.netty.KcpServer;
@ -57,6 +58,7 @@ public final class GameServer extends KcpServer {
private final CombineManger combineManger; private final CombineManger combineManger;
private final TowerScheduleManager towerScheduleManager; private final TowerScheduleManager towerScheduleManager;
private final WorldDataManager worldDataManager;
public GameServer() { public GameServer() {
this(new InetSocketAddress( this(new InetSocketAddress(
GAME_INFO.bindAddress, GAME_INFO.bindAddress,
@ -86,6 +88,7 @@ public final class GameServer extends KcpServer {
this.expeditionManager = new ExpeditionManager(this); this.expeditionManager = new ExpeditionManager(this);
this.combineManger = new CombineManger(this); this.combineManger = new CombineManger(this);
this.towerScheduleManager = new TowerScheduleManager(this); this.towerScheduleManager = new TowerScheduleManager(this);
this.worldDataManager = new WorldDataManager(this);
// Hook into shutdown event. // Hook into shutdown event.
Runtime.getRuntime().addShutdownHook(new Thread(this::onServerShutdown)); Runtime.getRuntime().addShutdownHook(new Thread(this::onServerShutdown));
} }
@ -153,6 +156,10 @@ public final class GameServer extends KcpServer {
return towerScheduleManager; return towerScheduleManager;
} }
public WorldDataManager getWorldDataManager() {
return worldDataManager;
}
public TaskMap getTaskMap() { public TaskMap getTaskMap() {
return this.taskMap; return this.taskMap;
} }