Some fix about scene script and quest (#2029)

* [ScriptLib] Query player when not get entity from scene

* Fix NPE when doing quests

* Add QUEST_CONTENT_SKILL trigger

Q353 need it

* Add some missing fields that contain in scene scripts

* Add a lua table serializer implement with jackson

This do not replace the original one,it is useful when debug

* Fix point_array type error

* feat: fix space
This commit is contained in:
ZanyRain 2023-02-10 00:10:07 +08:00 committed by GitHub
parent ab5b49b7c5
commit 3b29ba032e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 288 additions and 35 deletions

View File

@ -132,6 +132,7 @@ public class GameMainQuest {
// Add rewards
MainQuestData mainQuestData = GameData.getMainQuestDataMap().get(this.getParentQuestId());
if (mainQuestData != null && mainQuestData.getRewardIdList() != null) {
for (int rewardId : mainQuestData.getRewardIdList()) {
RewardData rewardData = GameData.getRewardDataMap().get(rewardId);
@ -141,6 +142,7 @@ public class GameMainQuest {
getOwner().getInventory().addItemParamDatas(rewardData.getRewardItemList(), ActionReason.QuestReward);
}
}
// handoff main quest
if (mainQuestData.getSuggestTrackMainQuestList() != null) {

View File

@ -272,6 +272,7 @@ public class QuestManager extends BasePlayerManager {
case QUEST_CONTENT_INTERACT_GADGET:
case QUEST_CONTENT_TRIGGER_FIRE:
case QUEST_CONTENT_UNLOCK_TRANS_POINT:
case QUEST_CONTENT_SKILL:
for (GameMainQuest mainQuest : checkMainQuests) {
mainQuest.tryFinishSubQuests(condType, paramStr, params);
}

View File

@ -0,0 +1,14 @@
package emu.grasscutter.game.quest.content;
import emu.grasscutter.data.excels.QuestData;
import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.QuestValue;
import emu.grasscutter.game.quest.enums.QuestTrigger;
@QuestValue(QuestTrigger.QUEST_CONTENT_SKILL)
public class ContentSkill extends BaseContent {
@Override
public boolean execute(GameQuest quest, QuestData.QuestCondition condition, String paramStr, int... params) {
return (condition.getParam()[0] == params[0]) && (condition.getParam()[1] == params[1]);
}
}

View File

@ -104,16 +104,22 @@ public class SceneScriptManager {
currentTriggers.put(eventId, new HashSet<>());
}
public void refreshGroup(SceneGroup group, int suiteIndex) {
if (group == null) {
return;
}
var suite = group.getSuiteByIndex(suiteIndex);
if (suite == null) {
return;
}
if (suite.sceneTriggers.size() > 0) {
for (var trigger : suite.sceneTriggers) {
resetTriggers(trigger.event);
this.currentTriggers.get(trigger.event).add(trigger);
}
}
spawnMonstersInGroup(group, suite);
spawnGadgetsInGroup(group, suite);
}

View File

@ -1,11 +1,13 @@
package emu.grasscutter.scripts;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.dungeons.challenge.DungeonChallenge;
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.EntityMonster;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.entity.gadget.GadgetWorktop;
import emu.grasscutter.game.dungeons.challenge.factory.ChallengeFactory;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.EntityType;
import emu.grasscutter.game.quest.enums.QuestState;
import emu.grasscutter.game.quest.enums.QuestTrigger;
@ -515,6 +517,12 @@ public class ScriptLib {
public int GetEntityType(int entityId){
var entity = getSceneScriptManager().getScene().getEntityById(entityId);
if(entity == null){
// check players
Player player = DatabaseHelper.getPlayerByUid(entityId);
if (player != null) {
return EntityType.Avatar.getValue();
}
return EntityType.None.getValue();
}

View File

@ -0,0 +1,11 @@
package emu.grasscutter.scripts.data;
import lombok.Setter;
import lombok.ToString;
@ToString
@Setter
public class Explore {
public String name;
public int exp;
}

View File

@ -13,6 +13,13 @@ public class SceneGadget extends SceneObject{
public int interact_id;
public boolean isOneoff;
public int draft_id;
public String drop_tag;
public boolean persistent;
public int mark_flag;
public int route_id;
public Explore explore;
public int trigger_count;
public boolean showcutscene;
public void setIsOneoff(boolean isOneoff) {
this.isOneoff = isOneoff;

View File

@ -8,5 +8,5 @@ import lombok.ToString;
public class SceneInitConfig {
public int suite;
public int end_suite;
public int rand_suite;
public boolean rand_suite;
}

View File

@ -9,4 +9,11 @@ public class SceneMonster extends SceneObject{
public int monster_id;
public int pose_id;
public int drop_id;
public int special_name_id;
public String drop_tag;
public int climate_area_id;
public boolean disableWander;
public int title_id;
public int[] affix;
public int mark_flag;
}

View File

@ -4,6 +4,8 @@ import emu.grasscutter.scripts.constants.ScriptRegionShape;
import emu.grasscutter.utils.Position;
import lombok.Setter;
import java.util.List;
@Setter
public class SceneRegion {
@ -14,6 +16,9 @@ public class SceneRegion {
public Position size;
// for SPHERE
public int radius;
public int area_id;
public float height;
public List<Position> point_array;
public transient SceneGroup group;
public boolean contains(Position position) {

View File

@ -15,6 +15,7 @@ public class SceneSuite {
public List<String> triggers = List.of();
public List<Integer> regions = List.of();
public int rand_weight;
public int[] npcs;
public transient List<SceneMonster> sceneMonsters = List.of();
public transient List<SceneGadget> sceneGadgets = List.of();
@ -22,7 +23,7 @@ public class SceneSuite {
public transient List<SceneRegion> sceneRegions = List.of();
public void init(SceneGroup sceneGroup) {
if(sceneGroup.monsters != null){
if(sceneGroup.monsters != null && this.monsters != null){
this.sceneMonsters = new ArrayList<>(
this.monsters.stream()
.filter(sceneGroup.monsters::containsKey)
@ -31,7 +32,7 @@ public class SceneSuite {
);
}
if(sceneGroup.gadgets != null){
if(sceneGroup.gadgets != null && this.gadgets != null){
this.sceneGadgets = new ArrayList<>(
this.gadgets.stream()
.filter(sceneGroup.gadgets::containsKey)
@ -40,7 +41,7 @@ public class SceneSuite {
);
}
if(sceneGroup.triggers != null) {
if(sceneGroup.triggers != null && this.triggers != null) {
this.sceneTriggers = new ArrayList<>(
this.triggers.stream()
.filter(sceneGroup.triggers::containsKey)
@ -48,7 +49,7 @@ public class SceneSuite {
.toList()
);
}
if(sceneGroup.regions != null) {
if(sceneGroup.regions != null && this.regions != null) {
this.sceneRegions = new ArrayList<>(
this.regions.stream()
.filter(sceneGroup.regions::containsKey)

View File

@ -10,6 +10,9 @@ public class SceneTrigger {
public String source;
public String condition;
public String action;
public boolean forbid_guest;
public int trigger_count;
public String tlog_tag;
public transient SceneGroup currentGroup;
@Override
@ -34,6 +37,8 @@ public class SceneTrigger {
", source='" + source + '\'' +
", condition='" + condition + '\'' +
", action='" + action + '\'' +
", forbid_guest='" + forbid_guest + '\'' +
", trigger_count='" + trigger_count + '\'' +
'}';
}
}

View File

@ -9,4 +9,5 @@ public class SceneVar {
public String name;
public int value;
public boolean no_refresh;
public int configId;
}

View File

@ -0,0 +1,183 @@
package emu.grasscutter.scripts.serializer;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.databind.type.MapType;
import emu.grasscutter.Grasscutter;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import java.io.IOException;
import java.util.*;
public class LuaTableJacksonSerializer extends JsonSerializer<LuaTable> implements Serializer {
private static ObjectMapper objectMapper;
public LuaTableJacksonSerializer() {
if (objectMapper == null) {
objectMapper = new ObjectMapper();
objectMapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);
// Some properties in Lua table but not in java field
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configOverride(List.class).setSetterInfo(JsonSetter.Value.forContentNulls(Nulls.AS_EMPTY));
SimpleModule luaSerializeModule = new SimpleModule();
luaSerializeModule.addSerializer(LuaTable.class, this);
objectMapper.registerModule(luaSerializeModule);
}
}
@Override
public void serialize(LuaTable value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (value == null || value.isnil()) {
gen.writeNull();
return;
}
// Detect table type
boolean isArray = false;
LuaValue[] keys = value.keys();
if (keys.length == 0) {
gen.writeNull();
return;
}
int count = 0;
for (int i = 0; i < keys.length; i++) {
if (!keys[i].isint() || (i + 1) != keys[i].toint()) {
break;
} else {
count++;
}
}
if (count == keys.length) {
isArray = true;
}
if (isArray) {
gen.writeStartArray();
for (LuaValue key : keys) {
LuaValue luaValue = value.get(key);
if (luaValue.isnil()) {
gen.writeNull();
} else if (luaValue.isboolean()) {
gen.writeBoolean(luaValue.toboolean());
} else if (luaValue.isint()) {
gen.writeNumber(luaValue.toint());
} else if (luaValue.islong()) {
gen.writeNumber(luaValue.tolong());
} else if (luaValue.isnumber()) {
gen.writeNumber(luaValue.tofloat());
} else if (luaValue.isstring()) {
gen.writeString(luaValue.tojstring());
} else if (luaValue.istable()) {
serialize(luaValue.checktable(), gen, serializers);
}
}
gen.writeEndArray();
} else {
gen.writeStartObject();
for (LuaValue key : keys) {
String keyStr = key.toString();
LuaValue luaValue = value.get(key);
if (luaValue.isnil()) {
gen.writeNullField(keyStr);
} else if (luaValue.isboolean()) {
gen.writeBooleanField(keyStr, luaValue.toboolean());
} else if (luaValue.isint()) {
gen.writeNumberField(keyStr, luaValue.toint());
} else if (luaValue.islong()) {
gen.writeNumberField(keyStr, luaValue.tolong());
} else if (luaValue.isnumber()) {
gen.writeNumberField(keyStr, luaValue.tofloat());
} else if (luaValue.isstring()) {
gen.writeStringField(keyStr, luaValue.tojstring());
} else if (luaValue.istable()) {
gen.writeFieldName(keyStr);
serialize(luaValue.checktable(), gen, serializers);
}
}
gen.writeEndObject();
}
gen.flush();
gen.close();
}
@Override
public <T> List<T> toList(Class<T> type, Object obj) {
List<T> list = new ArrayList<>();
if (!(obj instanceof LuaTable luaTable) || luaTable.isnil()) {
return list;
}
CollectionType collectionType = objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, type);
JsonNode jsonNode = objectMapper.valueToTree(luaTable);
Grasscutter.getLogger().trace("[LuaTableToList] className={},data={}", type.getCanonicalName(), jsonNode.toString());
if (jsonNode.isEmpty()) {
return list;
}
if (jsonNode.isArray()) {
try {
Object o = objectMapper.treeToValue(jsonNode, collectionType);
if (o != null) {
list = (ArrayList<T>) o;
}
} catch (JsonProcessingException e) {
e.printStackTrace();
}
} else if (jsonNode.isObject()) {
Iterator<Map.Entry<String, JsonNode>> fields = jsonNode.fields();
List<JsonNode> nodes = new ArrayList<>();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> next = fields.next();
nodes.add(next.getValue());
}
list = objectMapper.convertValue(nodes, collectionType);
}
return list;
}
@Override
public <T> T toObject(Class<T> type, Object obj) {
if (!(obj instanceof LuaTable luaTable) || luaTable.isnil()) {
return null;
}
JsonNode jsonNode = objectMapper.valueToTree(luaTable);
Grasscutter.getLogger().trace("[LuaTableToObject] className={},data={}", type.getCanonicalName(), jsonNode.toString());
try {
return objectMapper.treeToValue(jsonNode, type);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
@Override
public <T> Map<String, T> toMap(Class<T> type, Object obj) {
HashMap<String, T> map = new HashMap<>();
if (!(obj instanceof LuaTable luaTable) || luaTable.isnil()) {
return map;
}
MapType mapStringType = objectMapper.getTypeFactory().constructMapType(HashMap.class, String.class, type);
JsonNode jsonNode = objectMapper.valueToTree(luaTable);
Grasscutter.getLogger().trace("[LuaTableToMap] className={},data={}", type.getCanonicalName(), jsonNode.toString());
try {
Object o = objectMapper.treeToValue(jsonNode, mapStringType);
if (o != null) {
return (HashMap<String, T>) o;
}
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return map;
}
}

View File

@ -1,5 +1,6 @@
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.quest.enums.QuestTrigger;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
@ -23,5 +24,6 @@ public class HandlerEvtDoSkillSuccNotify extends PacketHandler {
// Handle skill notify in other managers.
player.getStaminaManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
player.getEnergyManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
player.getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_SKILL, skillId, 0);
}
}