Files

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
}