134 lines
3.4 KiB
Go
134 lines
3.4 KiB
Go
package gameserver
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"gac-hkrpg-go/internal/common"
|
|
goproto "gac-hkrpg-go/protocol/proto"
|
|
"sync"
|
|
)
|
|
|
|
type destructibleRule struct {
|
|
Path string `json:"json_path"`
|
|
RecoverMP uint32 `json:"recover_mp"`
|
|
}
|
|
|
|
var propRulesOnce sync.Once
|
|
var propRules map[uint32]destructibleRule
|
|
var propRulesError error
|
|
|
|
func loadPropRules() (map[uint32]destructibleRule, error) {
|
|
propRulesOnce.Do(func() {
|
|
raw, err := common.ReadResourceFile("resources/PropInteractionConfig.json")
|
|
if err != nil {
|
|
propRulesError = err
|
|
return
|
|
}
|
|
var data struct {
|
|
ClientVersion string `json:"client_version"`
|
|
Props map[uint32]destructibleRule `json:"destructibles"`
|
|
}
|
|
if err = json.Unmarshal(raw, &data); err != nil {
|
|
propRulesError = err
|
|
return
|
|
}
|
|
cfg, err := common.LoadRuntimeConfig()
|
|
if err != nil {
|
|
propRulesError = err
|
|
return
|
|
}
|
|
if cfg.ClientVersion != data.ClientVersion || len(data.Props) == 0 {
|
|
propRulesError = fmt.Errorf("destructible resource missing or Client revision mismatch")
|
|
return
|
|
}
|
|
propRules = data.Props
|
|
})
|
|
return propRules, propRulesError
|
|
}
|
|
|
|
func (s *Session) hitSceneProps(req *goproto.SceneCastSkillCsReq) []uint32 {
|
|
if s.techniqueAvatar(req.CasterId) == 0 {
|
|
return nil
|
|
}
|
|
if _, active := CURRENT_BATTLE.Load(s.Token); active {
|
|
return nil
|
|
}
|
|
rules, err := loadPropRules()
|
|
if err != nil {
|
|
Log("[PROP] " + err.Error())
|
|
return nil
|
|
}
|
|
var ids []uint32
|
|
seen := map[uint32]bool{}
|
|
add := func(id uint32) {
|
|
if p, ok := s.PropEntities[id]; ok {
|
|
if _, destructible := rules[p.PropID]; destructible && !seen[id] {
|
|
seen[id] = true
|
|
ids = append(ids, id)
|
|
}
|
|
}
|
|
}
|
|
for _, id := range req.HitTargetEntityIdList {
|
|
add(id)
|
|
}
|
|
for _, id := range req.AssistMonsterEntityIdList {
|
|
add(id)
|
|
}
|
|
for _, group := range req.AssistMonsterEntityInfo {
|
|
for _, id := range group.GetEntityIdList() {
|
|
add(id)
|
|
}
|
|
}
|
|
return ids
|
|
}
|
|
|
|
func (s *Session) breakSceneProps(ids []uint32) error {
|
|
rules, err := loadPropRules()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
lineup := s.techniqueLineup()
|
|
if lineup == nil {
|
|
return nil
|
|
}
|
|
notify := &goproto.SceneGroupRefreshScNotify{FloorId: s.CurrentSceneFloor}
|
|
groups := map[uint32]*goproto.SceneGroupRefreshInfo{}
|
|
var recover uint32
|
|
for _, id := range ids {
|
|
prop, exists := s.PropEntities[id]
|
|
if !exists {
|
|
continue
|
|
}
|
|
rule, ok := rules[prop.PropID]
|
|
if !ok {
|
|
continue
|
|
}
|
|
group := groups[prop.GroupID]
|
|
if group == nil {
|
|
group = &goproto.SceneGroupRefreshInfo{GroupId: prop.GroupID, State: 1, GroupRefreshType: goproto.SceneGroupRefreshType_SCENE_GROUP_REFRESH_TYPE_LOADED}
|
|
groups[prop.GroupID] = group
|
|
}
|
|
group.RefreshEntity = append(group.RefreshEntity, &goproto.SceneEntityRefreshInfo{RefreshType: &goproto.SceneEntityRefreshInfo_DeleteEntity{DeleteEntity: id}})
|
|
recover += rule.RecoverMP
|
|
delete(s.PropEntities, id)
|
|
SceneDebugLog("[PROP] destroyed entity=%d prop=%d recover_mp=%d", id, prop.PropID, rule.RecoverMP)
|
|
}
|
|
for _, id := range sortedU32Keys2(groups) {
|
|
notify.GroupRefreshInfo = append(notify.GroupRefreshInfo, groups[id])
|
|
}
|
|
if len(notify.GroupRefreshInfo) > 0 {
|
|
if err = s.Send(notify); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if recover > 0 {
|
|
remaining := lineup.MaxMp - *s.techniqueMP
|
|
if recover > remaining {
|
|
recover = remaining
|
|
}
|
|
*s.techniqueMP += recover
|
|
return s.syncTechnique(goproto.SyncLineupReason_SyncLineupReason_SyncReasonMpAdd)
|
|
}
|
|
return nil
|
|
}
|