Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
ziqian zhang
Grasscutter
Commits
8050f0cc
Commit
8050f0cc
authored
Jul 23, 2022
by
akatatsu27
Browse files
and misc bug fixes
parent
02a56fce
Changes
28
Hide whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/data/ResourceLoader.java
View file @
8050f0cc
...
@@ -56,22 +56,23 @@ public class ResourceLoader {
...
@@ -56,22 +56,23 @@ public class ResourceLoader {
public
static
void
loadAll
()
{
public
static
void
loadAll
()
{
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.status.resources.loading"
));
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.status.resources.loading"
));
// Load ability lists
// Load ability lists
loadAbilityEmbryos
();
loadAbilityEmbryos
();
loadOpenConfig
();
loadOpenConfig
();
loadAbilityModifiers
();
loadAbilityModifiers
();
// Load resources
// Load resources
loadResources
();
loadResources
();
// Process into depots
// Process into depots
GameDepot
.
load
();
GameDepot
.
load
();
// Load spawn data and quests
// Load spawn data and quests
loadSpawnData
();
loadSpawnData
();
loadQuests
();
loadQuests
();
// Load scene points - must be done AFTER resources are loaded
loadScriptSceneData
();
loadScenePoints
();
// Load scene points - must be done AFTER resources are loaded
// Load default home layout
loadScenePoints
();
loadHomeworldDefaultSaveData
();
// Load default home layout
loadNpcBornData
();
loadHomeworldDefaultSaveData
();
loadNpcBornData
();
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.status.resources.finish"
));
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.status.resources.finish"
));
}
}
...
@@ -420,10 +421,32 @@ public class ResourceLoader {
...
@@ -420,10 +421,32 @@ public class ResourceLoader {
Grasscutter
.
getLogger
().
debug
(
"Loaded "
+
GameData
.
getMainQuestDataMap
().
size
()
+
" MainQuestDatas."
);
Grasscutter
.
getLogger
().
debug
(
"Loaded "
+
GameData
.
getMainQuestDataMap
().
size
()
+
" MainQuestDatas."
);
}
}
@SneakyThrows
public
static
void
loadScriptSceneData
()
{
private
static
void
loadHomeworldDefaultSaveData
()
{
File
folder
=
new
File
(
RESOURCE
(
"ScriptSceneData/"
));
var
folder
=
Files
.
list
(
Path
.
of
(
RESOURCE
(
"BinOutput/HomeworldDefaultSave"
))).
toList
();
var
pattern
=
Pattern
.
compile
(
"scene(.*)_home_config.json"
);
if
(!
folder
.
exists
())
{
return
;
}
for
(
File
file
:
folder
.
listFiles
())
{
ScriptSceneData
sceneData
;
try
(
FileReader
fileReader
=
new
FileReader
(
file
))
{
sceneData
=
Grasscutter
.
getGsonFactory
().
fromJson
(
fileReader
,
ScriptSceneData
.
class
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
continue
;
}
GameData
.
getScriptSceneDataMap
().
put
(
file
.
getName
(),
sceneData
);
}
Grasscutter
.
getLogger
().
debug
(
"Loaded "
+
GameData
.
getScriptSceneDataMap
().
size
()
+
" ScriptSceneDatas."
);
}
@SneakyThrows
private
static
void
loadHomeworldDefaultSaveData
(){
var
folder
=
Files
.
list
(
Path
.
of
(
RESOURCE
(
"BinOutput/HomeworldDefaultSave"
))).
toList
();
var
pattern
=
Pattern
.
compile
(
"scene(.*)_home_config.json"
);
for
(
var
file
:
folder
)
{
for
(
var
file
:
folder
)
{
var
matcher
=
pattern
.
matcher
(
file
.
getFileName
().
toString
());
var
matcher
=
pattern
.
matcher
(
file
.
getFileName
().
toString
());
...
...
src/main/java/emu/grasscutter/data/binout/MainQuestData.java
View file @
8050f0cc
package
emu.grasscutter.data.binout
;
package
emu.grasscutter.data.binout
;
import
dev.morphia.annotations.Entity
;
import
emu.grasscutter.game.quest.enums.QuestType
;
import
emu.grasscutter.game.quest.enums.QuestType
;
import
lombok.Data
;
import
lombok.Data
;
import
java.util.List
;
import
java.util.Objects
;
public
class
MainQuestData
{
public
class
MainQuestData
{
private
int
id
;
private
int
id
;
private
int
ICLLDPJFIMA
;
private
int
series
;
private
int
series
;
private
QuestType
type
;
private
QuestType
type
;
private
long
titleTextMapHash
;
private
long
titleTextMapHash
;
private
int
[]
suggestTrackMainQuestList
;
private
int
[]
suggestTrackMainQuestList
;
private
int
[]
rewardIdList
;
private
int
[]
rewardIdList
;
private
SubQuestData
[]
subQuests
;
private
SubQuestData
[]
subQuests
;
private
List
<
TalkData
>
talks
;
public
int
getId
()
{
private
long
[]
preloadLuaList
;
return
id
;
}
public
int
getId
()
{
return
id
;
}
public
int
getSeries
()
{
public
int
getSeries
()
{
return
series
;
return
series
;
}
}
public
QuestType
getType
()
{
public
QuestType
getType
()
{
return
type
;
return
type
;
}
}
public
long
getTitleTextMapHash
()
{
public
long
getTitleTextMapHash
()
{
return
titleTextMapHash
;
return
titleTextMapHash
;
}
}
public
int
[]
getSuggestTrackMainQuestList
()
{
public
int
[]
getSuggestTrackMainQuestList
()
{
return
suggestTrackMainQuestList
;
return
suggestTrackMainQuestList
;
}
}
...
@@ -37,14 +43,28 @@ public class MainQuestData {
...
@@ -37,14 +43,28 @@ public class MainQuestData {
public
int
[]
getRewardIdList
()
{
public
int
[]
getRewardIdList
()
{
return
rewardIdList
;
return
rewardIdList
;
}
}
public
SubQuestData
[]
getSubQuests
()
{
public
SubQuestData
[]
getSubQuests
()
{
return
subQuests
;
return
subQuests
;
}
}
public
List
<
TalkData
>
getTalks
()
{
return
talks
;
}
public
void
onLoad
()
{
this
.
talks
=
talks
.
stream
().
filter
(
Objects:
:
nonNull
).
toList
();
}
@Data
@Data
public
static
class
SubQuestData
{
public
static
class
SubQuestData
{
private
int
subId
;
private
int
subId
;
private
int
order
;
private
int
order
;
}
}
@Data
@Entity
public
static
class
TalkData
{
private
int
id
;
private
String
heroTalk
;
}
}
}
src/main/java/emu/grasscutter/data/excels/QuestData.java
View file @
8050f0cc
...
@@ -36,10 +36,14 @@ public class QuestData extends GameResource {
...
@@ -36,10 +36,14 @@ public class QuestData extends GameResource {
private
List
<
QuestExecParam
>
beginExec
;
private
List
<
QuestExecParam
>
beginExec
;
private
List
<
QuestExecParam
>
finishExec
;
private
List
<
QuestExecParam
>
finishExec
;
private
List
<
QuestExecParam
>
failExec
;
private
List
<
QuestExecParam
>
failExec
;
private
Guide
guide
;
//ResourceLoader not happy if you remove getId() ~~
public
int
getId
()
{
public
int
getId
()
{
return
subId
;
return
subId
;
}
}
//Added getSubId() for clarity
public
int
getSubId
()
{
return
subId
;}
public
int
getMainId
()
{
public
int
getMainId
()
{
return
mainId
;
return
mainId
;
...
@@ -62,7 +66,7 @@ public class QuestData extends GameResource {
...
@@ -62,7 +66,7 @@ public class QuestData extends GameResource {
}
}
public
LogicType
getAcceptCondComb
()
{
public
LogicType
getAcceptCondComb
()
{
return
acceptCondComb
;
return
acceptCondComb
==
null
?
LogicType
.
LOGIC_NONE
:
acceptCondComb
;
}
}
public
List
<
QuestCondition
>
getAcceptCond
()
{
public
List
<
QuestCondition
>
getAcceptCond
()
{
...
@@ -70,7 +74,7 @@ public class QuestData extends GameResource {
...
@@ -70,7 +74,7 @@ public class QuestData extends GameResource {
}
}
public
LogicType
getFinishCondComb
()
{
public
LogicType
getFinishCondComb
()
{
return
finishCondComb
;
return
finishCondComb
==
null
?
LogicType
.
LOGIC_NONE
:
finishCondComb
;
}
}
public
List
<
QuestCondition
>
getFinishCond
()
{
public
List
<
QuestCondition
>
getFinishCond
()
{
...
@@ -78,7 +82,7 @@ public class QuestData extends GameResource {
...
@@ -78,7 +82,7 @@ public class QuestData extends GameResource {
}
}
public
LogicType
getFailCondComb
()
{
public
LogicType
getFailCondComb
()
{
return
failCondComb
;
return
failCondComb
==
null
?
LogicType
.
LOGIC_NONE
:
failCondComb
;
}
}
public
List
<
QuestCondition
>
getFailCond
()
{
public
List
<
QuestCondition
>
getFailCond
()
{
...
@@ -118,4 +122,11 @@ public class QuestData extends GameResource {
...
@@ -118,4 +122,11 @@ public class QuestData extends GameResource {
private
String
count
;
private
String
count
;
}
}
@Data
public
static
class
Guide
{
private
String
type
;
private
List
<
String
>
param
;
private
int
guideScene
;
}
}
}
src/main/java/emu/grasscutter/game/player/Player.java
View file @
8050f0cc
...
@@ -14,12 +14,8 @@ import emu.grasscutter.game.activity.ActivityManager;
...
@@ -14,12 +14,8 @@ import emu.grasscutter.game.activity.ActivityManager;
import
emu.grasscutter.game.avatar.Avatar
;
import
emu.grasscutter.game.avatar.Avatar
;
import
emu.grasscutter.game.avatar.AvatarStorage
;
import
emu.grasscutter.game.avatar.AvatarStorage
;
import
emu.grasscutter.game.battlepass.BattlePassManager
;
import
emu.grasscutter.game.battlepass.BattlePassManager
;
import
emu.grasscutter.game.entity.EntityMonster
;
import
emu.grasscutter.game.entity.*
;
import
emu.grasscutter.game.entity.EntityVehicle
;
import
emu.grasscutter.game.home.GameHome
;
import
emu.grasscutter.game.home.GameHome
;
import
emu.grasscutter.game.entity.EntityGadget
;
import
emu.grasscutter.game.entity.EntityItem
;
import
emu.grasscutter.game.entity.GameEntity
;
import
emu.grasscutter.game.expedition.ExpeditionInfo
;
import
emu.grasscutter.game.expedition.ExpeditionInfo
;
import
emu.grasscutter.game.friends.FriendsList
;
import
emu.grasscutter.game.friends.FriendsList
;
import
emu.grasscutter.game.friends.PlayerProfile
;
import
emu.grasscutter.game.friends.PlayerProfile
;
...
@@ -43,6 +39,7 @@ import emu.grasscutter.game.props.ClimateType;
...
@@ -43,6 +39,7 @@ import emu.grasscutter.game.props.ClimateType;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.game.props.WatcherTriggerType
;
import
emu.grasscutter.game.props.WatcherTriggerType
;
import
emu.grasscutter.game.quest.QuestManager
;
import
emu.grasscutter.game.quest.QuestManager
;
import
emu.grasscutter.game.quest.enums.QuestTrigger
;
import
emu.grasscutter.game.shop.ShopLimit
;
import
emu.grasscutter.game.shop.ShopLimit
;
import
emu.grasscutter.game.tower.TowerData
;
import
emu.grasscutter.game.tower.TowerData
;
import
emu.grasscutter.game.tower.TowerManager
;
import
emu.grasscutter.game.tower.TowerManager
;
...
@@ -61,6 +58,7 @@ import emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo
...
@@ -61,6 +58,7 @@ 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.net.proto.VisionTypeOuterClass.VisionType
;
import
emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType
;
import
emu.grasscutter.scripts.data.SceneRegion
;
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
;
...
@@ -74,6 +72,7 @@ import emu.grasscutter.utils.Utils;
...
@@ -74,6 +72,7 @@ import emu.grasscutter.utils.Utils;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
import
lombok.Getter
;
import
lombok.Getter
;
import
lombok.Setter
;
import
static
emu
.
grasscutter
.
config
.
Configuration
.*;
import
static
emu
.
grasscutter
.
config
.
Configuration
.*;
...
@@ -122,6 +121,7 @@ public class Player {
...
@@ -122,6 +121,7 @@ public class Player {
@Getter
private
Map
<
Long
,
ExpeditionInfo
>
expeditionInfo
;
@Getter
private
Map
<
Long
,
ExpeditionInfo
>
expeditionInfo
;
@Getter
private
Map
<
Integer
,
Integer
>
unlockedRecipies
;
@Getter
private
Map
<
Integer
,
Integer
>
unlockedRecipies
;
@Getter
private
List
<
ActiveForgeData
>
activeForges
;
@Getter
private
List
<
ActiveForgeData
>
activeForges
;
@Getter
private
Map
<
Integer
,
Integer
>
questGlobalVariables
;
@Transient
private
long
nextGuid
=
0
;
@Transient
private
long
nextGuid
=
0
;
@Transient
private
int
peerId
;
@Transient
private
int
peerId
;
...
@@ -151,7 +151,7 @@ public class Player {
...
@@ -151,7 +151,7 @@ public class Player {
@Getter
private
transient
CookingManager
cookingManager
;
@Getter
private
transient
CookingManager
cookingManager
;
@Getter
private
transient
ActivityManager
activityManager
;
@Getter
private
transient
ActivityManager
activityManager
;
@Getter
private
transient
PlayerBuffManager
buffManager
;
@Getter
private
transient
PlayerBuffManager
buffManager
;
// Manager data (Save-able to the database)
// Manager data (Save-able to the database)
private
PlayerProfile
playerProfile
;
private
PlayerProfile
playerProfile
;
private
TeamManager
teamManager
;
private
TeamManager
teamManager
;
...
@@ -579,9 +579,38 @@ public class Player {
...
@@ -579,9 +579,38 @@ public class Player {
return
towerData
;
return
towerData
;
}
}
public
PlayerGachaInfo
getGachaInfo
()
{
public
void
setQuestManager
(
QuestManager
questManager
)
{
return
gachaInfo
;
this
.
questManager
=
questManager
;
}
public
void
onEnterRegion
(
SceneRegion
region
)
{
getQuestManager
().
forEachActiveQuest
(
quest
->
{
if
(
quest
.
getTriggers
().
containsKey
(
"ENTER_REGION_"
+
String
.
valueOf
(
region
.
config_id
)))
{
// If trigger hasn't been fired yet
if
(!
Boolean
.
TRUE
.
equals
(
quest
.
getTriggers
().
put
(
"ENTER_REGION_"
+
String
.
valueOf
(
region
.
config_id
),
true
)))
{
//getSession().send(new PacketServerCondMeetQuestListUpdateNotify());
getQuestManager
().
triggerEvent
(
QuestTrigger
.
QUEST_CONTENT_TRIGGER_FIRE
,
quest
.
getTriggerData
().
get
(
"ENTER_REGION_"
+
String
.
valueOf
(
region
.
config_id
)).
getId
(),
0
);
}
}
});
}
public
void
onLeaveRegion
(
SceneRegion
region
)
{
getQuestManager
().
forEachActiveQuest
(
quest
->
{
if
(
quest
.
getTriggers
().
containsKey
(
"LEAVE_REGION_"
+
String
.
valueOf
(
region
.
config_id
)))
{
// If trigger hasn't been fired yet
if
(!
Boolean
.
TRUE
.
equals
(
quest
.
getTriggers
().
put
(
"LEAVE_REGION_"
+
String
.
valueOf
(
region
.
config_id
),
true
)))
{
getSession
().
send
(
new
PacketServerCondMeetQuestListUpdateNotify
());
getQuestManager
().
triggerEvent
(
QuestTrigger
.
QUEST_CONTENT_TRIGGER_FIRE
,
quest
.
getTriggerData
().
get
(
"LEAVE_REGION_"
+
String
.
valueOf
(
region
.
config_id
)).
getId
(),
0
);
}
}
});
}
}
public
PlayerGachaInfo
getGachaInfo
()
{
return
gachaInfo
;
}
public
PlayerProfile
getProfile
()
{
public
PlayerProfile
getProfile
()
{
if
(
this
.
playerProfile
==
null
)
{
if
(
this
.
playerProfile
==
null
)
{
...
@@ -892,7 +921,7 @@ public class Player {
...
@@ -892,7 +921,7 @@ public class Player {
public
boolean
hasSentLoginPackets
()
{
public
boolean
hasSentLoginPackets
()
{
return
hasSentLoginPackets
;
return
hasSentLoginPackets
;
}
}
public
void
addAvatar
(
Avatar
avatar
,
boolean
addToCurrentTeam
)
{
public
void
addAvatar
(
Avatar
avatar
,
boolean
addToCurrentTeam
)
{
boolean
result
=
getAvatars
().
addAvatar
(
avatar
);
boolean
result
=
getAvatars
().
addAvatar
(
avatar
);
...
@@ -1327,21 +1356,25 @@ public class Player {
...
@@ -1327,21 +1356,25 @@ public class Player {
// Execute daily reset logic if this is a new day.
// Execute daily reset logic if this is a new day.
this
.
doDailyReset
();
this
.
doDailyReset
();
// Packets
session
.
send
(
new
PacketPlayerDataNotify
(
this
));
// Player data
// Rewind active quests, and put the player to the first rewind position it finds (if any) of an active quest
session
.
send
(
new
PacketStoreWeightLimitNotify
());
getQuestManager
().
onLogin
();
session
.
send
(
new
PacketPlayerStoreNotify
(
this
));
session
.
send
(
new
PacketAvatarDataNotify
(
this
));
// Packets
session
.
send
(
new
PacketFinishedParentQuestNotify
(
this
));
session
.
send
(
new
PacketPlayerDataNotify
(
this
));
// Player data
session
.
send
(
new
PacketBattlePassAllDataNotify
(
this
));
session
.
send
(
new
PacketStoreWeightLimitNotify
());
session
.
send
(
new
PacketQuestListNotify
(
this
));
session
.
send
(
new
PacketPlayerStoreNotify
(
this
));
session
.
send
(
new
PacketCodexDataFullNotify
(
this
));
session
.
send
(
new
PacketAvatarDataNotify
(
this
));
session
.
send
(
new
PacketAllWidgetDataNotify
(
this
));
session
.
send
(
new
PacketFinishedParentQuestNotify
(
this
));
session
.
send
(
new
PacketWidgetGadgetAllDataNotify
());
session
.
send
(
new
PacketBattlePassAllDataNotify
(
this
));
session
.
send
(
new
PacketCombineDataNotify
(
this
.
unlockedCombines
));
session
.
send
(
new
PacketQuestListNotify
(
this
));
this
.
forgingManager
.
sendForgeDataNotify
();
session
.
send
(
new
PacketCodexDataFullNotify
(
this
));
this
.
resinManager
.
onPlayerLogin
();
session
.
send
(
new
PacketAllWidgetDataNotify
(
this
));
this
.
cookingManager
.
sendCookDataNofity
();
session
.
send
(
new
PacketWidgetGadgetAllDataNotify
());
session
.
send
(
new
PacketCombineDataNotify
(
this
.
unlockedCombines
));
this
.
forgingManager
.
sendForgeDataNotify
();
this
.
resinManager
.
onPlayerLogin
();
this
.
cookingManager
.
sendCookDataNofity
();
// Unlock in case this is an existing user that reached a level before we implemented unlocking.
// Unlock in case this is an existing user that reached a level before we implemented unlocking.
this
.
getOpenStateManager
().
unlockLevelDependentStates
();
this
.
getOpenStateManager
().
unlockLevelDependentStates
();
...
...
src/main/java/emu/grasscutter/game/quest/GameMainQuest.java
View file @
8050f0cc
...
@@ -2,7 +2,15 @@ package emu.grasscutter.game.quest;
...
@@ -2,7 +2,15 @@ package emu.grasscutter.game.quest;
import
java.util.*
;
import
java.util.*
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.binout.ScriptSceneData
;
import
emu.grasscutter.data.excels.QuestData
;
import
emu.grasscutter.game.quest.enums.LogicType
;
import
emu.grasscutter.game.quest.enums.QuestTrigger
;
import
emu.grasscutter.scripts.ScriptLoader
;
import
emu.grasscutter.server.packet.send.PacketCodexDataUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketCodexDataUpdateNotify
;
import
emu.grasscutter.utils.Position
;
import
lombok.Getter
;
import
org.bson.types.ObjectId
;
import
org.bson.types.ObjectId
;
import
dev.morphia.annotations.Entity
;
import
dev.morphia.annotations.Entity
;
...
@@ -11,6 +19,7 @@ import dev.morphia.annotations.Indexed;
...
@@ -11,6 +19,7 @@ import dev.morphia.annotations.Indexed;
import
dev.morphia.annotations.Transient
;
import
dev.morphia.annotations.Transient
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.binout.MainQuestData
;
import
emu.grasscutter.data.binout.MainQuestData
;
import
emu.grasscutter.data.binout.MainQuestData.*
;
import
emu.grasscutter.data.excels.RewardData
;
import
emu.grasscutter.data.excels.RewardData
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.player.Player
;
...
@@ -23,24 +32,33 @@ import emu.grasscutter.net.proto.QuestOuterClass.Quest;
...
@@ -23,24 +32,33 @@ import emu.grasscutter.net.proto.QuestOuterClass.Quest;
import
emu.grasscutter.server.packet.send.PacketFinishedParentQuestUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketFinishedParentQuestUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketQuestListUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketQuestListUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketQuestProgressUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketQuestProgressUpdateNotify
;
import
emu.grasscutter.utils.Utils
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
javax.script.Bindings
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
import
javax.script.CompiledScript
;
import
javax.script.ScriptException
;
import
static
emu
.
grasscutter
.
config
.
Configuration
.
SCRIPT
;
@Entity
(
value
=
"quests"
,
useDiscriminator
=
false
)
@Entity
(
value
=
"quests"
,
useDiscriminator
=
false
)
public
class
GameMainQuest
{
public
class
GameMainQuest
{
@Id
private
ObjectId
id
;
@Id
private
ObjectId
id
;
@Indexed
@Getter
private
int
ownerUid
;
@Indexed
private
int
ownerUid
;
@Transient
@Getter
private
Player
owner
;
@Transient
private
Player
owner
;
@Transient
@Getter
private
QuestManager
questManager
;
@Getter
private
Map
<
Integer
,
GameQuest
>
childQuests
;
private
Map
<
Integer
,
GameQuest
>
childQuests
;
@Getter
private
int
parentQuestId
;
@Getter
private
int
[]
questVars
;
private
int
parentQuestId
;
//QuestUpdateQuestVarReq is sent in two stages...
private
int
[]
questVars
;
@Getter
private
List
<
Integer
>
questVarsUpdate
;
private
ParentQuestState
state
;
@Getter
private
ParentQuestState
state
;
private
boolean
isFinished
;
@Getter
private
boolean
isFinished
;
List
<
QuestGroupSuite
>
questGroupSuites
;
@Getter
List
<
QuestGroupSuite
>
questGroupSuites
;
@Getter
int
[]
suggestTrackMainQuestList
;
@Getter
private
Map
<
Integer
,
TalkData
>
talks
;
//key is subId
private
Map
<
Integer
,
Position
>
rewindPositions
;
private
Map
<
Integer
,
Position
>
rewindRotations
;
@Deprecated
// Morphia only. Do not use.
@Deprecated
// Morphia only. Do not use.
public
GameMainQuest
()
{}
public
GameMainQuest
()
{}
...
@@ -48,52 +66,60 @@ public class GameMainQuest {
...
@@ -48,52 +66,60 @@ public class GameMainQuest {
public
GameMainQuest
(
Player
player
,
int
parentQuestId
)
{
public
GameMainQuest
(
Player
player
,
int
parentQuestId
)
{
this
.
owner
=
player
;
this
.
owner
=
player
;
this
.
ownerUid
=
player
.
getUid
();
this
.
ownerUid
=
player
.
getUid
();
this
.
questManager
=
player
.
getQuestManager
();
this
.
parentQuestId
=
parentQuestId
;
this
.
parentQuestId
=
parentQuestId
;
this
.
childQuests
=
new
HashMap
<>();
this
.
childQuests
=
new
HashMap
<>();
this
.
questVars
=
new
int
[
5
];
this
.
talks
=
new
HashMap
<>();
//official server always has a list of 5 questVars, with default value 0
this
.
questVars
=
new
int
[]
{
0
,
0
,
0
,
0
,
0
};
this
.
state
=
ParentQuestState
.
PARENT_QUEST_STATE_NONE
;
this
.
state
=
ParentQuestState
.
PARENT_QUEST_STATE_NONE
;
this
.
questGroupSuites
=
new
ArrayList
<>();
this
.
questGroupSuites
=
new
ArrayList
<>();
this
.
rewindPositions
=
new
HashMap
<>();
this
.
rewindRotations
=
new
HashMap
<>();
addAllChildQuests
();
addRewindPoints
();
}
}
public
int
getParentQuestId
()
{
private
void
addAllChildQuests
()
{
return
parentQuestId
;
List
<
Integer
>
subQuestIds
=
Arrays
.
stream
(
GameData
.
getMainQuestDataMap
().
get
(
this
.
parentQuestId
).
getSubQuests
()).
map
(
SubQuestData:
:
getSubId
).
toList
();
}
for
(
Integer
subQuestId
:
subQuestIds
)
{
QuestData
questConfig
=
GameData
.
getQuestDataMap
().
get
(
subQuestId
);
public
int
getOwnerUid
()
{
this
.
childQuests
.
put
(
subQuestId
,
new
GameQuest
(
this
,
questConfig
));
return
ownerUid
;
}
}
}
public
Player
getOwner
()
{
return
owner
;
}
public
void
setOwner
(
Player
player
)
{
public
void
setOwner
(
Player
player
)
{
if
(
player
.
getUid
()
!=
this
.
getOwnerUid
())
return
;
if
(
player
.
getUid
()
!=
this
.
getOwnerUid
())
return
;
this
.
owner
=
player
;
this
.
owner
=
player
;
}
}
public
Map
<
Integer
,
GameQuest
>
getChildQuests
()
{
public
int
getQuestVar
(
int
i
)
{
return
childQuests
;
return
questVars
[
i
];
}
}
public
void
setQuestVar
(
int
i
,
int
value
)
{
int
previousValue
=
this
.
questVars
[
i
];
this
.
questVars
[
i
]
=
value
;
Grasscutter
.
getLogger
().
debug
(
"questVar {} value changed from {} to {}"
,
i
,
previousValue
,
value
);
}
public
GameQuest
getChildQuestById
(
int
id
)
{
public
void
incQuestVar
(
int
i
,
int
inc
)
{
return
this
.
getChildQuests
().
get
(
id
);
int
previousValue
=
this
.
questVars
[
i
];
}
this
.
questVars
[
i
]
+=
inc
;
Grasscutter
.
getLogger
().
debug
(
"questVar {} value incremented from {} to {}"
,
i
,
previousValue
,
previousValue
+
inc
);
}
public
int
[]
getQuestVars
()
{
public
void
decQuestVar
(
int
i
,
int
dec
)
{
return
questVars
;
int
previousValue
=
this
.
questVars
[
i
];
}
this
.
questVars
[
i
]
-=
dec
;
Grasscutter
.
getLogger
().
debug
(
"questVar {} value decremented from {} to {}"
,
i
,
previousValue
,
previousValue
-
dec
);
}
public
ParentQuestState
getState
()
{
return
state
;
}
public
boolean
isFinished
(
)
{
public
GameQuest
getChildQuestById
(
int
id
)
{
return
isFinished
;
return
this
.
getChildQuests
().
get
(
id
)
;
}
}
public
GameQuest
getChildQuestByOrder
(
int
order
)
{
public
List
<
QuestGroupSuite
>
getQuestGroupSuites
()
{
return
this
.
getChildQuests
().
values
().
stream
().
filter
(
p
->
p
.
getQuestData
().
getOrder
()
==
order
).
toList
().
get
(
0
);
return
questGroupSuites
;
}
}
public
void
finish
()
{
public
void
finish
()
{
...
@@ -120,9 +146,193 @@ public class GameMainQuest {
...
@@ -120,9 +146,193 @@ public class GameMainQuest {
// handoff main quest
// handoff main quest
if
(
mainQuestData
.
getSuggestTrackMainQuestList
()
!=
null
){
if
(
mainQuestData
.
getSuggestTrackMainQuestList
()
!=
null
){
Arrays
.
stream
(
mainQuestData
.
getSuggestTrackMainQuestList
())
Arrays
.
stream
(
mainQuestData
.
getSuggestTrackMainQuestList
())
.
forEach
(
getOwner
().
getQuestManager
()::
startMainQuest
);
.
forEach
(
getQuestManager
()::
startMainQuest
);
}
}
}
}
//TODO
public
void
fail
()
{}
public
void
cancel
()
{}
// Rewinds to the last finished/unfinished rewind quest, and returns the avatar rewind position (if it exists)
public
List
<
Position
>
rewind
()
{
if
(
this
.
questManager
==
null
)
{
this
.
questManager
=
getOwner
().
getQuestManager
();
}
List
<
GameQuest
>
sortedByOrder
=
new
ArrayList
<>(
getChildQuests
().
values
().
stream
().
filter
(
q
->
q
.
getQuestData
().
isRewind
()).
toList
());
sortedByOrder
.
sort
((
a
,
b
)
->
{
if
(
a
==
b
){
return
0
;
}
return
a
.
getQuestData
().
getOrder
()
>
b
.
getQuestData
().
getOrder
()
?
1
:
-
1
;});
boolean
didRewind
=
false
;
for
(
GameQuest
quest
:
sortedByOrder
)
{
int
i
=
sortedByOrder
.
indexOf
(
quest
);
if
(
i
==
sortedByOrder
.
size
())
{
didRewind
=
quest
.
rewind
(
null
);
}
else
{
didRewind
=
quest
.
rewind
(
sortedByOrder
.
get
(
i
+
1
));
}
if
(
didRewind
)
{
break
;
}
}
List
<
GameQuest
>
rewindQuests
=
getChildQuests
().
values
().
stream
()
.
filter
(
p
->
(
p
.
getState
()
==
QuestState
.
QUEST_STATE_UNFINISHED
||
p
.
getState
()
==
QuestState
.
QUEST_STATE_FINISHED
)
&&
p
.
getQuestData
().
isRewind
()).
toList
();
for
(
GameQuest
quest
:
rewindQuests
)
{
if
(
rewindPositions
.
containsKey
(
quest
.
getSubQuestId
()))
{
List
<
Position
>
posAndRot
=
new
ArrayList
<>();
posAndRot
.
add
(
0
,
rewindPositions
.
get
(
quest
.
getSubQuestId
()));
posAndRot
.
add
(
1
,
rewindRotations
.
get
(
quest
.
getSubQuestId
()));
return
posAndRot
;
}
}
return
null
;
}
public
void
addRewindPoints
()
{
Bindings
bindings
=
ScriptLoader
.
getEngine
().
createBindings
();
CompiledScript
cs
=
ScriptLoader
.
getScriptByPath
(
SCRIPT
(
"Quest/Share/Q"
+
getParentQuestId
()
+
"ShareConfig."
+
ScriptLoader
.
getScriptType
()));
if
(
cs
==
null
)
{
Grasscutter
.
getLogger
().
error
(
"Couldn't find Q"
+
getParentQuestId
()
+
"ShareConfig."
+
ScriptLoader
.
getScriptType
());
return
;
}
// Eval script
try
{
cs
.
eval
(
bindings
);
var
rewindDataMap
=
ScriptLoader
.
getSerializer
().
toMap
(
RewindData
.
class
,
bindings
.
get
(
"rewind_data"
));
for
(
String
subId
:
rewindDataMap
.
keySet
())
{
RewindData
questRewind
=
rewindDataMap
.
get
(
subId
);
if
(
questRewind
!=
null
)
{
RewindData
.
AvatarData
avatarData
=
questRewind
.
getAvatar
();
if
(
avatarData
!=
null
)
{
String
avatarPos
=
avatarData
.
getPos
();
QuestData
.
Guide
guide
=
GameData
.
getQuestDataMap
().
get
(
Integer
.
valueOf
(
subId
)).
getGuide
();
if
(
guide
!=
null
)
{
int
sceneId
=
guide
.
getGuideScene
();
ScriptSceneData
fullGlobals
=
GameData
.
getScriptSceneDataMap
().
get
(
"flat.luas.scenes.full_globals.lua.json"
);
if
(
fullGlobals
!=
null
)
{
ScriptSceneData
.
ScriptObject
dummyPointScript
=
fullGlobals
.
getScriptObjectList
().
get
(
sceneId
+
"/scene"
+
sceneId
+
"_dummy_points.lua"
);
if
(
dummyPointScript
!=
null
)
{
Map
<
String
,
List
<
Float
>>
dummyPointMap
=
dummyPointScript
.
getDummyPoints
();
if
(
dummyPointMap
!=
null
)
{
List
<
Float
>
avatarPosPos
=
dummyPointMap
.
get
(
avatarPos
+
".pos"
);
if
(
avatarPosPos
!=
null
)
{
Position
pos
=
new
Position
(
avatarPosPos
.
get
(
0
),
avatarPosPos
.
get
(
1
),
avatarPosPos
.
get
(
2
));
List
<
Float
>
avatarPosRot
=
dummyPointMap
.
get
(
avatarPos
+
".rot"
);
Position
rot
=
new
Position
(
avatarPosRot
.
get
(
0
),
avatarPosRot
.
get
(
1
),
avatarPosRot
.
get
(
2
));
rewindPositions
.
put
(
Integer
.
valueOf
(
subId
),
pos
);
rewindRotations
.
put
(
Integer
.
valueOf
(
subId
),
rot
);
Grasscutter
.
getLogger
().
debug
(
"Succesfully loaded rewind position for subQuest {}"
,
subId
);
}
}
}
}
}
}
}
}
}
catch
(
ScriptException
e
)
{
Grasscutter
.
getLogger
().
error
(
"An error occurred while loading rewind positions"
);
}
}
public
void
tryAcceptSubQuests
(
QuestTrigger
condType
,
String
paramStr
,
int
...
params
)
{
try
{
List
<
GameQuest
>
subQuestsWithCond
=
getChildQuests
().
values
().
stream
()
.
filter
(
p
->
p
.
getState
()
==
QuestState
.
QUEST_STATE_UNSTARTED
)
.
filter
(
p
->
p
.
getQuestData
().
getAcceptCond
().
stream
().
anyMatch
(
q
->
q
.
getType
()
==
condType
))
.
toList
();
for
(
GameQuest
subQuestWithCond
:
subQuestsWithCond
)
{
List
<
QuestData
.
QuestCondition
>
acceptCond
=
subQuestWithCond
.
getQuestData
().
getAcceptCond
();
int
[]
accept
=
new
int
[
acceptCond
.
size
()];
for
(
int
i
=
0
;
i
<
subQuestWithCond
.
getQuestData
().
getAcceptCond
().
size
();
i
++)
{
QuestData
.
QuestCondition
condition
=
acceptCond
.
get
(
i
);
boolean
result
=
this
.
getOwner
().
getServer
().
getQuestSystem
().
triggerCondition
(
subQuestWithCond
,
condition
,
paramStr
,
params
);
accept
[
i
]
=
result
?
1
:
0
;
}
boolean
shouldAccept
=
LogicType
.
calculate
(
subQuestWithCond
.
getQuestData
().
getAcceptCondComb
(),
accept
);
if
(
shouldAccept
)
{
subQuestWithCond
.
start
();
getQuestManager
().
getAddToQuestListUpdateNotify
().
add
(
subQuestWithCond
);
}
}
this
.
save
();
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
"An error occurred while trying to accept quest."
,
e
);
}
}
public
void
tryFailSubQuests
(
QuestTrigger
condType
,
String
paramStr
,
int
...
params
)
{
try
{
List
<
GameQuest
>
subQuestsWithCond
=
getChildQuests
().
values
().
stream
()
.
filter
(
p
->
p
.
getState
()
==
QuestState
.
QUEST_STATE_UNFINISHED
)
.
filter
(
p
->
p
.
getQuestData
().
getFailCond
().
stream
().
anyMatch
(
q
->
q
.
getType
()
==
condType
))
.
toList
();
for
(
GameQuest
subQuestWithCond
:
subQuestsWithCond
)
{
List
<
QuestData
.
QuestCondition
>
failCond
=
subQuestWithCond
.
getQuestData
().
getFailCond
();
int
[]
fail
=
new
int
[
failCond
.
size
()];
for
(
int
i
=
0
;
i
<
subQuestWithCond
.
getQuestData
().
getFailCond
().
size
();
i
++)
{
QuestData
.
QuestCondition
condition
=
failCond
.
get
(
i
);
boolean
result
=
this
.
getOwner
().
getServer
().
getQuestSystem
().
triggerContent
(
subQuestWithCond
,
condition
,
paramStr
,
params
);
fail
[
i
]
=
result
?
1
:
0
;
}
boolean
shouldFail
=
LogicType
.
calculate
(
subQuestWithCond
.
getQuestData
().
getFailCondComb
(),
fail
);
if
(
shouldFail
)
{
subQuestWithCond
.
fail
();
getQuestManager
().
getAddToQuestListUpdateNotify
().
add
(
subQuestWithCond
);
}
}
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
"An error occurred while trying to fail quest."
,
e
);
}
}
public
void
tryFinishSubQuests
(
QuestTrigger
condType
,
String
paramStr
,
int
...
params
)
{
try
{
List
<
GameQuest
>
subQuestsWithCond
=
getChildQuests
().
values
().
stream
()
//There are subQuests with no acceptCond, but can be finished (example: 35104)
.
filter
(
p
->
p
.
getState
()
==
QuestState
.
QUEST_STATE_UNFINISHED
&&
p
.
getQuestData
().
getAcceptCond
()
!=
null
)
.
filter
(
p
->
p
.
getQuestData
().
getFinishCond
().
stream
().
anyMatch
(
q
->
q
.
getType
()
==
condType
))
.
toList
();
for
(
GameQuest
subQuestWithCond
:
subQuestsWithCond
)
{
List
<
QuestData
.
QuestCondition
>
finishCond
=
subQuestWithCond
.
getQuestData
().
getFinishCond
();
int
[]
finish
=
new
int
[
finishCond
.
size
()];
for
(
int
i
=
0
;
i
<
subQuestWithCond
.
getQuestData
().
getFinishCond
().
size
();
i
++)
{
QuestData
.
QuestCondition
condition
=
finishCond
.
get
(
i
);
boolean
result
=
this
.
getOwner
().
getServer
().
getQuestSystem
().
triggerContent
(
subQuestWithCond
,
condition
,
paramStr
,
params
);
finish
[
i
]
=
result
?
1
:
0
;
}
boolean
shouldFinish
=
LogicType
.
calculate
(
subQuestWithCond
.
getQuestData
().
getFinishCondComb
(),
finish
);
if
(
shouldFinish
)
{
subQuestWithCond
.
finish
();
getQuestManager
().
getAddToQuestListUpdateNotify
().
add
(
subQuestWithCond
);
}
}
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
debug
(
"An error occurred while trying to finish quest."
,
e
);
}
}
public
void
save
()
{
public
void
save
()
{
DatabaseHelper
.
saveQuest
(
this
);
DatabaseHelper
.
saveQuest
(
this
);
...
@@ -131,24 +341,30 @@ public class GameMainQuest {
...
@@ -131,24 +341,30 @@ public class GameMainQuest {
public
ParentQuest
toProto
()
{
public
ParentQuest
toProto
()
{
ParentQuest
.
Builder
proto
=
ParentQuest
.
newBuilder
()
ParentQuest
.
Builder
proto
=
ParentQuest
.
newBuilder
()
.
setParentQuestId
(
getParentQuestId
())
.
setParentQuestId
(
getParentQuestId
())
.
setIsFinished
(
isFinished
())
.
setIsFinished
(
isFinished
());
.
setParentQuestState
(
getState
().
getValue
());
/**
if ParentQuestState is NONE, official server does not send ParentQuestState nor childQuestList!!!
for
(
GameQuest
quest
:
this
.
getChildQuests
().
values
())
{
might need more sniffing...
ChildQuest
childQuest
=
ChildQuest
.
newBuilder
()
sending childQuestList without ParentQuestState set causes the game to hang on login
.
setQuestId
(
quest
.
getQuestId
())
*/
.
setState
(
quest
.
getState
().
getValue
())
if
(
getState
()
!=
ParentQuestState
.
PARENT_QUEST_STATE_NONE
)
{
.
build
();
proto
.
setParentQuestState
(
getState
().
getValue
());
for
(
GameQuest
quest
:
this
.
getChildQuests
().
values
())
{
proto
.
addChildQuestList
(
childQuest
);
if
(
quest
.
getState
()
!=
QuestState
.
QUEST_STATE_UNSTARTED
)
{
}
ChildQuest
childQuest
=
ChildQuest
.
newBuilder
()
.
setQuestId
(
quest
.
getSubQuestId
())
if
(
getQuestVars
()
!=
null
)
{
.
setState
(
quest
.
getState
().
getValue
())
for
(
int
i
:
getQuestVars
())
{
.
build
();
proto
.
addQuestVar
(
i
);
}
proto
.
addChildQuestList
(
childQuest
);
}
}
}
}
for
(
int
i
:
getQuestVars
())
{
proto
.
addQuestVar
(
i
);
}
return
proto
.
build
();
return
proto
.
build
();
}
}
}
}
src/main/java/emu/grasscutter/game/quest/GameQuest.java
View file @
8050f0cc
...
@@ -4,51 +4,84 @@ import dev.morphia.annotations.Entity;
...
@@ -4,51 +4,84 @@ import dev.morphia.annotations.Entity;
import
dev.morphia.annotations.Transient
;
import
dev.morphia.annotations.Transient
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.binout.MainQuestData
;
import
emu.grasscutter.data.binout.MainQuestData.SubQuestData
;
import
emu.grasscutter.data.excels.ChapterData
;
import
emu.grasscutter.data.excels.ChapterData
;
import
emu.grasscutter.data.excels.QuestData
;
import
emu.grasscutter.data.excels.QuestData
;
import
emu.grasscutter.data.excels.
QuestData.QuestCondition
;
import
emu.grasscutter.data.excels.
TriggerExcelConfigData
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.quest.enums.LogicType
;
import
emu.grasscutter.game.quest.enums.QuestState
;
import
emu.grasscutter.game.quest.enums.QuestState
;
import
emu.grasscutter.game.quest.enums.QuestTrigger
;
import
emu.grasscutter.game.quest.enums.QuestTrigger
;
import
emu.grasscutter.net.proto.ChapterStateOuterClass
;
import
emu.grasscutter.net.proto.ChapterStateOuterClass
;
import
emu.grasscutter.net.proto.QuestOuterClass.Quest
;
import
emu.grasscutter.net.proto.QuestOuterClass.Quest
;
import
emu.grasscutter.scripts.data.SceneGroup
;
import
emu.grasscutter.server.packet.send.PacketChapterStateNotify
;
import
emu.grasscutter.server.packet.send.PacketChapterStateNotify
;
import
emu.grasscutter.server.packet.send.PacketQuestListUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketQuestListUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketQuestProgressUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketQuestProgressUpdateNotify
;
import
emu.grasscutter.utils.Utils
;
import
emu.grasscutter.utils.Utils
;
import
lombok.Getter
;
import
lombok.Setter
;
import
javax.script.Bindings
;
import
java.util.Arrays
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
@Entity
@Entity
public
class
GameQuest
{
public
class
GameQuest
{
@Transient
private
GameMainQuest
mainQuest
;
@Transient
@Getter
@Setter
private
GameMainQuest
mainQuest
;
@Transient
private
QuestData
questData
;
@Transient
@Getter
private
QuestData
questData
;
private
int
questId
;
@Getter
private
int
subQuestId
;
private
int
mainQuestId
;
@Getter
private
int
mainQuestId
;
@Getter
@Setter
private
QuestState
state
;
private
QuestState
state
;
private
int
startTime
;
@Getter
@Setter
private
int
startTime
;
private
int
acceptTime
;
@Getter
@Setter
private
int
acceptTime
;
private
int
finishTime
;
@Getter
@Setter
private
int
finishTime
;
private
int
[]
finishProgressList
;
@Getter
private
int
[]
finishProgressList
;
private
int
[]
failProgressList
;
@Getter
private
int
[]
failProgressList
;
@Transient
@Getter
private
Map
<
String
,
TriggerExcelConfigData
>
triggerData
;
@Getter
private
Map
<
String
,
Boolean
>
triggers
;
private
transient
Bindings
bindings
;
@Deprecated
// Morphia only. Do not use.
@Deprecated
// Morphia only. Do not use.
public
GameQuest
()
{}
public
GameQuest
()
{}
public
GameQuest
(
GameMainQuest
mainQuest
,
QuestData
questData
)
{
public
GameQuest
(
GameMainQuest
mainQuest
,
QuestData
questData
)
{
this
.
mainQuest
=
mainQuest
;
this
.
mainQuest
=
mainQuest
;
this
.
questId
=
questData
.
getId
();
this
.
subQuestId
=
questData
.
getId
();
this
.
mainQuestId
=
questData
.
getMainId
();
this
.
mainQuestId
=
questData
.
getMainId
();
this
.
questData
=
questData
;
this
.
questData
=
questData
;
this
.
state
=
QuestState
.
QUEST_STATE_UNSTARTED
;
this
.
triggerData
=
new
HashMap
<>();
this
.
triggers
=
new
HashMap
<>();
}
public
void
start
()
{
this
.
acceptTime
=
Utils
.
getCurrentSeconds
();
this
.
acceptTime
=
Utils
.
getCurrentSeconds
();
this
.
startTime
=
this
.
acceptTime
;
this
.
startTime
=
this
.
acceptTime
;
this
.
state
=
QuestState
.
QUEST_STATE_UNFINISHED
;
this
.
state
=
QuestState
.
QUEST_STATE_UNFINISHED
;
List
<
QuestData
.
QuestCondition
>
triggerCond
=
questData
.
getFinishCond
().
stream
()
.
filter
(
p
->
p
.
getType
()
==
QuestTrigger
.
QUEST_CONTENT_TRIGGER_FIRE
).
toList
();
if
(
triggerCond
.
size
()
>
0
)
{
for
(
QuestData
.
QuestCondition
cond
:
triggerCond
)
{
TriggerExcelConfigData
newTrigger
=
GameData
.
getTriggerExcelConfigDataMap
().
get
(
cond
.
getParam
()[
0
]);
if
(
newTrigger
!=
null
)
{
if
(
this
.
triggerData
==
null
)
{
this
.
triggerData
=
new
HashMap
<>();
}
triggerData
.
put
(
newTrigger
.
getTriggerName
(),
newTrigger
);
triggers
.
put
(
newTrigger
.
getTriggerName
(),
false
);
SceneGroup
group
=
SceneGroup
.
of
(
newTrigger
.
getGroupId
()).
load
(
newTrigger
.
getSceneId
());
getOwner
().
getWorld
().
getSceneById
(
newTrigger
.
getSceneId
()).
loadTriggerFromGroup
(
group
,
newTrigger
.
getTriggerName
());
}
}
}
if
(
questData
.
getFinishCond
()
!=
null
&&
questData
.
get
Accept
Cond
().
size
()
!=
0
)
{
if
(
questData
.
getFinishCond
()
!=
null
&&
questData
.
get
Finish
Cond
().
size
()
!=
0
)
{
this
.
finishProgressList
=
new
int
[
questData
.
getFinishCond
().
size
()];
this
.
finishProgressList
=
new
int
[
questData
.
getFinishCond
().
size
()];
}
}
...
@@ -56,201 +89,136 @@ public class GameQuest {
...
@@ -56,201 +89,136 @@ public class GameQuest {
this
.
failProgressList
=
new
int
[
questData
.
getFailCond
().
size
()];
this
.
failProgressList
=
new
int
[
questData
.
getFailCond
().
size
()];
}
}
this
.
mainQuest
.
getChildQuests
().
put
(
this
.
questId
,
this
);
getQuestData
().
getBeginExec
().
forEach
(
e
->
getOwner
().
getServer
().
getQuestSystem
().
triggerExec
(
this
,
e
,
e
.
getParam
()));
this
.
getData
().
getBeginExec
().
forEach
(
e
->
getOwner
().
getServer
().
getQuestSystem
().
triggerExec
(
this
,
e
,
e
.
getParam
()));
this
.
getOwner
().
getQuestManager
().
triggerEvent
(
QuestTrigger
.
QUEST_CONTENT_QUEST_STATE_EQUAL
,
this
.
questId
,
this
.
state
.
getValue
());
if
(
ChapterData
.
beginQuestChapterMap
.
containsKey
(
q
uestId
))
{
if
(
ChapterData
.
beginQuestChapterMap
.
containsKey
(
subQ
uestId
)){
mainQuest
.
getOwner
().
sendPacket
(
new
PacketChapterStateNotify
(
mainQuest
.
getOwner
().
sendPacket
(
new
PacketChapterStateNotify
(
ChapterData
.
beginQuestChapterMap
.
get
(
q
uestId
).
getId
(),
ChapterData
.
beginQuestChapterMap
.
get
(
subQ
uestId
).
getId
(),
ChapterStateOuterClass
.
ChapterState
.
CHAPTER_STATE_BEGIN
ChapterStateOuterClass
.
ChapterState
.
CHAPTER_STATE_BEGIN
));
));
}
}
Grasscutter
.
getLogger
().
debug
(
"Quest {} is started"
,
questId
);
//Some subQuests and talks become active when some other subQuests are unfinished (even from different MainQuests)
}
this
.
getOwner
().
getQuestManager
().
triggerEvent
(
QuestTrigger
.
QUEST_CONTENT_QUEST_STATE_EQUAL
,
this
.
getSubQuestId
(),
this
.
getState
().
getValue
(),
0
,
0
,
0
);
this
.
getOwner
().
getQuestManager
().
triggerEvent
(
QuestTrigger
.
QUEST_COND_STATE_EQUAL
,
this
.
getSubQuestId
(),
this
.
getState
().
getValue
(),
0
,
0
,
0
);
public
GameMainQuest
getMainQuest
()
{
return
mainQuest
;
}
public
void
setMainQuest
(
GameMainQuest
mainQuest
)
{
this
.
mainQuest
=
mainQuest
;
}
public
Player
getOwner
()
{
return
getMainQuest
().
getOwner
();
}
public
int
getQuestId
()
{
return
questId
;
}
public
int
getMainQuestId
()
{
return
mainQuestId
;
}
public
QuestData
getData
()
{
return
questData
;
}
public
void
setConfig
(
QuestData
config
)
{
if
(
this
.
getQuestId
()
!=
config
.
getId
())
return
;
this
.
questData
=
config
;
}
public
QuestState
getState
()
{
return
state
;
}
public
void
setState
(
QuestState
state
)
{
this
.
state
=
state
;
}
public
int
getStartTime
()
{
return
startTime
;
}
public
void
setStartTime
(
int
startTime
)
{
this
.
startTime
=
startTime
;
}
public
int
getAcceptTime
()
{
return
acceptTime
;
}
public
void
setAcceptTime
(
int
acceptTime
)
{
this
.
acceptTime
=
acceptTime
;
}
public
int
getFinishTime
()
{
Grasscutter
.
getLogger
().
debug
(
"Quest {} is started"
,
subQuestId
);
return
finishTime
;
}
}
public
void
setFinishTime
(
int
finishTime
)
{
public
String
getTriggerNameById
(
int
id
)
{
this
.
finishTime
=
finishTime
;
TriggerExcelConfigData
trigger
=
GameData
.
getTriggerExcelConfigDataMap
().
get
(
id
);
if
(
trigger
!=
null
)
{
String
triggerName
=
trigger
.
getTriggerName
();
return
triggerName
;
}
//return empty string if can't find trigger
return
""
;
}
}
public
int
[]
getFinishProgressList
()
{
public
Player
getOwner
()
{
return
finishProgressList
;
return
this
.
getMainQuest
().
getOwner
()
;
}
}
public
void
setFinishProgress
(
int
index
,
int
value
)
{
public
void
setConfig
(
QuestData
config
)
{
finishProgressList
[
index
]
=
value
;
if
(
getSubQuestId
()
!=
config
.
getId
())
return
;
}
this
.
questData
=
config
;
}
public
int
[]
getFailProgressList
(
)
{
public
void
setFinishProgress
(
int
index
,
int
value
)
{
return
failProgressList
;
finishProgressList
[
index
]
=
value
;
}
}
public
void
setFailProgress
(
int
index
,
int
value
)
{
public
void
setFailProgress
(
int
index
,
int
value
)
{
failProgressList
[
index
]
=
value
;
failProgressList
[
index
]
=
value
;
}
}
public
void
finish
()
{
public
void
finish
()
{
this
.
state
=
QuestState
.
QUEST_STATE_FINISHED
;
this
.
state
=
QuestState
.
QUEST_STATE_FINISHED
;
this
.
finishTime
=
Utils
.
getCurrentSeconds
();
this
.
finishTime
=
Utils
.
getCurrentSeconds
();
if
(
this
.
getFinishProgressList
()
!=
null
)
{
if
(
getFinishProgressList
()
!=
null
)
{
for
(
int
i
=
0
;
i
<
getFinishProgressList
().
length
;
i
++)
{
Arrays
.
fill
(
getFinishProgressList
(),
1
);
getFinishProgressList
()[
i
]
=
1
;
}
}
}
this
.
getOwner
().
getSession
().
send
(
new
PacketQuestProgressUpdateNotify
(
this
));
getOwner
().
getSession
().
send
(
new
PacketQuestProgressUpdateNotify
(
this
));
this
.
getOwner
().
getSession
().
send
(
new
PacketQuestListUpdateNotify
(
this
));
if
(
this
.
getData
().
finishParent
())
{
// This quest finishes the questline - the main quest will also save the quest to db so we dont have to call save() here
this
.
getMainQuest
().
finish
();
}
else
{
// Try and accept other quests if possible
this
.
tryAcceptQuestLine
();
this
.
save
();
}
this
.
getData
().
getFinishExec
().
forEach
(
e
->
getOwner
().
getServer
().
getQuestSystem
().
triggerExec
(
this
,
e
,
e
.
getParam
()));
if
(
getQuestData
().
finishParent
())
{
// This quest finishes the questline - the main quest will also save the quest to db, so we don't have to call save() here
getMainQuest
().
finish
();
}
this
.
getOwner
().
getQuestManager
().
triggerEvent
(
QuestTrigger
.
QUEST_CONTENT_QUEST_STATE_EQUAL
,
this
.
questId
,
this
.
state
.
getValue
());
getQuestData
().
getFinishExec
().
forEach
(
e
->
getOwner
().
getServer
().
getQuestSystem
().
triggerExec
(
this
,
e
,
e
.
getParam
()));
//Some subQuests have conditions that subQuests are finished (even from different MainQuests)
getOwner
().
getQuestManager
().
triggerEvent
(
QuestTrigger
.
QUEST_CONTENT_QUEST_STATE_EQUAL
,
this
.
subQuestId
,
this
.
state
.
getValue
(),
0
,
0
,
0
);
getOwner
().
getQuestManager
().
triggerEvent
(
QuestTrigger
.
QUEST_COND_STATE_EQUAL
,
this
.
subQuestId
,
this
.
state
.
getValue
(),
0
,
0
,
0
);
if
(
ChapterData
.
endQuestChapterMap
.
containsKey
(
q
uestId
))
{
if
(
ChapterData
.
endQuestChapterMap
.
containsKey
(
subQ
uestId
)){
mainQuest
.
getOwner
().
sendPacket
(
new
PacketChapterStateNotify
(
mainQuest
.
getOwner
().
sendPacket
(
new
PacketChapterStateNotify
(
ChapterData
.
endQuestChapterMap
.
get
(
q
uestId
).
getId
(),
ChapterData
.
endQuestChapterMap
.
get
(
subQ
uestId
).
getId
(),
ChapterStateOuterClass
.
ChapterState
.
CHAPTER_STATE_END
ChapterStateOuterClass
.
ChapterState
.
CHAPTER_STATE_END
));
));
}
}
Grasscutter
.
getLogger
().
debug
(
"Quest {} is finished"
,
questId
);
Grasscutter
.
getLogger
().
debug
(
"Quest {} is finished"
,
subQuestId
);
}
}
public
boolean
tryAcceptQuestLine
()
{
try
{
MainQuestData
questConfig
=
GameData
.
getMainQuestDataMap
().
get
(
this
.
getMainQuestId
());
for
(
SubQuestData
subQuest
:
questConfig
.
getSubQuests
())
{
GameQuest
quest
=
getMainQuest
().
getChildQuestById
(
subQuest
.
getSubId
());
if
(
quest
==
null
)
{
QuestData
questData
=
GameData
.
getQuestDataMap
().
get
(
subQuest
.
getSubId
());
if
(
questData
==
null
||
questData
.
getAcceptCond
()
==
null
||
questData
.
getAcceptCond
().
size
()
==
0
)
{
continue
;
}
int
[]
accept
=
new
int
[
questData
.
getAcceptCond
().
size
()];
// TODO
for
(
int
i
=
0
;
i
<
questData
.
getAcceptCond
().
size
();
i
++)
{
QuestCondition
condition
=
questData
.
getAcceptCond
().
get
(
i
);
boolean
result
=
getOwner
().
getServer
().
getQuestSystem
().
triggerCondition
(
this
,
condition
,
condition
.
getParamStr
(),
condition
.
getParam
());
accept
[
i
]
=
result
?
1
:
0
;
//TODO
}
public
void
fail
()
{
this
.
state
=
QuestState
.
QUEST_STATE_FAILED
;
boolean
shouldAccept
=
LogicType
.
calculate
(
questData
.
getAcceptCondComb
(),
accept
);
this
.
finishTime
=
Utils
.
getCurrentSeconds
(
);
if
(
shouldAccept
)
{
if
(
getFailProgressList
()
!=
null
)
{
this
.
getOwner
().
getQuestManager
().
addQuest
(
questData
.
getId
());
Arrays
.
fill
(
getFailProgressList
(),
1
);
}
}
}
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
"An error occurred while trying to accept quest."
,
e
);
}
}
return
false
;
getOwner
().
getSession
().
send
(
new
PacketQuestProgressUpdateNotify
(
this
));
}
public
void
save
()
{
getMainQuest
().
save
();
}
public
Quest
toProto
()
{
getQuestData
().
getFailExec
().
forEach
(
e
->
getOwner
().
getServer
().
getQuestSystem
().
triggerExec
(
this
,
e
,
e
.
getParam
()));
Quest
.
Builder
proto
=
Quest
.
newBuilder
()
//Some subQuests have conditions that subQuests fail (even from different MainQuests)
.
setQuestId
(
this
.
getQuestId
())
getOwner
().
getQuestManager
().
triggerEvent
(
QuestTrigger
.
QUEST_CONTENT_QUEST_STATE_EQUAL
,
this
.
subQuestId
,
this
.
state
.
getValue
(),
0
,
0
,
0
);
.
setState
(
this
.
getState
().
getValue
())
getOwner
().
getQuestManager
().
triggerEvent
(
QuestTrigger
.
QUEST_COND_STATE_EQUAL
,
this
.
subQuestId
,
this
.
state
.
getValue
(),
0
,
0
,
0
);
.
setParentQuestId
(
this
.
getMainQuestId
())
.
setStartTime
(
this
.
getStartTime
())
.
setStartGameTime
(
438
)
.
setAcceptTime
(
this
.
getAcceptTime
());
if
(
this
.
getFinishProgressList
()
!=
null
)
{
for
(
int
i
:
this
.
getFinishProgressList
())
{
proto
.
addFinishProgressList
(
i
);
}
}
if
(
this
.
getFailProgressList
()
!=
null
)
{
}
for
(
int
i
:
this
.
getFailProgressList
())
{
// Return true if ParentQuest should rewind to this childQuest
proto
.
addFailProgressList
(
i
);
public
boolean
rewind
(
GameQuest
nextRewind
)
{
if
(
questData
.
isRewind
())
{
if
(
nextRewind
==
null
)
{
return
true
;}
// if the next isRewind subQuest is none or unstarted, reset all subQuests with order higher than this one, and restart this quest
if
(
nextRewind
.
getState
()
==
QuestState
.
QUEST_STATE_NONE
||
nextRewind
.
getState
()
==
QuestState
.
QUEST_STATE_UNSTARTED
)
{
getMainQuest
().
getChildQuests
().
values
().
stream
().
filter
(
p
->
p
.
getQuestData
().
getOrder
()
>
this
.
getQuestData
().
getOrder
()).
forEach
(
q
->
q
.
setState
(
QuestState
.
QUEST_STATE_UNSTARTED
));
this
.
start
();
return
true
;
}
}
}
}
return
false
;
return
proto
.
build
();
}
}
public
void
save
()
{
getMainQuest
().
save
();
}
public
Quest
toProto
()
{
Quest
.
Builder
proto
=
Quest
.
newBuilder
()
.
setQuestId
(
getSubQuestId
())
.
setState
(
getState
().
getValue
())
.
setParentQuestId
(
getMainQuestId
())
.
setStartTime
(
getStartTime
())
.
setStartGameTime
(
438
)
.
setAcceptTime
(
getAcceptTime
());
if
(
getFinishProgressList
()
!=
null
)
{
for
(
int
i
:
getFinishProgressList
())
{
proto
.
addFinishProgressList
(
i
);
}
}
if
(
getFailProgressList
()
!=
null
)
{
for
(
int
i
:
getFailProgressList
())
{
proto
.
addFailProgressList
(
i
);
}
}
return
proto
.
build
();
}
}
}
src/main/java/emu/grasscutter/game/quest/QuestManager.java
View file @
8050f0cc
package
emu.grasscutter.game.quest
;
package
emu.grasscutter.game.quest
;
import
java.beans.Transient
;
import
java.util.*
;
import
java.util.*
;
import
java.util.function.Consumer
;
import
java.util.function.Consumer
;
import
java.util.stream.Collectors
;
import
java.util.stream.Collectors
;
...
@@ -17,32 +18,127 @@ import emu.grasscutter.game.quest.enums.QuestTrigger;
...
@@ -17,32 +18,127 @@ import emu.grasscutter.game.quest.enums.QuestTrigger;
import
emu.grasscutter.game.quest.enums.LogicType
;
import
emu.grasscutter.game.quest.enums.LogicType
;
import
emu.grasscutter.game.quest.enums.QuestState
;
import
emu.grasscutter.game.quest.enums.QuestState
;
import
emu.grasscutter.server.packet.send.*
;
import
emu.grasscutter.server.packet.send.*
;
import
emu.grasscutter.utils.Position
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
import
jdk.jshell.spi.ExecutionControl
;
import
lombok.Getter
;
public
class
QuestManager
extends
BasePlayerManager
{
public
class
QuestManager
extends
BasePlayerManager
{
private
final
Int2ObjectMap
<
GameMainQuest
>
quests
;
@Getter
private
final
Player
player
;
@Getter
private
Map
<
Integer
,
Integer
>
questGlobalVariables
;
public
QuestManager
(
Player
player
)
{
@Getter
private
final
Int2ObjectMap
<
GameMainQuest
>
mainQuests
;
@Getter
private
List
<
GameQuest
>
addToQuestListUpdateNotify
;
/*
On SetPlayerBornDataReq, the server sends FinishedParentQuestNotify, with this exact
parentQuestList. Captured on Game version 2.7
Note: quest 40063 is already set to finished, with childQuest 4006406's state set to 3
*/
private
static
Set
<
Integer
>
newPlayerMainQuests
=
Set
.
of
(
303
,
318
,
348
,
349
,
350
,
351
,
416
,
500
,
501
,
502
,
503
,
504
,
505
,
506
,
507
,
508
,
509
,
20000
,
20507
,
20509
,
21004
,
21005
,
21010
,
21011
,
21016
,
21017
,
21020
,
21021
,
21025
,
40063
,
70121
,
70124
,
70511
,
71010
,
71012
,
71013
,
71015
,
71016
,
71017
,
71555
);
/*
On SetPlayerBornDataReq, the server sends ServerCondMeetQuestListUpdateNotify, with this exact
addQuestIdList. Captured on Game version 2.7
Total of 161...
*/
/*
private static Set<Integer> newPlayerServerCondMeetQuestListUpdateNotify = Set.of(3100101, 7104405, 2201601,
7100801, 1907002, 7293301, 7193801, 7293401, 7193901, 7091001, 7190501, 7090901, 7190401, 7090801, 7190301,
7195301, 7294801, 7195201, 7293001, 7094001, 7193501, 7293501, 7194001, 7293701, 7194201, 7194301, 7293801,
7194901, 7194101, 7195001, 7294501, 7294101, 7194601, 7294301, 7194801, 7091301, 7290301, 2102401, 7216801,
7190201, 7090701, 7093801, 7193301, 7292801, 7227828, 7093901, 7193401, 7292901, 7093701, 7193201, 7292701,
7082402, 7093601, 7292601, 7193101, 2102301, 7093501, 7292501, 7193001, 7093401, 7292401, 7192901, 7093301,
7292301, 7192801, 7294201, 7194701, 2100301, 7093201, 7212402, 7292201, 7192701, 7280001, 7293901, 7194401,
7093101, 7212302, 7292101, 7192601, 7093001, 7292001, 7192501, 7216001, 7195101, 7294601, 2100900, 7092901,
7291901, 7192401, 7092801, 7291801, 7192301, 2101501, 7092701, 7291701, 7192201, 7106401, 2100716, 7091801,
7290801, 7191301, 7293201, 7193701, 7094201, 7294001, 7194501, 2102290, 7227829, 7193601, 7094101, 7091401,
7290401, 7190901, 7106605, 7291601, 7192101, 7092601, 7291501, 7192001, 7092501, 7291401, 7191901, 7092401,
7291301, 7191801, 7092301, 7211402, 7291201, 7191701, 7092201, 7291101, 7191601, 7092101, 7291001, 7191501,
7092001, 7290901, 7191401, 7091901, 7290701, 7191201, 7091701, 7290601, 7191101, 7091601, 7290501, 7191001,
7091501, 7290201, 7190701, 7091201, 7190601, 7091101, 7190101, 7090601, 7090501, 7090401, 7010701, 7090301,
7090201, 7010103, 7090101
);
*/
public
QuestManager
(
Player
player
)
{
super
(
player
);
super
(
player
);
this
.
quests
=
new
Int2ObjectOpenHashMap
<>();
this
.
player
=
player
;
this
.
questGlobalVariables
=
player
.
getQuestGlobalVariables
();
this
.
mainQuests
=
new
Int2ObjectOpenHashMap
<>();
this
.
addToQuestListUpdateNotify
=
new
ArrayList
<>();
}
public
void
onNewPlayerCreate
()
{
List
<
GameMainQuest
>
newQuests
=
this
.
addMultMainQuests
(
newPlayerMainQuests
);
//getPlayer().sendPacket(new PacketServerCondMeetQuestListUpdateNotify(newPlayerServerCondMeetQuestListUpdateNotify));
getPlayer
().
sendPacket
(
new
PacketFinishedParentQuestUpdateNotify
(
newQuests
));
}
public
void
onLogin
()
{
List
<
GameMainQuest
>
activeQuests
=
getActiveMainQuests
();
for
(
GameMainQuest
quest
:
activeQuests
)
{
List
<
Position
>
rewindPos
=
quest
.
rewind
();
// <pos, rotation>
if
(
rewindPos
!=
null
)
{
getPlayer
().
getPosition
().
set
(
rewindPos
.
get
(
0
));
getPlayer
().
getRotation
().
set
(
rewindPos
.
get
(
1
));
}
}
}
private
List
<
GameMainQuest
>
addMultMainQuests
(
Set
<
Integer
>
mainQuestIds
)
{
List
<
GameMainQuest
>
newQuests
=
new
ArrayList
<>();
for
(
Integer
id
:
mainQuestIds
)
{
getMainQuests
().
put
(
id
.
intValue
(),
new
GameMainQuest
(
this
.
player
,
id
));
getMainQuestById
(
id
).
save
();
newQuests
.
add
(
getMainQuestById
(
id
));
}
return
newQuests
;
}
}
public
Int2ObjectMap
<
GameMainQuest
>
getQuests
()
{
/*
return
quests
;
Looking through mainQuests 72201-72208 and 72174, we can infer that a questGlobalVar's default value is 0
*/
public
Integer
getQuestGlobalVarValue
(
Integer
variable
)
{
return
this
.
questGlobalVariables
.
getOrDefault
(
variable
,
0
);
}
}
public
GameMainQuest
getMainQuestById
(
int
mainQuestId
)
{
public
void
setQuestGlobalVarValue
(
Integer
variable
,
Integer
value
)
{
return
getQuests
().
get
(
mainQuestId
);
Integer
previousValue
=
this
.
questGlobalVariables
.
put
(
variable
,
value
);
Grasscutter
.
getLogger
().
debug
(
"Changed questGlobalVar {} value from {} to {}"
,
variable
,
previousValue
==
null
?
0
:
previousValue
,
value
);
}
public
void
incQuestGlobalVarValue
(
Integer
variable
,
Integer
inc
)
{
//
Integer
previousValue
=
this
.
questGlobalVariables
.
getOrDefault
(
variable
,
0
);
this
.
questGlobalVariables
.
put
(
variable
,
previousValue
+
inc
);
Grasscutter
.
getLogger
().
debug
(
"Incremented questGlobalVar {} value from {} to {}"
,
variable
,
previousValue
,
previousValue
+
inc
);
}
//In MainQuest 998, dec is passed as a positive integer
public
void
decQuestGlobalVarValue
(
Integer
variable
,
Integer
dec
)
{
//
Integer
previousValue
=
this
.
questGlobalVariables
.
getOrDefault
(
variable
,
0
);
this
.
questGlobalVariables
.
put
(
variable
,
previousValue
-
dec
);
Grasscutter
.
getLogger
().
debug
(
"Decremented questGlobalVar {} value from {} to {}"
,
variable
,
previousValue
,
previousValue
-
dec
);
}
}
public
GameMainQuest
getMainQuestById
(
int
mainQuestId
)
{
return
getMainQuests
().
get
(
mainQuestId
);
}
public
GameQuest
getQuestById
(
int
questId
)
{
public
GameQuest
getQuestById
(
int
questId
)
{
QuestData
questConfig
=
GameData
.
getQuestDataMap
().
get
(
questId
);
QuestData
questConfig
=
GameData
.
getQuestDataMap
().
get
(
questId
);
if
(
questConfig
==
null
)
{
if
(
questConfig
==
null
)
{
return
null
;
return
null
;
}
}
GameMainQuest
mainQuest
=
getQuests
().
get
(
questConfig
.
getMainId
());
GameMainQuest
mainQuest
=
get
Main
Quests
().
get
(
questConfig
.
getMainId
());
if
(
mainQuest
==
null
)
{
if
(
mainQuest
==
null
)
{
return
null
;
return
null
;
...
@@ -51,34 +147,34 @@ public class QuestManager extends BasePlayerManager {
...
@@ -51,34 +147,34 @@ public class QuestManager extends BasePlayerManager {
return
mainQuest
.
getChildQuests
().
get
(
questId
);
return
mainQuest
.
getChildQuests
().
get
(
questId
);
}
}
public
void
forEachQuest
(
Consumer
<
GameQuest
>
callback
)
{
public
void
forEachQuest
(
Consumer
<
GameQuest
>
callback
)
{
for
(
GameMainQuest
mainQuest
:
getQuests
().
values
())
{
for
(
GameMainQuest
mainQuest
:
get
Main
Quests
().
values
())
{
for
(
GameQuest
quest
:
mainQuest
.
getChildQuests
().
values
())
{
for
(
GameQuest
quest
:
mainQuest
.
getChildQuests
().
values
())
{
callback
.
accept
(
quest
);
callback
.
accept
(
quest
);
}
}
}
}
}
}
public
void
forEachMainQuest
(
Consumer
<
GameMainQuest
>
callback
)
{
public
void
forEachMainQuest
(
Consumer
<
GameMainQuest
>
callback
)
{
for
(
GameMainQuest
mainQuest
:
getQuests
().
values
())
{
for
(
GameMainQuest
mainQuest
:
get
Main
Quests
().
values
())
{
callback
.
accept
(
mainQuest
);
callback
.
accept
(
mainQuest
);
}
}
}
}
// TODO
// TODO
public
void
forEachActiveQuest
(
Consumer
<
GameQuest
>
callback
)
{
public
void
forEachActiveQuest
(
Consumer
<
GameQuest
>
callback
)
{
for
(
GameMainQuest
mainQuest
:
getQuests
().
values
())
{
for
(
GameMainQuest
mainQuest
:
get
Main
Quests
().
values
())
{
for
(
GameQuest
quest
:
mainQuest
.
getChildQuests
().
values
())
{
for
(
GameQuest
quest
:
mainQuest
.
getChildQuests
().
values
())
{
if
(
quest
.
getState
()
!=
QuestState
.
QUEST_STATE_FINISHED
)
{
if
(
quest
.
getState
()
!=
QuestState
.
QUEST_STATE_FINISHED
)
{
callback
.
accept
(
quest
);
callback
.
accept
(
quest
);
}
}
}
}
}
}
}
}
public
GameMainQuest
addMainQuest
(
QuestData
questConfig
)
{
public
GameMainQuest
addMainQuest
(
QuestData
questConfig
)
{
GameMainQuest
mainQuest
=
new
GameMainQuest
(
getPlayer
(),
questConfig
.
getMainId
());
GameMainQuest
mainQuest
=
new
GameMainQuest
(
getPlayer
(),
questConfig
.
getMainId
());
get
Quests
().
put
(
mainQuest
.
getParentQuestId
(),
mainQuest
);
getMain
Quests
().
put
(
mainQuest
.
getParentQuestId
(),
mainQuest
);
getPlayer
().
sendPacket
(
new
PacketFinishedParentQuestUpdateNotify
(
mainQuest
));
getPlayer
().
sendPacket
(
new
PacketFinishedParentQuestUpdateNotify
(
mainQuest
));
...
@@ -102,18 +198,16 @@ public class QuestManager extends BasePlayerManager {
...
@@ -102,18 +198,16 @@ public class QuestManager extends BasePlayerManager {
// Sub quest
// Sub quest
GameQuest
quest
=
mainQuest
.
getChildQuestById
(
questId
);
GameQuest
quest
=
mainQuest
.
getChildQuestById
(
questId
);
if
(
quest
!=
null
)
{
// Forcefully start
return
null
;
quest
.
start
();
}
// Create
quest
=
new
GameQuest
(
mainQuest
,
questConfig
);
// Save main quest
// Save main quest
mainQuest
.
save
();
mainQuest
.
save
();
// Send packet
// Send packet
getPlayer
().
sendPacket
(
new
PacketQuestListUpdateNotify
(
quest
));
getPlayer
().
sendPacket
(
new
PacketQuestListUpdateNotify
(
mainQuest
.
getChildQuests
().
values
().
stream
()
.
filter
(
p
->
p
.
getState
()
!=
QuestState
.
QUEST_STATE_UNSTARTED
)
.
toList
()));
return
quest
;
return
quest
;
}
}
...
@@ -133,55 +227,81 @@ public class QuestManager extends BasePlayerManager {
...
@@ -133,55 +227,81 @@ public class QuestManager extends BasePlayerManager {
triggerEvent
(
condType
,
""
,
params
);
triggerEvent
(
condType
,
""
,
params
);
}
}
public
void
triggerEvent
(
QuestTrigger
condType
,
String
paramStr
,
int
...
params
)
{
//TODO
public
void
triggerEvent
(
QuestTrigger
condType
,
String
paramStr
,
int
...
params
)
{
Grasscutter
.
getLogger
().
debug
(
"Trigger Event {}, {}, {}"
,
condType
,
paramStr
,
params
);
Grasscutter
.
getLogger
().
debug
(
"Trigger Event {}, {}, {}"
,
condType
,
paramStr
,
params
);
Set
<
GameQuest
>
changedQuests
=
new
HashSet
<>();
List
<
GameMainQuest
>
checkMainQuests
=
this
.
getMainQuests
().
values
().
stream
()
.
filter
(
i
->
i
.
getState
()
!=
ParentQuestState
.
PARENT_QUEST_STATE_FINISHED
)
this
.
forEachActiveQuest
(
quest
->
{
.
toList
();
QuestData
data
=
quest
.
getData
();
switch
(
condType
){
//accept Conds
for
(
int
i
=
0
;
i
<
data
.
getFinishCond
().
size
();
i
++)
{
case
QUEST_COND_STATE_EQUAL:
if
(
quest
.
getFinishProgressList
()
==
null
case
QUEST_COND_STATE_NOT_EQUAL:
||
quest
.
getFinishProgressList
().
length
==
0
case
QUEST_COND_COMPLETE_TALK:
||
quest
.
getFinishProgressList
()[
i
]
==
1
)
{
case
QUEST_COND_LUA_NOTIFY:
continue
;
case
QUEST_COND_QUEST_VAR_EQUAL:
case
QUEST_COND_QUEST_VAR_GREATER:
case
QUEST_COND_QUEST_VAR_LESS:
case
QUEST_COND_PLAYER_LEVEL_EQUAL_GREATER:
case
QUEST_COND_QUEST_GLOBAL_VAR_EQUAL:
case
QUEST_COND_QUEST_GLOBAL_VAR_GREATER:
case
QUEST_COND_QUEST_GLOBAL_VAR_LESS:
for
(
GameMainQuest
mainquest
:
checkMainQuests
)
{
mainquest
.
tryAcceptSubQuests
(
condType
,
paramStr
,
params
);
}
}
break
;
QuestCondition
condition
=
data
.
getFinishCond
().
get
(
i
);
//fail Conds
case
QUEST_CONTENT_NOT_FINISH_PLOT:
if
(
condition
.
getType
()
!=
condType
)
{
for
(
GameMainQuest
mainquest
:
checkMainQuests
)
{
continue
;
mainquest
.
tryFailSubQuests
(
condType
,
paramStr
,
params
)
;
}
}
break
;
boolean
result
=
getPlayer
().
getServer
().
getQuestSystem
().
triggerContent
(
quest
,
condition
,
paramStr
,
params
);
//finish Conds
case
QUEST_CONTENT_COMPLETE_TALK:
if
(
result
)
{
case
QUEST_CONTENT_FINISH_PLOT:
quest
.
getFinishProgressList
()[
i
]
=
1
;
case
QUEST_CONTENT_COMPLETE_ANY_TALK:
case
QUEST_CONTENT_LUA_NOTIFY:
changedQuests
.
add
(
quest
);
case
QUEST_CONTENT_QUEST_VAR_EQUAL:
case
QUEST_CONTENT_QUEST_VAR_GREATER:
case
QUEST_CONTENT_QUEST_VAR_LESS:
case
QUEST_CONTENT_ENTER_DUNGEON:
case
QUEST_CONTENT_ENTER_ROOM:
case
QUEST_CONTENT_INTERACT_GADGET:
case
QUEST_CONTENT_TRIGGER_FIRE:
case
QUEST_CONTENT_UNLOCK_TRANS_POINT:
for
(
GameMainQuest
mainQuest
:
checkMainQuests
)
{
mainQuest
.
tryFinishSubQuests
(
condType
,
paramStr
,
params
);
}
}
}
break
;
});
//finish Or Fail Conds
for
(
GameQuest
quest
:
changedQuests
)
{
case
QUEST_CONTENT_GAME_TIME_TICK:
LogicType
logicType
=
quest
.
getData
().
getFailCondComb
();
case
QUEST_CONTENT_QUEST_STATE_EQUAL:
int
[]
progress
=
quest
.
getFinishProgressList
();
case
QUEST_CONTENT_ADD_QUEST_PROGRESS:
case
QUEST_CONTENT_LEAVE_SCENE:
// Handle logical comb
for
(
GameMainQuest
mainQuest
:
checkMainQuests
)
{
boolean
finish
=
LogicType
.
calculate
(
logicType
,
progress
);
mainQuest
.
tryFailSubQuests
(
condType
,
paramStr
,
params
);
mainQuest
.
tryFinishSubQuests
(
condType
,
paramStr
,
params
);
// Finish
}
if
(
finish
)
{
break
;
quest
.
finish
();
//QUEST_EXEC are handled directly by each subQuest
}
else
{
getPlayer
().
sendPacket
(
new
PacketQuestProgressUpdateNotify
(
quest
));
//Unused
quest
.
save
();
case
QUEST_CONTENT_QUEST_STATE_NOT_EQUAL:
}
case
QUEST_COND_PLAYER_CHOOSE_MALE:
default
:
Grasscutter
.
getLogger
().
error
(
"Unhandled QuestTrigger {}"
,
condType
);
}
}
}
if
(
this
.
addToQuestListUpdateNotify
.
size
()
!=
0
){
this
.
getPlayer
().
getSession
().
send
(
new
PacketQuestListUpdateNotify
(
this
.
addToQuestListUpdateNotify
));
this
.
addToQuestListUpdateNotify
.
clear
();
}
}
public
List
<
QuestGroupSuite
>
getSceneGroupSuite
(
int
sceneId
)
{
public
List
<
QuestGroupSuite
>
getSceneGroupSuite
(
int
sceneId
)
{
return
getQuests
().
values
().
stream
()
return
get
Main
Quests
().
values
().
stream
()
.
filter
(
i
->
i
.
getState
()
!=
ParentQuestState
.
PARENT_QUEST_STATE_FINISHED
)
.
filter
(
i
->
i
.
getState
()
!=
ParentQuestState
.
PARENT_QUEST_STATE_FINISHED
)
.
map
(
GameMainQuest:
:
getQuestGroupSuites
)
.
map
(
GameMainQuest:
:
getQuestGroupSuites
)
.
filter
(
Objects:
:
nonNull
)
.
filter
(
Objects:
:
nonNull
)
...
@@ -195,12 +315,16 @@ public class QuestManager extends BasePlayerManager {
...
@@ -195,12 +315,16 @@ public class QuestManager extends BasePlayerManager {
for
(
GameMainQuest
mainQuest
:
quests
)
{
for
(
GameMainQuest
mainQuest
:
quests
)
{
mainQuest
.
setOwner
(
this
.
getPlayer
());
mainQuest
.
setOwner
(
this
.
getPlayer
());
for
(
GameQuest
quest
:
mainQuest
.
getChildQuests
().
values
())
{
for
(
GameQuest
quest
:
mainQuest
.
getChildQuests
().
values
())
{
quest
.
setMainQuest
(
mainQuest
);
quest
.
setMainQuest
(
mainQuest
);
quest
.
setConfig
(
GameData
.
getQuestDataMap
().
get
(
quest
.
getQuestId
()));
quest
.
setConfig
(
GameData
.
getQuestDataMap
().
get
(
quest
.
get
Sub
QuestId
()));
}
}
this
.
getQuests
().
put
(
mainQuest
.
getParentQuestId
(),
mainQuest
);
this
.
getMainQuests
().
put
(
mainQuest
.
getParentQuestId
(),
mainQuest
);
}
}
}
public
List
<
GameMainQuest
>
getActiveMainQuests
()
{
return
getMainQuests
().
values
().
stream
().
filter
(
p
->
!
p
.
isFinished
()).
toList
();
}
}
}
}
src/main/java/emu/grasscutter/game/quest/conditions/ConditionLuaNotify.java
View file @
8050f0cc
...
@@ -8,7 +8,7 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
...
@@ -8,7 +8,7 @@ import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
@QuestValue
(
QuestTrigger
.
QUEST_COND_LUA_NOTIFY
)
@QuestValue
(
QuestTrigger
.
QUEST_COND_LUA_NOTIFY
)
public
class
ConditionLuaNotify
extends
QuestBaseHandler
{
public
class
ConditionLuaNotify
extends
QuestBaseHandler
{
//Wrong implementation. Example: 7010226 has no paramStr
@Override
@Override
public
boolean
execute
(
GameQuest
quest
,
QuestCondition
condition
,
String
paramStr
,
int
...
params
)
{
public
boolean
execute
(
GameQuest
quest
,
QuestCondition
condition
,
String
paramStr
,
int
...
params
)
{
return
condition
.
getParam
()[
0
]
==
Integer
.
parseInt
(
paramStr
);
return
condition
.
getParam
()[
0
]
==
Integer
.
parseInt
(
paramStr
);
...
...
src/main/java/emu/grasscutter/game/quest/conditions/ConditionStateEqual.java
View file @
8050f0cc
package
emu.grasscutter.game.quest.conditions
;
package
emu.grasscutter.game.quest.conditions
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.quest.QuestValue
;
import
emu.grasscutter.game.quest.QuestValue
;
import
emu.grasscutter.data.excels.QuestData.QuestCondition
;
import
emu.grasscutter.data.excels.QuestData.QuestCondition
;
import
emu.grasscutter.game.quest.GameQuest
;
import
emu.grasscutter.game.quest.GameQuest
;
...
@@ -11,13 +12,16 @@ public class ConditionStateEqual extends QuestBaseHandler {
...
@@ -11,13 +12,16 @@ public class ConditionStateEqual extends QuestBaseHandler {
@Override
@Override
public
boolean
execute
(
GameQuest
quest
,
QuestCondition
condition
,
String
paramStr
,
int
...
params
)
{
public
boolean
execute
(
GameQuest
quest
,
QuestCondition
condition
,
String
paramStr
,
int
...
params
)
{
GameQuest
checkQuest
=
quest
.
getOwner
().
getQuestManager
().
getQuestById
(
params
[
0
]);
GameQuest
checkQuest
=
quest
.
getOwner
().
getQuestManager
().
getQuestById
(
condition
.
getParam
()[
0
]);
if
(
checkQuest
==
null
)
{
/*
Will spam the console
//Grasscutter.getLogger().debug("Warning: quest {} hasn't been started yet!", condition.getParam()[0]);
if
(
checkQuest
!=
null
)
{
*/
return
checkQuest
.
getState
().
getValue
()
==
params
[
1
];
return
false
;
}
}
return
checkQuest
.
getState
().
getValue
()
==
condition
.
getParam
()[
1
];
return
false
;
}
}
}
}
src/main/java/emu/grasscutter/game/quest/content/ContentAddQuestProgress.java
View file @
8050f0cc
...
@@ -11,7 +11,12 @@ public class ContentAddQuestProgress extends QuestBaseHandler {
...
@@ -11,7 +11,12 @@ public class ContentAddQuestProgress extends QuestBaseHandler {
@Override
@Override
public
boolean
execute
(
GameQuest
quest
,
QuestCondition
condition
,
String
paramStr
,
int
...
params
)
{
public
boolean
execute
(
GameQuest
quest
,
QuestCondition
condition
,
String
paramStr
,
int
...
params
)
{
return
condition
.
getParam
()[
0
]
==
params
[
0
];
/*
//paramStr is a lua group, params[0] may also be a lua group!
questid = xxxxxx lua group = xxxxxxyy
count seems relevant only for lua group
*/
return
condition
.
getParam
()[
0
]
==
params
[
0
];
//missing params[1], paramStr, and count
}
}
}
}
src/main/java/emu/grasscutter/game/quest/content/ContentCompleteTalk.java
View file @
8050f0cc
package
emu.grasscutter.game.quest.content
;
package
emu.grasscutter.game.quest.content
;
import
emu.grasscutter.data.binout.MainQuestData
;
import
emu.grasscutter.game.quest.GameMainQuest
;
import
emu.grasscutter.game.quest.GameQuest
;
import
emu.grasscutter.game.quest.QuestValue
;
import
emu.grasscutter.game.quest.QuestValue
;
import
emu.grasscutter.data.excels.QuestData.QuestCondition
;
import
emu.grasscutter.data.excels.QuestData.QuestCondition
;
import
emu.grasscutter.game.quest.GameQuest
;
import
emu.grasscutter.game.quest.enums.QuestTrigger
;
import
emu.grasscutter.game.quest.enums.QuestTrigger
;
import
emu.grasscutter.game.quest.handlers.QuestBaseHandler
;
import
emu.grasscutter.game.quest.handlers.QuestBaseHandler
;
...
@@ -11,7 +13,9 @@ public class ContentCompleteTalk extends QuestBaseHandler {
...
@@ -11,7 +13,9 @@ public class ContentCompleteTalk extends QuestBaseHandler {
@Override
@Override
public
boolean
execute
(
GameQuest
quest
,
QuestCondition
condition
,
String
paramStr
,
int
...
params
)
{
public
boolean
execute
(
GameQuest
quest
,
QuestCondition
condition
,
String
paramStr
,
int
...
params
)
{
return
condition
.
getParam
()[
0
]
==
params
[
0
];
GameMainQuest
checkMainQuest
=
quest
.
getOwner
().
getQuestManager
().
getMainQuestById
(
params
[
0
]/
100
);
if
(
checkMainQuest
==
null
)
{
return
false
;}
MainQuestData
.
TalkData
talkData
=
checkMainQuest
.
getTalks
().
get
(
Integer
.
valueOf
(
params
[
0
]));
return
talkData
==
null
||
condition
.
getParamStr
().
contains
(
paramStr
)
||
checkMainQuest
.
getChildQuestById
(
params
[
0
])
!=
null
;
}
}
}
}
src/main/java/emu/grasscutter/game/quest/content/ContentEnterDungeon.java
View file @
8050f0cc
...
@@ -11,7 +11,7 @@ public class ContentEnterDungeon extends QuestBaseHandler {
...
@@ -11,7 +11,7 @@ public class ContentEnterDungeon extends QuestBaseHandler {
@Override
@Override
public
boolean
execute
(
GameQuest
quest
,
QuestCondition
condition
,
String
paramStr
,
int
...
params
)
{
public
boolean
execute
(
GameQuest
quest
,
QuestCondition
condition
,
String
paramStr
,
int
...
params
)
{
return
condition
.
getParam
()[
0
]
==
params
[
0
];
return
condition
.
getParam
()[
0
]
==
params
[
0
];
//missing params[1]
}
}
}
}
src/main/java/emu/grasscutter/game/quest/content/ContentFinishPlot.java
View file @
8050f0cc
package
emu.grasscutter.game.quest.content
;
package
emu.grasscutter.game.quest.content
;
import
emu.grasscutter.data.binout.MainQuestData
;
import
emu.grasscutter.game.quest.GameMainQuest
;
import
emu.grasscutter.game.quest.QuestValue
;
import
emu.grasscutter.game.quest.QuestValue
;
import
emu.grasscutter.data.excels.QuestData.QuestCondition
;
import
emu.grasscutter.data.excels.QuestData.QuestCondition
;
import
emu.grasscutter.game.quest.GameQuest
;
import
emu.grasscutter.game.quest.GameQuest
;
...
@@ -11,7 +13,9 @@ public class ContentFinishPlot extends QuestBaseHandler {
...
@@ -11,7 +13,9 @@ public class ContentFinishPlot extends QuestBaseHandler {
@Override
@Override
public
boolean
execute
(
GameQuest
quest
,
QuestCondition
condition
,
String
paramStr
,
int
...
params
)
{
public
boolean
execute
(
GameQuest
quest
,
QuestCondition
condition
,
String
paramStr
,
int
...
params
)
{
return
condition
.
getParam
()[
0
]
==
params
[
0
];
MainQuestData
.
TalkData
talkData
=
quest
.
getMainQuest
().
getTalks
().
get
(
Integer
.
valueOf
(
params
[
0
]));
}
GameQuest
subQuest
=
quest
.
getMainQuest
().
getChildQuestById
(
params
[
0
]);
return
talkData
!=
null
||
subQuest
!=
null
;
}
}
}
src/main/java/emu/grasscutter/game/quest/content/ContentQuestStateEqual.java
View file @
8050f0cc
...
@@ -11,13 +11,9 @@ public class ContentQuestStateEqual extends QuestBaseHandler {
...
@@ -11,13 +11,9 @@ public class ContentQuestStateEqual extends QuestBaseHandler {
@Override
@Override
public
boolean
execute
(
GameQuest
quest
,
QuestCondition
condition
,
String
paramStr
,
int
...
params
)
{
public
boolean
execute
(
GameQuest
quest
,
QuestCondition
condition
,
String
paramStr
,
int
...
params
)
{
GameQuest
checkQuest
=
quest
.
getOwner
().
getQuestManager
().
getQuestById
(
params
[
0
]);
GameQuest
checkQuest
=
quest
.
getOwner
().
getQuestManager
().
getQuestById
(
condition
.
getParam
()[
0
]);
if
(
checkQuest
==
null
)
{
return
false
;}
if
(
checkQuest
!=
null
)
{
return
checkQuest
.
getState
().
getValue
()
==
params
[
1
];
return
checkQuest
.
getState
().
getValue
()
==
params
[
1
];
}
return
false
;
}
}
}
}
src/main/java/emu/grasscutter/game/quest/enums/QuestState.java
View file @
8050f0cc
...
@@ -5,10 +5,17 @@ public enum QuestState {
...
@@ -5,10 +5,17 @@ public enum QuestState {
QUEST_STATE_UNSTARTED
(
1
),
QUEST_STATE_UNSTARTED
(
1
),
QUEST_STATE_UNFINISHED
(
2
),
QUEST_STATE_UNFINISHED
(
2
),
QUEST_STATE_FINISHED
(
3
),
QUEST_STATE_FINISHED
(
3
),
QUEST_STATE_FAILED
(
4
);
QUEST_STATE_FAILED
(
4
),
// Used by lua
NONE
(
0
),
UNSTARTED
(
1
),
UNFINISHED
(
2
),
FINISHED
(
3
),
FAILED
(
4
);
private
final
int
value
;
private
final
int
value
;
QuestState
(
int
id
)
{
QuestState
(
int
id
)
{
this
.
value
=
id
;
this
.
value
=
id
;
}
}
...
...
src/main/java/emu/grasscutter/scripts/SceneScriptManager.java
View file @
8050f0cc
...
@@ -92,6 +92,7 @@ public class SceneScriptManager {
...
@@ -92,6 +92,7 @@ public class SceneScriptManager {
}
}
public
void
registerTrigger
(
SceneTrigger
trigger
)
{
public
void
registerTrigger
(
SceneTrigger
trigger
)
{
getTriggersByEvent
(
trigger
.
event
).
add
(
trigger
);
getTriggersByEvent
(
trigger
.
event
).
add
(
trigger
);
Grasscutter
.
getLogger
().
debug
(
"Registered trigger {}"
,
trigger
.
name
);
}
}
public
void
deregisterTrigger
(
List
<
SceneTrigger
>
triggers
)
{
public
void
deregisterTrigger
(
List
<
SceneTrigger
>
triggers
)
{
triggers
.
forEach
(
this
::
deregisterTrigger
);
triggers
.
forEach
(
this
::
deregisterTrigger
);
...
@@ -122,6 +123,7 @@ public class SceneScriptManager {
...
@@ -122,6 +123,7 @@ public class SceneScriptManager {
public
void
registerRegion
(
EntityRegion
region
)
{
public
void
registerRegion
(
EntityRegion
region
)
{
regions
.
put
(
region
.
getId
(),
region
);
regions
.
put
(
region
.
getId
(),
region
);
Grasscutter
.
getLogger
().
debug
(
"Registered region {} from group {}"
,
region
.
getMetaRegion
().
config_id
,
region
.
getGroupId
());
}
}
public
void
registerRegionInGroupSuite
(
SceneGroup
group
,
SceneSuite
suite
){
public
void
registerRegionInGroupSuite
(
SceneGroup
group
,
SceneSuite
suite
){
suite
.
sceneRegions
.
stream
().
map
(
region
->
new
EntityRegion
(
this
.
getScene
(),
region
))
suite
.
sceneRegions
.
stream
().
map
(
region
->
new
EntityRegion
(
this
.
getScene
(),
region
))
...
@@ -195,9 +197,30 @@ public class SceneScriptManager {
...
@@ -195,9 +197,30 @@ public class SceneScriptManager {
.
filter
(
e
->
e
.
getEntityType
()
==
EntityType
.
Avatar
.
getValue
()
&&
region
.
getMetaRegion
().
contains
(
e
.
getPosition
()))
.
filter
(
e
->
e
.
getEntityType
()
==
EntityType
.
Avatar
.
getValue
()
&&
region
.
getMetaRegion
().
contains
(
e
.
getPosition
()))
.
forEach
(
region:
:
addEntity
);
.
forEach
(
region:
:
addEntity
);
var
players
=
region
.
getScene
().
getPlayers
();
int
targetID
=
0
;
if
(
players
.
size
()
>
0
)
targetID
=
players
.
get
(
0
).
getUid
();
if
(
region
.
hasNewEntities
())
{
if
(
region
.
hasNewEntities
())
{
Grasscutter
.
getLogger
().
trace
(
"Call EVENT_ENTER_REGION_{}"
,
region
.
getMetaRegion
().
config_id
);
callEvent
(
EventType
.
EVENT_ENTER_REGION
,
new
ScriptArgs
(
region
.
getConfigId
())
callEvent
(
EventType
.
EVENT_ENTER_REGION
,
new
ScriptArgs
(
region
.
getConfigId
())
.
setSourceEntityId
(
region
.
getId
())
.
setSourceEntityId
(
region
.
getId
())
.
setTargetEntityId
(
targetID
)
);
region
.
resetNewEntities
();
}
for
(
int
entityId
:
region
.
getEntities
())
{
if
(!
region
.
getMetaRegion
().
contains
(
getScene
().
getEntityById
(
entityId
).
getPosition
()))
{
region
.
removeEntity
(
entityId
);
}
}
if
(
region
.
entityLeave
())
{
callEvent
(
EventType
.
EVENT_LEAVE_REGION
,
new
ScriptArgs
(
region
.
getConfigId
())
.
setSourceEntityId
(
region
.
getId
())
.
setTargetEntityId
(
region
.
getFirstEntityId
())
.
setTargetEntityId
(
region
.
getFirstEntityId
())
);
);
...
@@ -286,27 +309,39 @@ public class SceneScriptManager {
...
@@ -286,27 +309,39 @@ public class SceneScriptManager {
}
}
private
void
realCallEvent
(
int
eventType
,
ScriptArgs
params
)
{
private
void
realCallEvent
(
int
eventType
,
ScriptArgs
params
)
{
try
{
try
{
ScriptLoader
.
getScriptLib
().
setSceneScriptManager
(
this
);
Set
<
SceneTrigger
>
relevantTriggers
=
new
HashSet
<>();
for
(
SceneTrigger
trigger
:
this
.
getTriggersByEvent
(
eventType
))
{
if
(
eventType
==
EventType
.
EVENT_ENTER_REGION
||
eventType
==
EventType
.
EVENT_LEAVE_REGION
)
{
try
{
List
<
SceneTrigger
>
relevantTriggersList
=
this
.
getTriggersByEvent
(
eventType
).
stream
()
ScriptLoader
.
getScriptLib
().
setCurrentGroup
(
trigger
.
currentGroup
);
.
filter
(
p
->
p
.
condition
.
contains
(
String
.
valueOf
(
params
.
param1
))).
toList
();
relevantTriggers
=
new
HashSet
<>(
relevantTriggersList
);
LuaValue
ret
=
callScriptFunc
(
trigger
.
condition
,
trigger
.
currentGroup
,
params
);
}
else
{
relevantTriggers
=
this
.
getTriggersByEvent
(
eventType
);}
Grasscutter
.
getLogger
().
trace
(
"Call Condition Trigger {}"
,
trigger
.
condition
);
for
(
SceneTrigger
trigger
:
relevantTriggers
)
{
try
{
if
(
ret
.
isboolean
()
&&
ret
.
checkboolean
())
{
ScriptLoader
.
getScriptLib
().
setCurrentGroup
(
trigger
.
currentGroup
);
// the SetGroupVariableValueByGroup in tower need the param to record the first stage time
LuaValue
ret
=
this
.
callScriptFunc
(
trigger
.
condition
,
trigger
.
currentGroup
,
params
);
callScriptFunc
(
trigger
.
action
,
trigger
.
currentGroup
,
params
);
Grasscutter
.
getLogger
().
trace
(
"Call Condition Trigger {}, [{},{},{}]"
,
trigger
.
condition
,
params
.
param1
,
params
.
source_eid
,
params
.
target_eid
);
Grasscutter
.
getLogger
().
trace
(
"Call Action Trigger {}"
,
trigger
.
action
);
if
(
ret
.
isboolean
()
&&
ret
.
checkboolean
())
{
}
// the SetGroupVariableValueByGroup in tower need the param to record the first stage time
//TODO some ret may not bool
this
.
callScriptFunc
(
trigger
.
action
,
trigger
.
currentGroup
,
params
);
Grasscutter
.
getLogger
().
trace
(
"Call Action Trigger {}"
,
trigger
.
action
);
}
finally
{
if
(
trigger
.
event
==
EventType
.
EVENT_ENTER_REGION
)
{
ScriptLoader
.
getScriptLib
().
removeCurrentGroup
();
EntityRegion
region
=
this
.
regions
.
values
().
stream
().
filter
(
p
->
p
.
getConfigId
()
==
params
.
param1
).
toList
().
get
(
0
);
}
getScene
().
getPlayers
().
forEach
(
p
->
p
.
onEnterRegion
(
region
.
getMetaRegion
()));
}
}
else
if
(
trigger
.
event
==
EventType
.
EVENT_LEAVE_REGION
)
{
}
finally
{
EntityRegion
region
=
this
.
regions
.
values
().
stream
().
filter
(
p
->
p
.
getConfigId
()
==
params
.
param1
).
toList
().
get
(
0
);
getScene
().
getPlayers
().
forEach
(
p
->
p
.
onLeaveRegion
(
region
.
getMetaRegion
()));
}
deregisterTrigger
(
trigger
);
}
else
{
Grasscutter
.
getLogger
().
debug
(
"Condition Trigger {} returned {}"
,
trigger
.
condition
,
ret
);
}
//TODO some ret do not bool
}
finally
{
ScriptLoader
.
getScriptLib
().
removeCurrentGroup
();
}
}
}
finally
{
// make sure it is removed
// make sure it is removed
ScriptLoader
.
getScriptLib
().
removeSceneScriptManager
();
ScriptLoader
.
getScriptLib
().
removeSceneScriptManager
();
}
}
...
...
src/main/java/emu/grasscutter/scripts/data/SceneRegion.java
View file @
8050f0cc
...
@@ -26,7 +26,8 @@ public class SceneRegion {
...
@@ -26,7 +26,8 @@ public class SceneRegion {
var
x
=
Math
.
pow
(
pos
.
getX
()
-
position
.
getX
(),
2
);
var
x
=
Math
.
pow
(
pos
.
getX
()
-
position
.
getX
(),
2
);
var
y
=
Math
.
pow
(
pos
.
getY
()
-
position
.
getY
(),
2
);
var
y
=
Math
.
pow
(
pos
.
getY
()
-
position
.
getY
(),
2
);
var
z
=
Math
.
pow
(
pos
.
getZ
()
-
position
.
getZ
(),
2
);
var
z
=
Math
.
pow
(
pos
.
getZ
()
-
position
.
getZ
(),
2
);
return
x
+
y
+
z
<=
(
radius
^
2
);
// ^ means XOR in java!
return
x
+
y
+
z
<=
(
radius
*
radius
);
}
}
return
false
;
return
false
;
}
}
...
...
src/main/java/emu/grasscutter/scripts/serializer/LuaSerializer.java
View file @
8050f0cc
...
@@ -29,22 +29,70 @@ public class LuaSerializer implements Serializer {
...
@@ -29,22 +29,70 @@ public class LuaSerializer implements Serializer {
public
<
T
>
T
toObject
(
Class
<
T
>
type
,
Object
obj
)
{
public
<
T
>
T
toObject
(
Class
<
T
>
type
,
Object
obj
)
{
return
serialize
(
type
,
(
LuaTable
)
obj
);
return
serialize
(
type
,
(
LuaTable
)
obj
);
}
}
public
<
T
>
List
<
T
>
serializeList
(
Class
<
T
>
type
,
LuaTable
table
)
{
@Override
public
<
T
>
Map
<
String
,
T
>
toMap
(
Class
<
T
>
type
,
Object
obj
)
{
return
serializeMap
(
type
,
(
LuaTable
)
obj
);
}
private
<
T
>
Map
<
String
,
T
>
serializeMap
(
Class
<
T
>
type
,
LuaTable
table
)
{
Map
<
String
,
T
>
map
=
new
HashMap
<>();
if
(
table
==
null
)
{
return
map
;
}
try
{
LuaValue
[]
keys
=
table
.
keys
();
for
(
LuaValue
k
:
keys
)
{
try
{
LuaValue
keyValue
=
table
.
get
(
k
);
T
object
=
null
;
if
(
keyValue
.
istable
())
{
object
=
serialize
(
type
,
keyValue
.
checktable
());
}
else
if
(
keyValue
.
isint
())
{
object
=
(
T
)
(
Integer
)
keyValue
.
toint
();
}
else
if
(
keyValue
.
isnumber
())
{
object
=
(
T
)
(
Float
)
keyValue
.
tofloat
();
// terrible...
}
else
if
(
keyValue
.
isstring
())
{
object
=
(
T
)
keyValue
.
tojstring
();
}
else
if
(
keyValue
.
isboolean
())
{
object
=
(
T
)
(
Boolean
)
keyValue
.
toboolean
();
}
else
{
object
=
(
T
)
keyValue
;
}
if
(
object
!=
null
)
{
map
.
put
(
String
.
valueOf
(
k
),
object
);
}
}
catch
(
Exception
ex
)
{
}
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
return
map
;
}
public
<
T
>
List
<
T
>
serializeList
(
Class
<
T
>
type
,
LuaTable
table
)
{
List
<
T
>
list
=
new
ArrayList
<>();
List
<
T
>
list
=
new
ArrayList
<>();
if
(
table
==
null
)
{
if
(
table
==
null
)
{
return
list
;
return
list
;
}
}
try
{
try
{
LuaValue
[]
keys
=
table
.
keys
();
LuaValue
[]
keys
=
table
.
keys
();
for
(
LuaValue
k
:
keys
)
{
for
(
LuaValue
k
:
keys
)
{
try
{
try
{
LuaValue
keyValue
=
table
.
get
(
k
);
LuaValue
keyValue
=
table
.
get
(
k
);
T
object
=
null
;
T
object
=
null
;
if
(
keyValue
.
istable
())
{
if
(
keyValue
.
istable
())
{
object
=
serialize
(
type
,
keyValue
.
checktable
());
object
=
serialize
(
type
,
keyValue
.
checktable
());
}
else
if
(
keyValue
.
isint
())
{
}
else
if
(
keyValue
.
isint
())
{
...
@@ -75,7 +123,7 @@ public class LuaSerializer implements Serializer {
...
@@ -75,7 +123,7 @@ public class LuaSerializer implements Serializer {
public
<
T
>
T
serialize
(
Class
<
T
>
type
,
LuaTable
table
)
{
public
<
T
>
T
serialize
(
Class
<
T
>
type
,
LuaTable
table
)
{
T
object
=
null
;
T
object
=
null
;
if
(
type
==
List
.
class
)
{
if
(
type
==
List
.
class
)
{
try
{
try
{
Class
<
T
>
listType
=
(
Class
<
T
>)
type
.
getTypeParameters
()[
0
].
getClass
();
Class
<
T
>
listType
=
(
Class
<
T
>)
type
.
getTypeParameters
()[
0
].
getClass
();
...
@@ -85,7 +133,7 @@ public class LuaSerializer implements Serializer {
...
@@ -85,7 +133,7 @@ public class LuaSerializer implements Serializer {
return
null
;
return
null
;
}
}
}
}
try
{
try
{
if
(!
methodAccessCache
.
containsKey
(
type
))
{
if
(!
methodAccessCache
.
containsKey
(
type
))
{
cacheType
(
type
);
cacheType
(
type
);
...
@@ -98,7 +146,7 @@ public class LuaSerializer implements Serializer {
...
@@ -98,7 +146,7 @@ public class LuaSerializer implements Serializer {
if
(
table
==
null
)
{
if
(
table
==
null
)
{
return
object
;
return
object
;
}
}
LuaValue
[]
keys
=
table
.
keys
();
LuaValue
[]
keys
=
table
.
keys
();
for
(
LuaValue
k
:
keys
)
{
for
(
LuaValue
k
:
keys
)
{
try
{
try
{
...
@@ -131,7 +179,7 @@ public class LuaSerializer implements Serializer {
...
@@ -131,7 +179,7 @@ public class LuaSerializer implements Serializer {
Grasscutter
.
getLogger
().
info
(
ScriptUtils
.
toMap
(
table
).
toString
());
Grasscutter
.
getLogger
().
info
(
ScriptUtils
.
toMap
(
table
).
toString
());
e
.
printStackTrace
();
e
.
printStackTrace
();
}
}
return
object
;
return
object
;
}
}
...
...
src/main/java/emu/grasscutter/scripts/serializer/Serializer.java
View file @
8050f0cc
package
emu.grasscutter.scripts.serializer
;
package
emu.grasscutter.scripts.serializer
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
org.luaj.vm2.LuaTable
;
public
interface
Serializer
{
public
interface
Serializer
{
public
<
T
>
List
<
T
>
toList
(
Class
<
T
>
type
,
Object
obj
);
public
<
T
>
List
<
T
>
toList
(
Class
<
T
>
type
,
Object
obj
);
public
<
T
>
T
toObject
(
Class
<
T
>
type
,
Object
obj
);
public
<
T
>
T
toObject
(
Class
<
T
>
type
,
Object
obj
);
public
<
T
>
Map
<
String
,
T
>
toMap
(
Class
<
T
>
type
,
Object
obj
);
}
}
src/main/java/emu/grasscutter/server/packet/recv/HandlerAddQuestContentProgressReq.java
View file @
8050f0cc
package
emu.grasscutter.server.packet.recv
;
package
emu.grasscutter.server.packet.recv
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.excels.QuestData
;
import
emu.grasscutter.game.quest.GameQuest
;
import
emu.grasscutter.game.quest.enums.QuestTrigger
;
import
emu.grasscutter.game.quest.enums.QuestTrigger
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.packet.PacketHandler
;
...
@@ -7,6 +10,9 @@ import emu.grasscutter.net.packet.PacketOpcodes;
...
@@ -7,6 +10,9 @@ import emu.grasscutter.net.packet.PacketOpcodes;
import
emu.grasscutter.net.proto.AddQuestContentProgressReqOuterClass
;
import
emu.grasscutter.net.proto.AddQuestContentProgressReqOuterClass
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.PacketAddQuestContentProgressRsp
;
import
emu.grasscutter.server.packet.send.PacketAddQuestContentProgressRsp
;
import
emu.grasscutter.data.excels.QuestData.QuestCondition
;
import
java.util.List
;
import
java.util.stream.Stream
;
@Opcodes
(
PacketOpcodes
.
AddQuestContentProgressReq
)
@Opcodes
(
PacketOpcodes
.
AddQuestContentProgressReq
)
public
class
HandlerAddQuestContentProgressReq
extends
PacketHandler
{
public
class
HandlerAddQuestContentProgressReq
extends
PacketHandler
{
...
@@ -14,9 +20,14 @@ public class HandlerAddQuestContentProgressReq extends PacketHandler {
...
@@ -14,9 +20,14 @@ public class HandlerAddQuestContentProgressReq extends PacketHandler {
@Override
@Override
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
var
req
=
AddQuestContentProgressReqOuterClass
.
AddQuestContentProgressReq
.
parseFrom
(
payload
);
var
req
=
AddQuestContentProgressReqOuterClass
.
AddQuestContentProgressReq
.
parseFrom
(
payload
);
//Find all conditions in quest that are the same as the given one
session
.
getPlayer
().
getQuestManager
().
triggerEvent
(
QuestTrigger
.
getContentTriggerByValue
(
req
.
getContentType
()),
req
.
getParam
());
Stream
<
QuestCondition
>
finishCond
=
GameData
.
getQuestDataMap
().
get
(
req
.
getParam
()).
getFinishCond
().
stream
();
Stream
<
QuestCondition
>
acceptCond
=
GameData
.
getQuestDataMap
().
get
(
req
.
getParam
()).
getAcceptCond
().
stream
();
Stream
<
QuestCondition
>
failCond
=
GameData
.
getQuestDataMap
().
get
(
req
.
getParam
()).
getFailCond
().
stream
();
List
<
QuestCondition
>
allCondMatch
=
Stream
.
concat
(
Stream
.
concat
(
acceptCond
,
failCond
),
finishCond
).
filter
(
p
->
p
.
getType
().
getValue
()
==
req
.
getContentType
()).
toList
();
for
(
QuestCondition
cond
:
allCondMatch
)
{
session
.
getPlayer
().
getQuestManager
().
triggerEvent
(
QuestTrigger
.
getContentTriggerByValue
(
req
.
getContentType
()),
cond
.
getParam
());
}
session
.
send
(
new
PacketAddQuestContentProgressRsp
(
req
.
getContentType
()));
session
.
send
(
new
PacketAddQuestContentProgressRsp
(
req
.
getContentType
()));
}
}
...
...
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment