mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2026-02-04 14:32:26 +08:00
简化配置表读取
This commit is contained in:
21
Makefile
21
Makefile
@@ -8,8 +8,8 @@ all: build
|
|||||||
# 清理
|
# 清理
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm -rf ./bin
|
rm -rf ./bin/*
|
||||||
rm -rf ./protocol/proto
|
rm -rf ./protocol/proto/*
|
||||||
rm -rf ./gate/client_proto/client_proto_gen.go
|
rm -rf ./gate/client_proto/client_proto_gen.go
|
||||||
rm -rf ./gs/api/*.pb.go && rm -rf ./node/api/*.pb.go
|
rm -rf ./gs/api/*.pb.go && rm -rf ./node/api/*.pb.go
|
||||||
|
|
||||||
@@ -24,14 +24,14 @@ docker_clean:
|
|||||||
rm -rf ./docker/node/bin/node
|
rm -rf ./docker/node/bin/node
|
||||||
rm -rf ./docker/dispatch/bin/dispatch
|
rm -rf ./docker/dispatch/bin/dispatch
|
||||||
rm -rf ./docker/gate/bin/gate
|
rm -rf ./docker/gate/bin/gate
|
||||||
rm -rf ./docker/fight/bin/fight
|
rm -rf ./docker/anticheat/bin/anticheat
|
||||||
rm -rf ./docker/pathfinding/bin/pathfinding
|
rm -rf ./docker/pathfinding/bin/pathfinding
|
||||||
rm -rf ./docker/gs/bin/gs
|
rm -rf ./docker/gs/bin/gs
|
||||||
rm -rf ./docker/gm/bin/gm
|
rm -rf ./docker/gm/bin/gm
|
||||||
docker rmi flswld/node:$(VERSION)
|
docker rmi flswld/node:$(VERSION)
|
||||||
docker rmi flswld/dispatch:$(VERSION)
|
docker rmi flswld/dispatch:$(VERSION)
|
||||||
docker rmi flswld/gate:$(VERSION)
|
docker rmi flswld/gate:$(VERSION)
|
||||||
docker rmi flswld/fight:$(VERSION)
|
docker rmi flswld/anticheat:$(VERSION)
|
||||||
docker rmi flswld/pathfinding:$(VERSION)
|
docker rmi flswld/pathfinding:$(VERSION)
|
||||||
docker rmi flswld/gs:$(VERSION)
|
docker rmi flswld/gs:$(VERSION)
|
||||||
docker rmi flswld/gm:$(VERSION)
|
docker rmi flswld/gm:$(VERSION)
|
||||||
@@ -43,7 +43,7 @@ docker_config:
|
|||||||
mkdir -p ./docker/node/bin && cp -rf ./cmd/node/* ./docker/node/bin/
|
mkdir -p ./docker/node/bin && cp -rf ./cmd/node/* ./docker/node/bin/
|
||||||
mkdir -p ./docker/dispatch/bin && cp -rf ./cmd/dispatch/* ./docker/dispatch/bin/
|
mkdir -p ./docker/dispatch/bin && cp -rf ./cmd/dispatch/* ./docker/dispatch/bin/
|
||||||
mkdir -p ./docker/gate/bin && cp -rf ./cmd/gate/* ./docker/gate/bin/
|
mkdir -p ./docker/gate/bin && cp -rf ./cmd/gate/* ./docker/gate/bin/
|
||||||
mkdir -p ./docker/fight/bin && cp -rf ./cmd/fight/* ./docker/fight/bin/
|
mkdir -p ./docker/anticheat/bin && cp -rf ./cmd/anticheat/* ./docker/anticheat/bin/
|
||||||
mkdir -p ./docker/pathfinding/bin && cp -rf ./cmd/pathfinding/* ./docker/pathfinding/bin/
|
mkdir -p ./docker/pathfinding/bin && cp -rf ./cmd/pathfinding/* ./docker/pathfinding/bin/
|
||||||
mkdir -p ./docker/gs/bin && cp -rf ./cmd/gs/* ./docker/gs/bin/
|
mkdir -p ./docker/gs/bin && cp -rf ./cmd/gs/* ./docker/gs/bin/
|
||||||
mkdir -p ./docker/gm/bin && cp -rf ./cmd/gm/* ./docker/gm/bin/
|
mkdir -p ./docker/gm/bin && cp -rf ./cmd/gm/* ./docker/gm/bin/
|
||||||
@@ -54,14 +54,14 @@ docker_build:
|
|||||||
mkdir -p ./docker/node/bin && cp -rf ./bin/node ./docker/node/bin/
|
mkdir -p ./docker/node/bin && cp -rf ./bin/node ./docker/node/bin/
|
||||||
mkdir -p ./docker/dispatch/bin && cp -rf ./bin/dispatch ./docker/dispatch/bin/
|
mkdir -p ./docker/dispatch/bin && cp -rf ./bin/dispatch ./docker/dispatch/bin/
|
||||||
mkdir -p ./docker/gate/bin && cp -rf ./bin/gate ./docker/gate/bin/
|
mkdir -p ./docker/gate/bin && cp -rf ./bin/gate ./docker/gate/bin/
|
||||||
mkdir -p ./docker/fight/bin && cp -rf ./bin/fight ./docker/fight/bin/
|
mkdir -p ./docker/anticheat/bin && cp -rf ./bin/anticheat ./docker/anticheat/bin/
|
||||||
mkdir -p ./docker/pathfinding/bin && cp -rf ./bin/pathfinding ./docker/pathfinding/bin/
|
mkdir -p ./docker/pathfinding/bin && cp -rf ./bin/pathfinding ./docker/pathfinding/bin/
|
||||||
mkdir -p ./docker/gs/bin && cp -rf ./bin/gs ./docker/gs/bin/
|
mkdir -p ./docker/gs/bin && cp -rf ./bin/gs ./docker/gs/bin/
|
||||||
mkdir -p ./docker/gm/bin && cp -rf ./bin/gm ./docker/gm/bin/
|
mkdir -p ./docker/gm/bin && cp -rf ./bin/gm ./docker/gm/bin/
|
||||||
docker build -t flswld/node:$(VERSION) ./docker/node
|
docker build -t flswld/node:$(VERSION) ./docker/node
|
||||||
docker build -t flswld/dispatch:$(VERSION) ./docker/dispatch
|
docker build -t flswld/dispatch:$(VERSION) ./docker/dispatch
|
||||||
docker build -t flswld/gate:$(VERSION) ./docker/gate
|
docker build -t flswld/gate:$(VERSION) ./docker/gate
|
||||||
docker build -t flswld/fight:$(VERSION) ./docker/fight
|
docker build -t flswld/anticheat:$(VERSION) ./docker/anticheat
|
||||||
docker build -t flswld/pathfinding:$(VERSION) ./docker/pathfinding
|
docker build -t flswld/pathfinding:$(VERSION) ./docker/pathfinding
|
||||||
docker build -t flswld/gs:$(VERSION) ./docker/gs
|
docker build -t flswld/gs:$(VERSION) ./docker/gs
|
||||||
docker build -t flswld/gm:$(VERSION) ./docker/gm
|
docker build -t flswld/gm:$(VERSION) ./docker/gm
|
||||||
@@ -69,7 +69,7 @@ docker_build:
|
|||||||
# 安装natsrpc生成工具
|
# 安装natsrpc生成工具
|
||||||
.PHONY: dev_tool
|
.PHONY: dev_tool
|
||||||
dev_tool:
|
dev_tool:
|
||||||
go install github.com/golang/protobuf/protoc-gen-go@v1.5.2
|
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28.1
|
||||||
go install github.com/byebyebruce/natsrpc/cmd/protoc-gen-natsrpc@develop
|
go install github.com/byebyebruce/natsrpc/cmd/protoc-gen-natsrpc@develop
|
||||||
|
|
||||||
# 生成natsrpc协议代码
|
# 生成natsrpc协议代码
|
||||||
@@ -101,11 +101,6 @@ gen_proto:
|
|||||||
rm -rf ../proto && mkdir -p ../proto && mv ./proto/* ../proto/ && rm -rf ./proto && \
|
rm -rf ../proto && mkdir -p ../proto && mv ./proto/* ../proto/ && rm -rf ./proto && \
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
# 生成服务器配置表
|
|
||||||
.PHONY: gen_csv
|
|
||||||
gen_csv:
|
|
||||||
cd gdconf && mkdir -p ./game_data_config/csv && go test -count=1 -v -run TestGenGdCsv .
|
|
||||||
|
|
||||||
# 生成客户端协议代理功能所需的代码
|
# 生成客户端协议代理功能所需的代码
|
||||||
.PHONY: gen_client_proto
|
.PHONY: gen_client_proto
|
||||||
gen_client_proto:
|
gen_client_proto:
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
* Docker >= 20.10
|
* Docker >= 20.10
|
||||||
* Docker Compose >= 1.29
|
* Docker Compose >= 1.29
|
||||||
|
|
||||||
#### 本项目未使用CGO构建,理论上Windows、Linux、MaxOS系统都可以编译运行
|
#### 本项目未使用CGO构建,理论上Windows、Linux、macOS系统都可以编译运行
|
||||||
|
|
||||||
## 快速启动
|
## 快速启动
|
||||||
|
|
||||||
@@ -60,7 +60,6 @@ make docker_build # 构建镜像
|
|||||||
* 启动
|
* 启动
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
make gen_csv # 生成配置表
|
|
||||||
cd docker
|
cd docker
|
||||||
# 启动前请先确保各服务器的配置文件正确(如docker/node/bin/application.toml)
|
# 启动前请先确保各服务器的配置文件正确(如docker/node/bin/application.toml)
|
||||||
docker-compose up -d # 启动服务器
|
docker-compose up -d # 启动服务器
|
||||||
@@ -77,8 +76,8 @@ docker-compose up -d # 启动服务器
|
|||||||
* node 节点服务器 (仅单节点 有状态)
|
* node 节点服务器 (仅单节点 有状态)
|
||||||
* dispatch 登录服务器 (可多节点 无状态)
|
* dispatch 登录服务器 (可多节点 无状态)
|
||||||
* gate 网关服务器 (可多节点 有状态)
|
* gate 网关服务器 (可多节点 有状态)
|
||||||
* fight 战斗服务器 (可多节点 有状态 非必要 未启动由gs接管)
|
* anticheat 反作弊服务器 (可多节点 有状态 尚不完善非必要启动)
|
||||||
* pathfinding 寻路服务器 (可多节点 无状态 非必要 未启动由gs接管)
|
* pathfinding 寻路服务器 (可多节点 无状态 尚不完善非必要启动)
|
||||||
* gs 游戏服务器 (可多节点 有状态)
|
* gs 游戏服务器 (可多节点 有状态)
|
||||||
* gm 游戏管理服务器 (仅单节点 无状态)
|
* gm 游戏管理服务器 (仅单节点 无状态)
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"hk4e/common/config"
|
"hk4e/common/config"
|
||||||
"hk4e/common/mq"
|
"hk4e/common/mq"
|
||||||
"hk4e/common/rpc"
|
"hk4e/common/rpc"
|
||||||
"hk4e/fight/engine"
|
|
||||||
"hk4e/node/api"
|
"hk4e/node/api"
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
)
|
)
|
||||||
@@ -29,7 +28,7 @@ func Run(ctx context.Context, configFile string) error {
|
|||||||
|
|
||||||
// 注册到节点服务器
|
// 注册到节点服务器
|
||||||
rsp, err := client.Discovery.RegisterServer(context.TODO(), &api.RegisterServerReq{
|
rsp, err := client.Discovery.RegisterServer(context.TODO(), &api.RegisterServerReq{
|
||||||
ServerType: api.FIGHT,
|
ServerType: api.ANTICHEAT,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -40,7 +39,7 @@ func Run(ctx context.Context, configFile string) error {
|
|||||||
for {
|
for {
|
||||||
<-ticker.C
|
<-ticker.C
|
||||||
_, err := client.Discovery.KeepaliveServer(context.TODO(), &api.KeepaliveServerReq{
|
_, err := client.Discovery.KeepaliveServer(context.TODO(), &api.KeepaliveServerReq{
|
||||||
ServerType: api.FIGHT,
|
ServerType: api.ANTICHEAT,
|
||||||
AppId: APPID,
|
AppId: APPID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -50,22 +49,20 @@ func Run(ctx context.Context, configFile string) error {
|
|||||||
}()
|
}()
|
||||||
defer func() {
|
defer func() {
|
||||||
_, _ = client.Discovery.CancelServer(context.TODO(), &api.CancelServerReq{
|
_, _ = client.Discovery.CancelServer(context.TODO(), &api.CancelServerReq{
|
||||||
ServerType: api.FIGHT,
|
ServerType: api.ANTICHEAT,
|
||||||
AppId: APPID,
|
AppId: APPID,
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
|
|
||||||
logger.InitLogger("fight_" + APPID)
|
logger.InitLogger("anticheat_" + APPID)
|
||||||
logger.Warn("fight start, appid: %v", APPID)
|
logger.Warn("anticheat start, appid: %v", APPID)
|
||||||
defer func() {
|
defer func() {
|
||||||
logger.CloseLogger()
|
logger.CloseLogger()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
messageQueue := mq.NewMessageQueue(api.FIGHT, APPID, client)
|
messageQueue := mq.NewMessageQueue(api.ANTICHEAT, APPID, client)
|
||||||
defer messageQueue.Close()
|
defer messageQueue.Close()
|
||||||
|
|
||||||
_ = engine.NewFightEngine(messageQueue)
|
|
||||||
|
|
||||||
c := make(chan os.Signal, 1)
|
c := make(chan os.Signal, 1)
|
||||||
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
|
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
|
||||||
for {
|
for {
|
||||||
@@ -76,7 +73,7 @@ func Run(ctx context.Context, configFile string) error {
|
|||||||
logger.Warn("get a signal %s", s.String())
|
logger.Warn("get a signal %s", s.String())
|
||||||
switch s {
|
switch s {
|
||||||
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
|
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
|
||||||
logger.Warn("fight exit, appid: %v", APPID)
|
logger.Warn("anticheat exit, appid: %v", APPID)
|
||||||
return nil
|
return nil
|
||||||
case syscall.SIGHUP:
|
case syscall.SIGHUP:
|
||||||
default:
|
default:
|
||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"hk4e/fight/app"
|
"hk4e/anticheat/app"
|
||||||
"hk4e/pkg/statsviz_serve"
|
"hk4e/pkg/statsviz_serve"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -3,16 +3,16 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"hk4e/fight/app"
|
"hk4e/anticheat/app"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FightCmd() *cobra.Command {
|
func AnticheatCmd() *cobra.Command {
|
||||||
var cfg string
|
var cfg string
|
||||||
c := &cobra.Command{
|
c := &cobra.Command{
|
||||||
Use: "fight",
|
Use: "anticheat",
|
||||||
Short: "fight server",
|
Short: "anticheat server",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
return app.Run(context.Background(), cfg)
|
return app.Run(context.Background(), cfg)
|
||||||
},
|
},
|
||||||
@@ -23,7 +23,7 @@ func main() {
|
|||||||
NodeCmd(),
|
NodeCmd(),
|
||||||
DispatchCmd(),
|
DispatchCmd(),
|
||||||
GateCmd(),
|
GateCmd(),
|
||||||
FightCmd(),
|
AnticheatCmd(),
|
||||||
PathfindingCmd(),
|
PathfindingCmd(),
|
||||||
GSCmd(),
|
GSCmd(),
|
||||||
GMCmd(),
|
GMCmd(),
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ func (m *MessageQueue) sendHandler() {
|
|||||||
gateTcpMqInstMap := map[string]map[string]*GateTcpMqInst{
|
gateTcpMqInstMap := map[string]map[string]*GateTcpMqInst{
|
||||||
api.GATE: make(map[string]*GateTcpMqInst),
|
api.GATE: make(map[string]*GateTcpMqInst),
|
||||||
api.GS: make(map[string]*GateTcpMqInst),
|
api.GS: make(map[string]*GateTcpMqInst),
|
||||||
api.FIGHT: make(map[string]*GateTcpMqInst),
|
api.ANTICHEAT: make(map[string]*GateTcpMqInst),
|
||||||
api.PATHFINDING: make(map[string]*GateTcpMqInst),
|
api.PATHFINDING: make(map[string]*GateTcpMqInst),
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
@@ -293,8 +293,8 @@ func (m *MessageQueue) gateTcpMqHandshake(conn net.Conn) {
|
|||||||
inst.serverType = api.GATE
|
inst.serverType = api.GATE
|
||||||
case api.GS:
|
case api.GS:
|
||||||
inst.serverType = api.GS
|
inst.serverType = api.GS
|
||||||
case api.FIGHT:
|
case api.ANTICHEAT:
|
||||||
inst.serverType = api.FIGHT
|
inst.serverType = api.ANTICHEAT
|
||||||
case api.PATHFINDING:
|
case api.PATHFINDING:
|
||||||
inst.serverType = api.PATHFINDING
|
inst.serverType = api.PATHFINDING
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import pb "google.golang.org/protobuf/proto"
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
MsgTypeGame = iota // 来自客户端的游戏消息
|
MsgTypeGame = iota // 来自客户端的游戏消息
|
||||||
MsgTypeFight // 战斗服务器消息
|
|
||||||
MsgTypeConnCtrl // GATE客户端连接信息消息
|
MsgTypeConnCtrl // GATE客户端连接信息消息
|
||||||
MsgTypeServer // 服务器之间转发的消息
|
MsgTypeServer // 服务器之间转发的消息
|
||||||
)
|
)
|
||||||
@@ -16,7 +15,6 @@ type NetMsg struct {
|
|||||||
AppId string `msgpack:"-"`
|
AppId string `msgpack:"-"`
|
||||||
Topic string `msgpack:"-"`
|
Topic string `msgpack:"-"`
|
||||||
GameMsg *GameMsg
|
GameMsg *GameMsg
|
||||||
FightMsg *FightMsg
|
|
||||||
ConnCtrlMsg *ConnCtrlMsg
|
ConnCtrlMsg *ConnCtrlMsg
|
||||||
ServerMsg *ServerMsg
|
ServerMsg *ServerMsg
|
||||||
OriginServerType string
|
OriginServerType string
|
||||||
@@ -50,22 +48,6 @@ type ConnCtrlMsg struct {
|
|||||||
KickReason uint32
|
KickReason uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
AddFightRoutine = iota // 添加战斗实例
|
|
||||||
DelFightRoutine // 删除战斗实例
|
|
||||||
FightRoutineAddEntity // 战斗实例添加实体
|
|
||||||
FightRoutineDelEntity // 战斗实例删除实体
|
|
||||||
)
|
|
||||||
|
|
||||||
type FightMsg struct {
|
|
||||||
FightRoutineId uint32
|
|
||||||
EntityId uint32
|
|
||||||
FightPropMap map[uint32]float32
|
|
||||||
Uid uint32
|
|
||||||
AvatarGuid uint64
|
|
||||||
GateServerAppId string
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ServerAppidBindNotify = iota // 玩家连接绑定的各个服务器appid通知
|
ServerAppidBindNotify = iota // 玩家连接绑定的各个服务器appid通知
|
||||||
ServerUserOnlineStateChangeNotify // 广播玩家上线和离线状态以及所在GS的appid
|
ServerUserOnlineStateChangeNotify // 广播玩家上线和离线状态以及所在GS的appid
|
||||||
@@ -77,14 +59,14 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ServerMsg struct {
|
type ServerMsg struct {
|
||||||
FightServerAppId string
|
AnticheatServerAppId string
|
||||||
UserId uint32
|
UserId uint32
|
||||||
IsOnline bool
|
IsOnline bool
|
||||||
GameServerAppId string
|
GameServerAppId string
|
||||||
JoinHostUserId uint32
|
JoinHostUserId uint32
|
||||||
UserMpInfo *UserMpInfo
|
UserMpInfo *UserMpInfo
|
||||||
ChatMsgInfo *ChatMsgInfo
|
ChatMsgInfo *ChatMsgInfo
|
||||||
AddFriendInfo *AddFriendInfo
|
AddFriendInfo *AddFriendInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type OriginInfo struct {
|
type OriginInfo struct {
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ func (m *MessageQueue) SendToGs(appId string, netMsg *NetMsg) {
|
|||||||
m.netMsgInput <- netMsg
|
m.netMsgInput <- netMsg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MessageQueue) SendToFight(appId string, netMsg *NetMsg) {
|
func (m *MessageQueue) SendToAnticheat(appId string, netMsg *NetMsg) {
|
||||||
netMsg.Topic = m.getTopic(api.FIGHT, appId)
|
netMsg.Topic = m.getTopic(api.ANTICHEAT, appId)
|
||||||
netMsg.ServerType = api.FIGHT
|
netMsg.ServerType = api.ANTICHEAT
|
||||||
netMsg.AppId = appId
|
netMsg.AppId = appId
|
||||||
originServerType, originServerAppId := m.getOriginServer()
|
originServerType, originServerAppId := m.getOriginServer()
|
||||||
netMsg.OriginServerType = originServerType
|
netMsg.OriginServerType = originServerType
|
||||||
|
|||||||
@@ -67,10 +67,10 @@ services:
|
|||||||
limits:
|
limits:
|
||||||
cpus: '4.00'
|
cpus: '4.00'
|
||||||
memory: 1024M
|
memory: 1024M
|
||||||
fight_services:
|
anticheat_services:
|
||||||
restart: always
|
restart: always
|
||||||
image: flswld/fight:1.0.0
|
image: flswld/anticheat:1.0.0
|
||||||
container_name: fight
|
container_name: anticheat
|
||||||
ports:
|
ports:
|
||||||
- "5678:5678/tcp"
|
- "5678:5678/tcp"
|
||||||
environment:
|
environment:
|
||||||
@@ -80,7 +80,7 @@ services:
|
|||||||
- /etc/localtime:/etc/localtime
|
- /etc/localtime:/etc/localtime
|
||||||
- /etc/timezone:/etc/timezone
|
- /etc/timezone:/etc/timezone
|
||||||
- /usr/share/zoneinfo:/usr/share/zoneinfo
|
- /usr/share/zoneinfo:/usr/share/zoneinfo
|
||||||
- ./fight/bin/application.toml:/fight/application.toml
|
- ./anticheat/bin/application.toml:/anticheat/application.toml
|
||||||
depends_on:
|
depends_on:
|
||||||
- gate_services
|
- gate_services
|
||||||
deploy:
|
deploy:
|
||||||
@@ -103,7 +103,7 @@ services:
|
|||||||
- /usr/share/zoneinfo:/usr/share/zoneinfo
|
- /usr/share/zoneinfo:/usr/share/zoneinfo
|
||||||
- ./pathfinding/bin/application.toml:/pathfinding/application.toml
|
- ./pathfinding/bin/application.toml:/pathfinding/application.toml
|
||||||
depends_on:
|
depends_on:
|
||||||
- fight_services
|
- anticheat_services
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
|||||||
7
docker/anticheat/Dockerfile
Normal file
7
docker/anticheat/Dockerfile
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
FROM ubuntu:18.04
|
||||||
|
|
||||||
|
WORKDIR /anticheat
|
||||||
|
COPY ./bin/anticheat ./anticheat
|
||||||
|
RUN chmod +x ./anticheat
|
||||||
|
|
||||||
|
ENTRYPOINT ["./anticheat"]
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
FROM ubuntu:18.04
|
|
||||||
|
|
||||||
WORKDIR /fight
|
|
||||||
COPY ./bin/fight ./fight
|
|
||||||
RUN chmod +x ./fight
|
|
||||||
|
|
||||||
ENTRYPOINT ["./fight"]
|
|
||||||
@@ -1,284 +0,0 @@
|
|||||||
package engine
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"hk4e/common/constant"
|
|
||||||
"hk4e/common/mq"
|
|
||||||
"hk4e/pkg/logger"
|
|
||||||
"hk4e/protocol/cmd"
|
|
||||||
"hk4e/protocol/proto"
|
|
||||||
|
|
||||||
pb "google.golang.org/protobuf/proto"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FightEngine struct {
|
|
||||||
messageQueue *mq.MessageQueue
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewFightEngine(messageQueue *mq.MessageQueue) (r *FightEngine) {
|
|
||||||
r = new(FightEngine)
|
|
||||||
r.messageQueue = messageQueue
|
|
||||||
go r.fightHandle()
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FightEngine) fightHandle() {
|
|
||||||
fightRoutineMsgChanMap := make(map[uint32]chan *mq.NetMsg)
|
|
||||||
fightRoutineCloseChanMap := make(map[uint32]chan bool)
|
|
||||||
userIdFightRoutineIdMap := make(map[uint32]uint32)
|
|
||||||
for {
|
|
||||||
netMsg := <-f.messageQueue.GetNetMsg()
|
|
||||||
logger.Debug("recv net msg, netMsg: %v", netMsg)
|
|
||||||
switch netMsg.MsgType {
|
|
||||||
case mq.MsgTypeGame:
|
|
||||||
gameMsg := netMsg.GameMsg
|
|
||||||
if netMsg.EventId != mq.NormalMsg {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
logger.Debug("recv game msg, gameMsg: %v", gameMsg)
|
|
||||||
fightRoutineId, exist := userIdFightRoutineIdMap[gameMsg.UserId]
|
|
||||||
if !exist {
|
|
||||||
logger.Error("could not found fight routine id by uid: %v", gameMsg.UserId)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fightRoutineMsgChan, exist := fightRoutineMsgChanMap[fightRoutineId]
|
|
||||||
if !exist {
|
|
||||||
logger.Error("could not found fight routine msg chan by fight routine id: %v", fightRoutineId)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fightRoutineMsgChan <- netMsg
|
|
||||||
case mq.MsgTypeFight:
|
|
||||||
fightMsg := netMsg.FightMsg
|
|
||||||
logger.Debug("recv fight msg, fightMsg: %v", fightMsg)
|
|
||||||
switch netMsg.EventId {
|
|
||||||
case mq.AddFightRoutine:
|
|
||||||
fightRoutineMsgChan := make(chan *mq.NetMsg, 1000)
|
|
||||||
fightRoutineMsgChanMap[fightMsg.FightRoutineId] = fightRoutineMsgChan
|
|
||||||
fightRoutineCloseChan := make(chan bool, 1)
|
|
||||||
fightRoutineCloseChanMap[fightMsg.FightRoutineId] = fightRoutineCloseChan
|
|
||||||
go runFightRoutine(fightMsg.FightRoutineId, fightMsg.GateServerAppId, fightRoutineMsgChan, fightRoutineCloseChan, f.messageQueue)
|
|
||||||
case mq.DelFightRoutine:
|
|
||||||
fightRoutineCloseChan, exist := fightRoutineCloseChanMap[fightMsg.FightRoutineId]
|
|
||||||
if !exist {
|
|
||||||
logger.Error("could not found fight routine close chan by fight routine id: %v", fightMsg.FightRoutineId)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fightRoutineCloseChan <- true
|
|
||||||
case mq.FightRoutineAddEntity:
|
|
||||||
if fightMsg.Uid != 0 {
|
|
||||||
userIdFightRoutineIdMap[fightMsg.Uid] = fightMsg.FightRoutineId
|
|
||||||
}
|
|
||||||
fightRoutineMsgChan, exist := fightRoutineMsgChanMap[fightMsg.FightRoutineId]
|
|
||||||
if !exist {
|
|
||||||
logger.Error("could not found fight routine msg chan by fight routine id: %v", fightMsg.FightRoutineId)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fightRoutineMsgChan <- netMsg
|
|
||||||
case mq.FightRoutineDelEntity:
|
|
||||||
if fightMsg.Uid != 0 {
|
|
||||||
delete(userIdFightRoutineIdMap, fightMsg.Uid)
|
|
||||||
}
|
|
||||||
fightRoutineMsgChan, exist := fightRoutineMsgChanMap[fightMsg.FightRoutineId]
|
|
||||||
if !exist {
|
|
||||||
logger.Error("could not found fight routine msg chan by fight routine id: %v", fightMsg.FightRoutineId)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fightRoutineMsgChan <- netMsg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendMsg 发送消息给客户端
|
|
||||||
func SendMsg(messageQueue *mq.MessageQueue, cmdId uint16, userId uint32, gateAppId string, payloadMsg pb.Message) {
|
|
||||||
if userId < 100000000 || payloadMsg == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
gameMsg := new(mq.GameMsg)
|
|
||||||
gameMsg.UserId = userId
|
|
||||||
gameMsg.CmdId = cmdId
|
|
||||||
gameMsg.ClientSeq = 0
|
|
||||||
// 在这里直接序列化成二进制数据 防止发送的消息内包含各种游戏数据指针 而造成并发读写的问题
|
|
||||||
payloadMessageData, err := pb.Marshal(payloadMsg)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("parse payload msg to bin error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
gameMsg.PayloadMessageData = payloadMessageData
|
|
||||||
messageQueue.SendToGate(gateAppId, &mq.NetMsg{
|
|
||||||
MsgType: mq.MsgTypeGame,
|
|
||||||
EventId: mq.NormalMsg,
|
|
||||||
GameMsg: gameMsg,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type Entity struct {
|
|
||||||
entityId uint32
|
|
||||||
fightPropMap map[uint32]float32
|
|
||||||
uid uint32
|
|
||||||
avatarGuid uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// FightRoutine 战局例程
|
|
||||||
type FightRoutine struct {
|
|
||||||
messageQueue *mq.MessageQueue
|
|
||||||
entityMap map[uint32]*Entity
|
|
||||||
combatInvokeEntryList []*proto.CombatInvokeEntry
|
|
||||||
tickCount uint64
|
|
||||||
gateAppId string
|
|
||||||
}
|
|
||||||
|
|
||||||
func runFightRoutine(fightRoutineId uint32, gateAppId string, fightRoutineMsgChan chan *mq.NetMsg, fightRoutineCloseChan chan bool, messageQueue *mq.MessageQueue) {
|
|
||||||
f := new(FightRoutine)
|
|
||||||
f.messageQueue = messageQueue
|
|
||||||
f.entityMap = make(map[uint32]*Entity)
|
|
||||||
f.combatInvokeEntryList = make([]*proto.CombatInvokeEntry, 0)
|
|
||||||
f.tickCount = 0
|
|
||||||
f.gateAppId = gateAppId
|
|
||||||
logger.Debug("create fight routine, fightRoutineId: %v", fightRoutineId)
|
|
||||||
ticker := time.NewTicker(time.Millisecond * 10)
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case netMsg := <-fightRoutineMsgChan:
|
|
||||||
switch netMsg.MsgType {
|
|
||||||
case mq.MsgTypeGame:
|
|
||||||
gameMsg := netMsg.GameMsg
|
|
||||||
f.attackHandle(gameMsg)
|
|
||||||
case mq.MsgTypeFight:
|
|
||||||
fightMsg := netMsg.FightMsg
|
|
||||||
switch netMsg.EventId {
|
|
||||||
case mq.FightRoutineAddEntity:
|
|
||||||
f.entityMap[fightMsg.EntityId] = &Entity{
|
|
||||||
entityId: fightMsg.EntityId,
|
|
||||||
fightPropMap: fightMsg.FightPropMap,
|
|
||||||
uid: fightMsg.Uid,
|
|
||||||
avatarGuid: fightMsg.AvatarGuid,
|
|
||||||
}
|
|
||||||
case mq.FightRoutineDelEntity:
|
|
||||||
delete(f.entityMap, fightMsg.EntityId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case <-ticker.C:
|
|
||||||
f.onTick()
|
|
||||||
case <-fightRoutineCloseChan:
|
|
||||||
logger.Debug("destroy fight routine, fightRoutineId: %v", fightRoutineId)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FightRoutine) onTick() {
|
|
||||||
f.tickCount++
|
|
||||||
now := time.Now().UnixMilli()
|
|
||||||
if f.tickCount%5 == 0 {
|
|
||||||
f.onTick50MilliSecond(now)
|
|
||||||
}
|
|
||||||
if f.tickCount%100 == 0 {
|
|
||||||
f.onTickSecond(now)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FightRoutine) onTick50MilliSecond(now int64) {
|
|
||||||
if len(f.combatInvokeEntryList) > 0 {
|
|
||||||
combatInvocationsNotifyAll := new(proto.CombatInvocationsNotify)
|
|
||||||
combatInvocationsNotifyAll.InvokeList = f.combatInvokeEntryList
|
|
||||||
for _, uid := range f.getAllPlayer(f.entityMap) {
|
|
||||||
SendMsg(f.messageQueue, cmd.CombatInvocationsNotify, uid, f.gateAppId, combatInvocationsNotifyAll)
|
|
||||||
}
|
|
||||||
f.combatInvokeEntryList = make([]*proto.CombatInvokeEntry, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FightRoutine) onTickSecond(now int64) {
|
|
||||||
// 改面板
|
|
||||||
for _, entity := range f.entityMap {
|
|
||||||
if entity.uid == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
entity.fightPropMap[constant.FIGHT_PROP_CUR_ATTACK] = 1000000
|
|
||||||
entity.fightPropMap[constant.FIGHT_PROP_CRITICAL] = 1.0
|
|
||||||
avatarFightPropNotify := &proto.AvatarFightPropNotify{
|
|
||||||
AvatarGuid: entity.avatarGuid,
|
|
||||||
FightPropMap: entity.fightPropMap,
|
|
||||||
}
|
|
||||||
SendMsg(f.messageQueue, cmd.AvatarFightPropNotify, entity.uid, f.gateAppId, avatarFightPropNotify)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FightRoutine) attackHandle(gameMsg *mq.GameMsg) {
|
|
||||||
_ = gameMsg.UserId
|
|
||||||
cmdId := gameMsg.CmdId
|
|
||||||
_ = gameMsg.ClientSeq
|
|
||||||
payloadMsg := gameMsg.PayloadMessage
|
|
||||||
|
|
||||||
switch cmdId {
|
|
||||||
case cmd.CombatInvocationsNotify:
|
|
||||||
req := payloadMsg.(*proto.CombatInvocationsNotify)
|
|
||||||
for _, entry := range req.InvokeList {
|
|
||||||
if entry.ForwardType != proto.ForwardType_FORWARD_TO_ALL {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if entry.ArgumentType != proto.CombatTypeArgument_COMBAT_EVT_BEING_HIT {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
hitInfo := new(proto.EvtBeingHitInfo)
|
|
||||||
err := pb.Unmarshal(entry.CombatData, hitInfo)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("parse EvtBeingHitInfo error: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
attackResult := hitInfo.AttackResult
|
|
||||||
if attackResult == nil {
|
|
||||||
logger.Error("attackResult is nil")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// logger.Debug("run attack handler, attackResult: %v", attackResult)
|
|
||||||
target := f.entityMap[attackResult.DefenseId]
|
|
||||||
if target == nil {
|
|
||||||
logger.Error("could not found target, defense id: %v", attackResult.DefenseId)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
attackResult.Damage *= 100
|
|
||||||
damage := attackResult.Damage
|
|
||||||
attackerId := attackResult.AttackerId
|
|
||||||
_ = attackerId
|
|
||||||
currHp := float32(0)
|
|
||||||
if target.fightPropMap != nil {
|
|
||||||
currHp = target.fightPropMap[constant.FIGHT_PROP_CUR_HP]
|
|
||||||
currHp -= damage
|
|
||||||
if currHp < 0 {
|
|
||||||
currHp = 0
|
|
||||||
}
|
|
||||||
target.fightPropMap[constant.FIGHT_PROP_CUR_HP] = currHp
|
|
||||||
}
|
|
||||||
entityFightPropUpdateNotify := new(proto.EntityFightPropUpdateNotify)
|
|
||||||
entityFightPropUpdateNotify.EntityId = target.entityId
|
|
||||||
entityFightPropUpdateNotify.FightPropMap = make(map[uint32]float32)
|
|
||||||
entityFightPropUpdateNotify.FightPropMap[constant.FIGHT_PROP_CUR_HP] = currHp
|
|
||||||
for _, uid := range f.getAllPlayer(f.entityMap) {
|
|
||||||
SendMsg(f.messageQueue, cmd.EntityFightPropUpdateNotify, uid, f.gateAppId, entityFightPropUpdateNotify)
|
|
||||||
}
|
|
||||||
combatData, err := pb.Marshal(hitInfo)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("create combat invocations entity hit info error: %v", err)
|
|
||||||
}
|
|
||||||
entry.CombatData = combatData
|
|
||||||
f.combatInvokeEntryList = append(f.combatInvokeEntryList, entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FightRoutine) getAllPlayer(entityMap map[uint32]*Entity) []uint32 {
|
|
||||||
uidMap := make(map[uint32]bool)
|
|
||||||
for _, entity := range entityMap {
|
|
||||||
if entity.uid != 0 {
|
|
||||||
uidMap[entity.uid] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uidList := make([]uint32, 0)
|
|
||||||
for uid := range uidMap {
|
|
||||||
uidList = append(uidList, uid)
|
|
||||||
}
|
|
||||||
return uidList
|
|
||||||
}
|
|
||||||
@@ -162,7 +162,7 @@ func (k *KcpConnectManager) acceptHandle(listener *kcp.Listener) {
|
|||||||
xorKey: k.dispatchKey,
|
xorKey: k.dispatchKey,
|
||||||
changeXorKeyFin: false,
|
changeXorKeyFin: false,
|
||||||
gsServerAppId: "",
|
gsServerAppId: "",
|
||||||
fightServerAppId: "",
|
anticheatServerAppId: "",
|
||||||
pathfindingServerAppId: "",
|
pathfindingServerAppId: "",
|
||||||
changeGameServer: false,
|
changeGameServer: false,
|
||||||
joinHostUserId: 0,
|
joinHostUserId: 0,
|
||||||
@@ -278,7 +278,7 @@ type Session struct {
|
|||||||
xorKey []byte
|
xorKey []byte
|
||||||
changeXorKeyFin bool
|
changeXorKeyFin bool
|
||||||
gsServerAppId string
|
gsServerAppId string
|
||||||
fightServerAppId string
|
anticheatServerAppId string
|
||||||
pathfindingServerAppId string
|
pathfindingServerAppId string
|
||||||
changeGameServer bool
|
changeGameServer bool
|
||||||
joinHostUserId uint32
|
joinHostUserId uint32
|
||||||
|
|||||||
@@ -132,9 +132,9 @@ func (k *KcpConnectManager) recvMsgHandle(protoMsg *ProtoMsg, session *Session)
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 转发到战斗服务器
|
// 转发到反作弊服务器
|
||||||
if session.fightServerAppId != "" && protoMsg.CmdId == cmd.CombatInvocationsNotify {
|
if session.anticheatServerAppId != "" && protoMsg.CmdId == cmd.CombatInvocationsNotify {
|
||||||
k.messageQueue.SendToFight(session.fightServerAppId, &mq.NetMsg{
|
k.messageQueue.SendToAnticheat(session.anticheatServerAppId, &mq.NetMsg{
|
||||||
MsgType: mq.MsgTypeGame,
|
MsgType: mq.MsgTypeGame,
|
||||||
EventId: mq.NormalMsg,
|
EventId: mq.NormalMsg,
|
||||||
GameMsg: gameMsg,
|
GameMsg: gameMsg,
|
||||||
@@ -182,7 +182,7 @@ func (k *KcpConnectManager) sendMsgHandle() {
|
|||||||
session.changeGameServer = false
|
session.changeGameServer = false
|
||||||
session.joinHostUserId = 0
|
session.joinHostUserId = 0
|
||||||
} else {
|
} else {
|
||||||
serverMsg.FightServerAppId = session.fightServerAppId
|
serverMsg.AnticheatServerAppId = session.anticheatServerAppId
|
||||||
}
|
}
|
||||||
k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{
|
k.messageQueue.SendToGs(session.gsServerAppId, &mq.NetMsg{
|
||||||
MsgType: mq.MsgTypeServer,
|
MsgType: mq.MsgTypeServer,
|
||||||
@@ -255,7 +255,7 @@ func (k *KcpConnectManager) sendMsgHandle() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
session.gsServerAppId = serverMsg.GameServerAppId
|
session.gsServerAppId = serverMsg.GameServerAppId
|
||||||
session.fightServerAppId = ""
|
session.anticheatServerAppId = ""
|
||||||
session.changeGameServer = true
|
session.changeGameServer = true
|
||||||
session.joinHostUserId = serverMsg.JoinHostUserId
|
session.joinHostUserId = serverMsg.JoinHostUserId
|
||||||
// 网关代发登录请求到新的GS
|
// 网关代发登录请求到新的GS
|
||||||
@@ -434,13 +434,13 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
session.gsServerAppId = gsServerAppId.AppId
|
session.gsServerAppId = gsServerAppId.AppId
|
||||||
fightServerAppId, err := k.discovery.GetServerAppId(context.TODO(), &api.GetServerAppIdReq{
|
anticheatServerAppId, err := k.discovery.GetServerAppId(context.TODO(), &api.GetServerAppIdReq{
|
||||||
ServerType: api.FIGHT,
|
ServerType: api.ANTICHEAT,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("get fight server appid error: %v, uid: %v", err, uid)
|
logger.Error("get anticheat server appid error: %v, uid: %v", err, uid)
|
||||||
}
|
}
|
||||||
session.fightServerAppId = fightServerAppId.AppId
|
session.anticheatServerAppId = anticheatServerAppId.AppId
|
||||||
pathfindingServerAppId, err := k.discovery.GetServerAppId(context.TODO(), &api.GetServerAppIdReq{
|
pathfindingServerAppId, err := k.discovery.GetServerAppId(context.TODO(), &api.GetServerAppIdReq{
|
||||||
ServerType: api.PATHFINDING,
|
ServerType: api.PATHFINDING,
|
||||||
})
|
})
|
||||||
@@ -449,7 +449,7 @@ func (k *KcpConnectManager) getPlayerToken(req *proto.GetPlayerTokenReq, session
|
|||||||
}
|
}
|
||||||
session.pathfindingServerAppId = pathfindingServerAppId.AppId
|
session.pathfindingServerAppId = pathfindingServerAppId.AppId
|
||||||
logger.Debug("session gs appid: %v, uid: %v", session.gsServerAppId, uid)
|
logger.Debug("session gs appid: %v, uid: %v", session.gsServerAppId, uid)
|
||||||
logger.Debug("session fight appid: %v, uid: %v", session.fightServerAppId, uid)
|
logger.Debug("session anticheat appid: %v, uid: %v", session.anticheatServerAppId, uid)
|
||||||
logger.Debug("session pathfinding appid: %v, uid: %v", session.pathfindingServerAppId, uid)
|
logger.Debug("session pathfinding appid: %v, uid: %v", session.pathfindingServerAppId, uid)
|
||||||
// 返回响应
|
// 返回响应
|
||||||
rsp := new(proto.GetPlayerTokenRsp)
|
rsp := new(proto.GetPlayerTokenRsp)
|
||||||
|
|||||||
@@ -1,28 +1,19 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// AvatarCostumeData 角色时装配置表
|
// AvatarCostumeData 角色时装配置表
|
||||||
type AvatarCostumeData struct {
|
type AvatarCostumeData struct {
|
||||||
CostumeID int32 `csv:"CostumeID"` // 时装ID
|
CostumeID int32 `csv:"时装ID"`
|
||||||
ItemID int32 `csv:"ItemID,omitempty"` // 道具ID
|
ItemID int32 `csv:"道具ID,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadAvatarCostumeData() {
|
func (g *GameDataConfig) loadAvatarCostumeData() {
|
||||||
g.AvatarCostumeDataMap = make(map[int32]*AvatarCostumeData)
|
g.AvatarCostumeDataMap = make(map[int32]*AvatarCostumeData)
|
||||||
data := g.readCsvFileData("AvatarCostumeData.csv")
|
avatarCostumeDataList := make([]*AvatarCostumeData, 0)
|
||||||
var avatarCostumeDataList []*AvatarCostumeData
|
readTable[AvatarCostumeData](g.tablePrefix+"AvatarCostumeData.txt", &avatarCostumeDataList)
|
||||||
err := csvutil.Unmarshal(data, &avatarCostumeDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, avatarCostumeData := range avatarCostumeDataList {
|
for _, avatarCostumeData := range avatarCostumeDataList {
|
||||||
// 屏蔽默认时装
|
// 屏蔽默认时装
|
||||||
if avatarCostumeData.ItemID == 0 {
|
if avatarCostumeData.ItemID == 0 {
|
||||||
|
|||||||
@@ -3,32 +3,29 @@ package gdconf
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"hk4e/pkg/endec"
|
"hk4e/pkg/endec"
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/hjson/hjson-go/v4"
|
"github.com/hjson/hjson-go/v4"
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// AvatarData 角色配置表
|
// AvatarData 角色配置表
|
||||||
type AvatarData struct {
|
type AvatarData struct {
|
||||||
AvatarId int32 `csv:"AvatarId"` // ID
|
AvatarId int32 `csv:"ID"`
|
||||||
HpBase float32 `csv:"HpBase,omitempty"` // 基础生命值
|
HpBase float32 `csv:"基础生命值,omitempty"`
|
||||||
AttackBase float32 `csv:"AttackBase,omitempty"` // 基础攻击力
|
AttackBase float32 `csv:"基础攻击力,omitempty"`
|
||||||
DefenseBase float32 `csv:"DefenseBase,omitempty"` // 基础防御力
|
DefenseBase float32 `csv:"基础防御力,omitempty"`
|
||||||
Critical float32 `csv:"Critical,omitempty"` // 暴击率
|
Critical float32 `csv:"暴击率,omitempty"`
|
||||||
CriticalHurt float32 `csv:"CriticalHurt,omitempty"` // 暴击伤害
|
CriticalHurt float32 `csv:"暴击伤害,omitempty"`
|
||||||
QualityType int32 `csv:"QualityType,omitempty"` // 角色品质
|
QualityType int32 `csv:"角色品质,omitempty"`
|
||||||
ConfigJson string `csv:"ConfigJson,omitempty"` // 战斗config
|
ConfigJson string `csv:"战斗config,omitempty"`
|
||||||
InitialWeapon int32 `csv:"InitialWeapon,omitempty"` // 初始武器
|
InitialWeapon int32 `csv:"初始武器,omitempty"`
|
||||||
WeaponType int32 `csv:"WeaponType,omitempty"` // 武器种类
|
WeaponType int32 `csv:"武器种类,omitempty"`
|
||||||
SkillDepotId int32 `csv:"SkillDepotId,omitempty"` // 技能库ID
|
SkillDepotId int32 `csv:"技能库ID,omitempty"`
|
||||||
PromoteId int32 `csv:"PromoteId,omitempty"` // 角色突破ID
|
PromoteId int32 `csv:"角色突破ID,omitempty"`
|
||||||
PromoteRewardLevelStr string `csv:"PromoteRewardLevelStr,omitempty"` // 角色突破奖励获取等阶
|
PromoteRewardLevel IntArray `csv:"角色突破奖励获取等阶,omitempty"`
|
||||||
PromoteRewardStr string `csv:"PromoteRewardStr,omitempty"` // 角色突破奖励
|
PromoteReward IntArray `csv:"角色突破奖励,omitempty"`
|
||||||
|
|
||||||
AbilityHashCodeList []int32
|
AbilityHashCodeList []int32
|
||||||
PromoteRewardMap map[uint32]uint32
|
PromoteRewardMap map[uint32]uint32
|
||||||
@@ -45,13 +42,8 @@ type ConfigAvatarAbility struct {
|
|||||||
|
|
||||||
func (g *GameDataConfig) loadAvatarData() {
|
func (g *GameDataConfig) loadAvatarData() {
|
||||||
g.AvatarDataMap = make(map[int32]*AvatarData)
|
g.AvatarDataMap = make(map[int32]*AvatarData)
|
||||||
data := g.readCsvFileData("AvatarData.csv")
|
avatarDataList := make([]*AvatarData, 0)
|
||||||
var avatarDataList []*AvatarData
|
readTable[AvatarData](g.tablePrefix+"AvatarData.txt", &avatarDataList)
|
||||||
err := csvutil.Unmarshal(data, &avatarDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, avatarData := range avatarDataList {
|
for _, avatarData := range avatarDataList {
|
||||||
// 读取战斗config解析技能并转化为哈希码
|
// 读取战斗config解析技能并转化为哈希码
|
||||||
fileData, err := os.ReadFile(g.jsonPrefix + "avatar/" + avatarData.ConfigJson + ".json")
|
fileData, err := os.ReadFile(g.jsonPrefix + "avatar/" + avatarData.ConfigJson + ".json")
|
||||||
@@ -73,21 +65,10 @@ func (g *GameDataConfig) loadAvatarData() {
|
|||||||
avatarData.AbilityHashCodeList = append(avatarData.AbilityHashCodeList, abilityHashCode)
|
avatarData.AbilityHashCodeList = append(avatarData.AbilityHashCodeList, abilityHashCode)
|
||||||
}
|
}
|
||||||
// 突破奖励转换列表
|
// 突破奖励转换列表
|
||||||
if avatarData.PromoteRewardLevelStr != "" && avatarData.PromoteRewardStr != "" {
|
if len(avatarData.PromoteRewardLevel) != 0 && len(avatarData.PromoteReward) != 0 {
|
||||||
tempRewardLevelList := strings.Split(strings.ReplaceAll(avatarData.PromoteRewardLevelStr, " ", ""), "#")
|
avatarData.PromoteRewardMap = make(map[uint32]uint32, len(avatarData.PromoteReward))
|
||||||
tempRewardList := strings.Split(strings.ReplaceAll(avatarData.PromoteRewardStr, " ", ""), "#")
|
for index, rewardId := range avatarData.PromoteReward {
|
||||||
avatarData.PromoteRewardMap = make(map[uint32]uint32, len(tempRewardList))
|
promoteLevel := avatarData.PromoteRewardLevel[index]
|
||||||
for i, s := range tempRewardList {
|
|
||||||
promoteLevel, err := strconv.Atoi(tempRewardLevelList[i])
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("level to i err, %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
rewardId, err := strconv.Atoi(s)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("reward id to i err, %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
avatarData.PromoteRewardMap[uint32(promoteLevel)] = uint32(rewardId)
|
avatarData.PromoteRewardMap[uint32(promoteLevel)] = uint32(rewardId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,19 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// AvatarFlycloakData 角色风之翼配置表
|
// AvatarFlycloakData 角色风之翼配置表
|
||||||
type AvatarFlycloakData struct {
|
type AvatarFlycloakData struct {
|
||||||
FlycloakID int32 `csv:"FlycloakID"` // 风之翼ID
|
FlycloakID int32 `csv:"风之翼ID"`
|
||||||
ItemID int32 `csv:"ItemID,omitempty"` // 道具ID
|
ItemID int32 `csv:"道具ID,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadAvatarFlycloakData() {
|
func (g *GameDataConfig) loadAvatarFlycloakData() {
|
||||||
g.AvatarFlycloakDataMap = make(map[int32]*AvatarFlycloakData)
|
g.AvatarFlycloakDataMap = make(map[int32]*AvatarFlycloakData)
|
||||||
data := g.readCsvFileData("AvatarFlycloakData.csv")
|
avatarFlycloakDataList := make([]*AvatarFlycloakData, 0)
|
||||||
var avatarFlycloakDataList []*AvatarFlycloakData
|
readTable[AvatarFlycloakData](g.tablePrefix+"AvatarFlycloakData.txt", &avatarFlycloakDataList)
|
||||||
err := csvutil.Unmarshal(data, &avatarFlycloakDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, avatarFlycloakData := range avatarFlycloakDataList {
|
for _, avatarFlycloakData := range avatarFlycloakDataList {
|
||||||
// list -> map
|
// list -> map
|
||||||
g.AvatarFlycloakDataMap[avatarFlycloakData.FlycloakID] = avatarFlycloakData
|
g.AvatarFlycloakDataMap[avatarFlycloakData.FlycloakID] = avatarFlycloakData
|
||||||
|
|||||||
@@ -1,28 +1,19 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// AvatarLevelData 角色等级配置表
|
// AvatarLevelData 角色等级配置表
|
||||||
type AvatarLevelData struct {
|
type AvatarLevelData struct {
|
||||||
Level int32 `csv:"Level"` // 等级
|
Level int32 `csv:"等级"`
|
||||||
Exp int32 `csv:"Exp,omitempty"` // 升到下一级所需经验
|
Exp int32 `csv:"升到下一级所需经验,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadAvatarLevelData() {
|
func (g *GameDataConfig) loadAvatarLevelData() {
|
||||||
g.AvatarLevelDataMap = make(map[int32]*AvatarLevelData)
|
g.AvatarLevelDataMap = make(map[int32]*AvatarLevelData)
|
||||||
data := g.readCsvFileData("AvatarLevelData.csv")
|
avatarLevelDataList := make([]*AvatarLevelData, 0)
|
||||||
var avatarLevelDataList []*AvatarLevelData
|
readTable[AvatarLevelData](g.tablePrefix+"AvatarLevelData.txt", &avatarLevelDataList)
|
||||||
err := csvutil.Unmarshal(data, &avatarLevelDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, avatarLevelData := range avatarLevelDataList {
|
for _, avatarLevelData := range avatarLevelDataList {
|
||||||
// list -> map
|
// list -> map
|
||||||
g.AvatarLevelDataMap[avatarLevelData.Level] = avatarLevelData
|
g.AvatarLevelDataMap[avatarLevelData.Level] = avatarLevelData
|
||||||
|
|||||||
@@ -1,41 +1,32 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// AvatarPromoteData 角色突破配置表
|
// AvatarPromoteData 角色突破配置表
|
||||||
type AvatarPromoteData struct {
|
type AvatarPromoteData struct {
|
||||||
PromoteId int32 `csv:"PromoteId"` // 角色突破ID
|
PromoteId int32 `csv:"角色突破ID"`
|
||||||
PromoteLevel int32 `csv:"PromoteLevel,omitempty"` // 突破等级
|
PromoteLevel int32 `csv:"突破等级,omitempty"`
|
||||||
CostCoin int32 `csv:"CostCoin,omitempty"` // 消耗金币
|
CostCoin int32 `csv:"消耗金币,omitempty"`
|
||||||
CostItemId1 int32 `csv:"CostItemId1,omitempty"` // [消耗物品]1ID
|
CostItemId1 int32 `csv:"[消耗物品]1ID,omitempty"`
|
||||||
CostItemCount1 int32 `csv:"CostItemCount1,omitempty"` // [消耗物品]1数量
|
CostItemCount1 int32 `csv:"[消耗物品]1数量,omitempty"`
|
||||||
CostItemId2 int32 `csv:"CostItemId2,omitempty"` // [消耗物品]2ID
|
CostItemId2 int32 `csv:"[消耗物品]2ID,omitempty"`
|
||||||
CostItemCount2 int32 `csv:"CostItemCount2,omitempty"` // [消耗物品]2数量
|
CostItemCount2 int32 `csv:"[消耗物品]2数量,omitempty"`
|
||||||
CostItemId3 int32 `csv:"CostItemId3,omitempty"` // [消耗物品]3ID
|
CostItemId3 int32 `csv:"[消耗物品]3ID,omitempty"`
|
||||||
CostItemCount3 int32 `csv:"CostItemCount3,omitempty"` // [消耗物品]3数量
|
CostItemCount3 int32 `csv:"[消耗物品]3数量,omitempty"`
|
||||||
CostItemId4 int32 `csv:"CostItemId4,omitempty"` // [消耗物品]4ID
|
CostItemId4 int32 `csv:"[消耗物品]4ID,omitempty"`
|
||||||
CostItemCount4 int32 `csv:"CostItemCount4,omitempty"` // [消耗物品]4数量
|
CostItemCount4 int32 `csv:"[消耗物品]4数量,omitempty"`
|
||||||
LevelLimit int32 `csv:"LevelLimit,omitempty"` // 解锁等级上限
|
LevelLimit int32 `csv:"解锁等级上限,omitempty"`
|
||||||
MinPlayerLevel int32 `csv:"MinPlayerLevel,omitempty"` // 冒险等级要求
|
MinPlayerLevel int32 `csv:"冒险等级要求,omitempty"`
|
||||||
|
|
||||||
CostItemMap map[uint32]uint32 // 消耗物品列表
|
CostItemMap map[uint32]uint32 // 消耗物品列表
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadAvatarPromoteData() {
|
func (g *GameDataConfig) loadAvatarPromoteData() {
|
||||||
g.AvatarPromoteDataMap = make(map[int32]map[int32]*AvatarPromoteData)
|
g.AvatarPromoteDataMap = make(map[int32]map[int32]*AvatarPromoteData)
|
||||||
data := g.readCsvFileData("AvatarPromoteData.csv")
|
avatarPromoteDataList := make([]*AvatarPromoteData, 0)
|
||||||
var avatarPromoteDataList []*AvatarPromoteData
|
readTable[AvatarPromoteData](g.tablePrefix+"AvatarPromoteData.txt", &avatarPromoteDataList)
|
||||||
err := csvutil.Unmarshal(data, &avatarPromoteDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, avatarPromoteData := range avatarPromoteDataList {
|
for _, avatarPromoteData := range avatarPromoteDataList {
|
||||||
// list -> map
|
// list -> map
|
||||||
_, ok := g.AvatarPromoteDataMap[avatarPromoteData.PromoteId]
|
_, ok := g.AvatarPromoteDataMap[avatarPromoteData.PromoteId]
|
||||||
|
|||||||
@@ -1,32 +1,23 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// AvatarSkillData 角色技能配置表
|
// AvatarSkillData 角色技能配置表
|
||||||
type AvatarSkillData struct {
|
type AvatarSkillData struct {
|
||||||
AvatarSkillId int32 `csv:"AvatarSkillId"` // ID
|
AvatarSkillId int32 `csv:"ID"`
|
||||||
AbilityName string `csv:"AbilityName,omitempty"` // Ability名称
|
AbilityName string `csv:"Ability名称,omitempty"`
|
||||||
// TODO 这个字段实际上并不是拿来直接扣体力的 体力应该由ability来做 但是现在我捋不清所以摆烂了 改了一下表暂时先这么用着
|
// TODO 这个字段实际上并不是拿来直接扣体力的 体力应该由ability来做 但是现在我捋不清所以摆烂了 改了一下表暂时先这么用着
|
||||||
CostStamina int32 `csv:"CostStamina,omitempty"` // 消耗体力
|
CostStamina int32 `csv:"消耗体力,omitempty"`
|
||||||
CostElemType int32 `csv:"CostElemType,omitempty"` // 消耗能量类型
|
CostElemType int32 `csv:"消耗能量类型,omitempty"`
|
||||||
CostElemVal int32 `csv:"CostElemVal,omitempty"` // 消耗能量值
|
CostElemVal int32 `csv:"消耗能量值,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadAvatarSkillData() {
|
func (g *GameDataConfig) loadAvatarSkillData() {
|
||||||
g.AvatarSkillDataMap = make(map[int32]*AvatarSkillData)
|
g.AvatarSkillDataMap = make(map[int32]*AvatarSkillData)
|
||||||
data := g.readCsvFileData("AvatarSkillData.csv")
|
avatarSkillDataList := make([]*AvatarSkillData, 0)
|
||||||
var avatarSkillDataList []*AvatarSkillData
|
readTable[AvatarSkillData](g.tablePrefix+"AvatarSkillData.txt", &avatarSkillDataList)
|
||||||
err := csvutil.Unmarshal(data, &avatarSkillDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, avatarSkillData := range avatarSkillDataList {
|
for _, avatarSkillData := range avatarSkillDataList {
|
||||||
// list -> map
|
// list -> map
|
||||||
g.AvatarSkillDataMap[avatarSkillData.AvatarSkillId] = avatarSkillData
|
g.AvatarSkillDataMap[avatarSkillData.AvatarSkillId] = avatarSkillData
|
||||||
|
|||||||
@@ -8,28 +8,27 @@ import (
|
|||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/hjson/hjson-go/v4"
|
"github.com/hjson/hjson-go/v4"
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// AvatarSkillDepotData 角色技能库配置表
|
// AvatarSkillDepotData 角色技能库配置表
|
||||||
type AvatarSkillDepotData struct {
|
type AvatarSkillDepotData struct {
|
||||||
AvatarSkillDepotId int32 `csv:"AvatarSkillDepotId"` // ID
|
AvatarSkillDepotId int32 `csv:"ID"`
|
||||||
EnergySkill int32 `csv:"EnergySkill,omitempty"` // 充能技能
|
EnergySkill int32 `csv:"充能技能,omitempty"`
|
||||||
Skill1 int32 `csv:"Skill1,omitempty"` // 技能1
|
Skill1 int32 `csv:"技能1,omitempty"`
|
||||||
Skill2 int32 `csv:"Skill2,omitempty"` // 技能2
|
Skill2 int32 `csv:"技能2,omitempty"`
|
||||||
Skill3 int32 `csv:"Skill3,omitempty"` // 技能3
|
Skill3 int32 `csv:"技能3,omitempty"`
|
||||||
Skill4 int32 `csv:"Skill4,omitempty"` // 技能4
|
Skill4 int32 `csv:"技能4,omitempty"`
|
||||||
ProudSkill1GroupId int32 `csv:"ProudSkill1GroupId,omitempty"` // 固有得意技组1ID
|
ProudSkill1GroupId int32 `csv:"固有得意技组1ID,omitempty"`
|
||||||
ProudSkill1NeedAvatarPromoteLevel int32 `csv:"ProudSkill1NeedAvatarPromoteLevel,omitempty"` // 固有得意技组1激活所需角色突破等级
|
ProudSkill1NeedAvatarPromoteLevel int32 `csv:"固有得意技组1激活所需角色突破等级,omitempty"`
|
||||||
ProudSkill2GroupId int32 `csv:"ProudSkill2GroupId,omitempty"` // 固有得意技组2ID
|
ProudSkill2GroupId int32 `csv:"固有得意技组2ID,omitempty"`
|
||||||
ProudSkill2NeedAvatarPromoteLevel int32 `csv:"ProudSkill2NeedAvatarPromoteLevel,omitempty"` // 固有得意技组2激活所需角色突破等级
|
ProudSkill2NeedAvatarPromoteLevel int32 `csv:"固有得意技组2激活所需角色突破等级,omitempty"`
|
||||||
ProudSkill3GroupId int32 `csv:"ProudSkill3GroupId,omitempty"` // 固有得意技组3ID
|
ProudSkill3GroupId int32 `csv:"固有得意技组3ID,omitempty"`
|
||||||
ProudSkill3NeedAvatarPromoteLevel int32 `csv:"ProudSkill3NeedAvatarPromoteLevel,omitempty"` // 固有得意技组3激活所需角色突破等级
|
ProudSkill3NeedAvatarPromoteLevel int32 `csv:"固有得意技组3激活所需角色突破等级,omitempty"`
|
||||||
ProudSkill4GroupId int32 `csv:"ProudSkill4GroupId,omitempty"` // 固有得意技组4ID
|
ProudSkill4GroupId int32 `csv:"固有得意技组4ID,omitempty"`
|
||||||
ProudSkill4NeedAvatarPromoteLevel int32 `csv:"ProudSkill4NeedAvatarPromoteLevel,omitempty"` // 固有得意技组4激活所需角色突破等级
|
ProudSkill4NeedAvatarPromoteLevel int32 `csv:"固有得意技组4激活所需角色突破等级,omitempty"`
|
||||||
ProudSkill5GroupId int32 `csv:"ProudSkill5GroupId,omitempty"` // 固有得意技组5ID
|
ProudSkill5GroupId int32 `csv:"固有得意技组5ID,omitempty"`
|
||||||
ProudSkill5NeedAvatarPromoteLevel int32 `csv:"ProudSkill5NeedAvatarPromoteLevel,omitempty"` // 固有得意技组5激活所需角色突破等级
|
ProudSkill5NeedAvatarPromoteLevel int32 `csv:"固有得意技组5激活所需角色突破等级,omitempty"`
|
||||||
SkillDepotAbilityGroup string `csv:"SkillDepotAbilityGroup,omitempty"` // AbilityGroup
|
SkillDepotAbilityGroup string `csv:"AbilityGroup,omitempty"`
|
||||||
|
|
||||||
Skills []int32
|
Skills []int32
|
||||||
InherentProudSkillOpens []*InherentProudSkillOpens
|
InherentProudSkillOpens []*InherentProudSkillOpens
|
||||||
@@ -43,14 +42,8 @@ type InherentProudSkillOpens struct {
|
|||||||
|
|
||||||
func (g *GameDataConfig) loadAvatarSkillDepotData() {
|
func (g *GameDataConfig) loadAvatarSkillDepotData() {
|
||||||
g.AvatarSkillDepotDataMap = make(map[int32]*AvatarSkillDepotData)
|
g.AvatarSkillDepotDataMap = make(map[int32]*AvatarSkillDepotData)
|
||||||
data := g.readCsvFileData("AvatarSkillDepotData.csv")
|
avatarSkillDepotDataList := make([]*AvatarSkillDepotData, 0)
|
||||||
var avatarSkillDepotDataList []*AvatarSkillDepotData
|
readTable[AvatarSkillDepotData](g.tablePrefix+"AvatarSkillDepotData.txt", &avatarSkillDepotDataList)
|
||||||
err := csvutil.Unmarshal(data, &avatarSkillDepotDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
|
|
||||||
playerElementsFilePath := g.jsonPrefix + "ability_group/AbilityGroup_Other_PlayerElementAbility.json"
|
playerElementsFilePath := g.jsonPrefix + "ability_group/AbilityGroup_Other_PlayerElementAbility.json"
|
||||||
playerElementsFile, err := os.ReadFile(playerElementsFilePath)
|
playerElementsFile, err := os.ReadFile(playerElementsFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ package gdconf
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// 当初写卡池算法的时候临时建立的表 以后再做迁移吧
|
// 当初写卡池算法的时候临时建立的表 以后再做迁移吧
|
||||||
@@ -25,13 +23,8 @@ func (g *GameDataConfig) loadDropGroupData() {
|
|||||||
g.DropGroupDataMap = make(map[int32]*DropGroupData)
|
g.DropGroupDataMap = make(map[int32]*DropGroupData)
|
||||||
fileNameList := []string{"DropGachaAvatarUp.csv", "DropGachaWeaponUp.csv", "DropGachaNormal.csv"}
|
fileNameList := []string{"DropGachaAvatarUp.csv", "DropGachaWeaponUp.csv", "DropGachaNormal.csv"}
|
||||||
for _, fileName := range fileNameList {
|
for _, fileName := range fileNameList {
|
||||||
data := g.readCsvFileData("../ext/" + fileName)
|
dropList := make([]*Drop, 0)
|
||||||
var dropList []*Drop
|
readExtCsv[Drop](g.extPrefix+fileName, &dropList)
|
||||||
err := csvutil.Unmarshal(data, &dropList)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("parse file error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, drop := range dropList {
|
for _, drop := range dropList {
|
||||||
dropGroupData, exist := g.DropGroupDataMap[drop.DropId]
|
dropGroupData, exist := g.DropGroupDataMap[drop.DropId]
|
||||||
if !exist {
|
if !exist {
|
||||||
|
|||||||
@@ -1,31 +1,22 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// FetterData 角色资料解锁配置表
|
// FetterData 角色资料解锁配置表
|
||||||
type FetterData struct {
|
type FetterData struct {
|
||||||
FetterId int32 `csv:"FetterId"` // ID
|
FetterId int32 `csv:"ID"`
|
||||||
AvatarId int32 `csv:"AvatarId"` // 角色ID
|
AvatarId int32 `csv:"角色ID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadFetterData() {
|
func (g *GameDataConfig) loadFetterData() {
|
||||||
g.FetterDataMap = make(map[int32]*FetterData)
|
g.FetterDataMap = make(map[int32]*FetterData)
|
||||||
g.FetterDataAvatarIdMap = make(map[int32][]int32)
|
g.FetterDataAvatarIdMap = make(map[int32][]int32)
|
||||||
fileNameList := []string{"FettersData.csv", "FetterDataStory.csv", "FetterDataIformation.csv", "PhotographExpressionName.csv", "PhotographPoseName.csv"}
|
fileNameList := []string{"FettersData.txt", "FetterDataStory.txt", "FetterDataIformation.txt", "PhotographExpressionName.txt", "PhotographPoseName.txt"}
|
||||||
for _, fileName := range fileNameList {
|
for _, fileName := range fileNameList {
|
||||||
data := g.readCsvFileData(fileName)
|
fetterDataList := make([]*FetterData, 0)
|
||||||
var fetterDataList []*FetterData
|
readTable[FetterData](g.tablePrefix+fileName, &fetterDataList)
|
||||||
err := csvutil.Unmarshal(data, &fetterDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, fetterData := range fetterDataList {
|
for _, fetterData := range fetterDataList {
|
||||||
// list -> map
|
// list -> map
|
||||||
g.FetterDataMap[fetterData.FetterId] = fetterData
|
g.FetterDataMap[fetterData.FetterId] = fetterData
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/csv"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -12,6 +16,7 @@ import (
|
|||||||
"hk4e/common/constant"
|
"hk4e/common/constant"
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
|
"github.com/jszwec/csvutil"
|
||||||
lua "github.com/yuin/gopher-lua"
|
lua "github.com/yuin/gopher-lua"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -22,9 +27,10 @@ var CONF_RELOAD *GameDataConfig = nil
|
|||||||
|
|
||||||
type GameDataConfig struct {
|
type GameDataConfig struct {
|
||||||
// 配置表路径前缀
|
// 配置表路径前缀
|
||||||
csvPrefix string
|
tablePrefix string
|
||||||
jsonPrefix string
|
jsonPrefix string
|
||||||
luaPrefix string
|
luaPrefix string
|
||||||
|
extPrefix string
|
||||||
// 配置表数据
|
// 配置表数据
|
||||||
AvatarDataMap map[int32]*AvatarData // 角色
|
AvatarDataMap map[int32]*AvatarData // 角色
|
||||||
AvatarSkillDataMap map[int32]*AvatarSkillData // 角色技能
|
AvatarSkillDataMap map[int32]*AvatarSkillData // 角色技能
|
||||||
@@ -89,13 +95,13 @@ func (g *GameDataConfig) loadAll() {
|
|||||||
panic(info)
|
panic(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
g.csvPrefix = pathPrefix + "/csv"
|
g.tablePrefix = pathPrefix + "/txt"
|
||||||
dirInfo, err = os.Stat(g.csvPrefix)
|
dirInfo, err = os.Stat(g.tablePrefix)
|
||||||
if err != nil || !dirInfo.IsDir() {
|
if err != nil || !dirInfo.IsDir() {
|
||||||
info := fmt.Sprintf("open game data config csv dir error: %v", err)
|
info := fmt.Sprintf("open game data config txt dir error: %v", err)
|
||||||
panic(info)
|
panic(info)
|
||||||
}
|
}
|
||||||
g.csvPrefix += "/"
|
g.tablePrefix += "/"
|
||||||
|
|
||||||
g.jsonPrefix = pathPrefix + "/json"
|
g.jsonPrefix = pathPrefix + "/json"
|
||||||
dirInfo, err = os.Stat(g.jsonPrefix)
|
dirInfo, err = os.Stat(g.jsonPrefix)
|
||||||
@@ -113,6 +119,14 @@ func (g *GameDataConfig) loadAll() {
|
|||||||
}
|
}
|
||||||
g.luaPrefix += "/"
|
g.luaPrefix += "/"
|
||||||
|
|
||||||
|
g.extPrefix = pathPrefix + "/ext"
|
||||||
|
dirInfo, err = os.Stat(g.extPrefix)
|
||||||
|
if err != nil || !dirInfo.IsDir() {
|
||||||
|
info := fmt.Sprintf("open game data config ext dir error: %v", err)
|
||||||
|
panic(info)
|
||||||
|
}
|
||||||
|
g.extPrefix += "/"
|
||||||
|
|
||||||
g.load()
|
g.load()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,8 +161,38 @@ func (g *GameDataConfig) load() {
|
|||||||
g.loadTriggerData() // 场景LUA触发器
|
g.loadTriggerData() // 场景LUA触发器
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) readCsvFileData(fileName string) []byte {
|
// CSV相关
|
||||||
fileData, err := os.ReadFile(g.csvPrefix + fileName)
|
|
||||||
|
func splitStringArray(str string) []string {
|
||||||
|
if str == "" {
|
||||||
|
return make([]string, 0)
|
||||||
|
} else if strings.Contains(str, ";") {
|
||||||
|
return strings.Split(str, ";")
|
||||||
|
} else if strings.Contains(str, ",") {
|
||||||
|
return strings.Split(str, ",")
|
||||||
|
} else {
|
||||||
|
return []string{str}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type IntArray []int32
|
||||||
|
|
||||||
|
func (a *IntArray) UnmarshalCSV(data []byte) error {
|
||||||
|
str := string(data)
|
||||||
|
str = strings.ReplaceAll(str, " ", "")
|
||||||
|
intStrList := splitStringArray(str)
|
||||||
|
for _, intStr := range intStrList {
|
||||||
|
v, err := strconv.ParseInt(intStr, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
*a = append(*a, int32(v))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readExtCsv[T any](tablePath string, table *[]*T) {
|
||||||
|
fileData, err := os.ReadFile(tablePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
info := fmt.Sprintf("open file error: %v", err)
|
info := fmt.Sprintf("open file error: %v", err)
|
||||||
panic(info)
|
panic(info)
|
||||||
@@ -160,9 +204,42 @@ func (g *GameDataConfig) readCsvFileData(fileName string) []byte {
|
|||||||
standardCsvData := make([]byte, 0)
|
standardCsvData := make([]byte, 0)
|
||||||
standardCsvData = append(standardCsvData, fileData[:index1]...)
|
standardCsvData = append(standardCsvData, fileData[:index1]...)
|
||||||
standardCsvData = append(standardCsvData, fileData[index3+(index2+1)+(index1+1):]...)
|
standardCsvData = append(standardCsvData, fileData[index3+(index2+1)+(index1+1):]...)
|
||||||
return standardCsvData
|
err = csvutil.Unmarshal(standardCsvData, table)
|
||||||
|
if err != nil {
|
||||||
|
info := fmt.Sprintf("parse file error: %v", err)
|
||||||
|
panic(info)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readTable[T any](tablePath string, table *[]*T) {
|
||||||
|
fileData, err := os.ReadFile(tablePath)
|
||||||
|
if err != nil {
|
||||||
|
info := fmt.Sprintf("open file error: %v", err)
|
||||||
|
panic(info)
|
||||||
|
}
|
||||||
|
reader := csv.NewReader(bytes.NewBuffer(fileData))
|
||||||
|
reader.Comma = '\t'
|
||||||
|
dec, err := csvutil.NewDecoder(reader)
|
||||||
|
if err != nil {
|
||||||
|
info := fmt.Sprintf("create decoder error: %v", err)
|
||||||
|
panic(info)
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
t := new(T)
|
||||||
|
err := dec.Decode(t)
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
info := fmt.Sprintf("decode file error: %v", err)
|
||||||
|
panic(info)
|
||||||
|
}
|
||||||
|
*table = append(*table, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LUA相关
|
||||||
|
|
||||||
type ScriptLibFunc struct {
|
type ScriptLibFunc struct {
|
||||||
fnName string
|
fnName string
|
||||||
fn lua.LGFunction
|
fn lua.LGFunction
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"image/jpeg"
|
"image/jpeg"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -17,79 +15,6 @@ import (
|
|||||||
"github.com/hjson/hjson-go/v4"
|
"github.com/hjson/hjson-go/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TableField struct {
|
|
||||||
FieldName string `json:"field_name"`
|
|
||||||
FieldType string `json:"field_type"`
|
|
||||||
OriginName string `json:"origin_name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type TableStructMapping struct {
|
|
||||||
TableName string `json:"table_name"`
|
|
||||||
FieldList []*TableField `json:"field_list"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成最终服务器读取的配置表
|
|
||||||
func TestGenGdCsv(t *testing.T) {
|
|
||||||
tableStructMappingList := make([]*TableStructMapping, 0)
|
|
||||||
configFileData, err := os.ReadFile("./table_struct_mapping.json")
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("open config file error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(configFileData, &tableStructMappingList)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("parse config file error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, tableStructMapping := range tableStructMappingList {
|
|
||||||
txtFileData, err := os.ReadFile("./game_data_config/txt/" + tableStructMapping.TableName + ".txt")
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("read txt file error: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// 转换txt配置表格式为csv
|
|
||||||
originCsv := string(txtFileData)
|
|
||||||
originCsv = strings.ReplaceAll(originCsv, "\r\n", "\n")
|
|
||||||
originCsv = strings.ReplaceAll(originCsv, "\r", "\n")
|
|
||||||
originCsv = strings.ReplaceAll(originCsv, ",", "#")
|
|
||||||
originCsv = strings.ReplaceAll(originCsv, ";", "#")
|
|
||||||
originCsv = strings.ReplaceAll(originCsv, "\t", ",")
|
|
||||||
originCsvLineList := strings.Split(originCsv, "\n")
|
|
||||||
if len(originCsvLineList) == 0 {
|
|
||||||
log.Printf("origin csv file is empty")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
originCsvHeadList := strings.Split(originCsvLineList[0], ",")
|
|
||||||
if len(originCsvHeadList) == 0 {
|
|
||||||
log.Printf("origin csv file head is empty")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fieldNameHead := ""
|
|
||||||
fieldTypeHead := ""
|
|
||||||
for index, originCsvHead := range originCsvHeadList {
|
|
||||||
for _, tableField := range tableStructMapping.FieldList {
|
|
||||||
if originCsvHead == tableField.OriginName {
|
|
||||||
// 字段名匹配成功
|
|
||||||
fieldNameHead += tableField.FieldName
|
|
||||||
fieldTypeHead += tableField.FieldType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if index < len(originCsvHeadList)-1 {
|
|
||||||
fieldNameHead += ","
|
|
||||||
fieldTypeHead += ","
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fieldNameHead += "\n"
|
|
||||||
fieldTypeHead += "\n"
|
|
||||||
gdCsvFile := fieldNameHead + fieldTypeHead + originCsv
|
|
||||||
err = os.WriteFile("./game_data_config/csv/"+tableStructMapping.TableName+".csv", []byte(gdCsvFile), 0644)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("write gd csv file error: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 测试初始化加载配置表
|
// 测试初始化加载配置表
|
||||||
func TestInitGameDataConfig(t *testing.T) {
|
func TestInitGameDataConfig(t *testing.T) {
|
||||||
config.InitConfig("./bin/application.toml")
|
config.InitConfig("./bin/application.toml")
|
||||||
@@ -99,7 +24,7 @@ func TestInitGameDataConfig(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
logger.Info("start load conf")
|
logger.Info("start load conf")
|
||||||
InitGameDataConfig()
|
InitGameDataConfig()
|
||||||
logger.Info("load conf finish, conf: %v", CONF)
|
logger.Info("load conf finish")
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +1,21 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GatherData 采集物配置表
|
// GatherData 采集物配置表
|
||||||
type GatherData struct {
|
type GatherData struct {
|
||||||
PointType int32 `csv:"PointType"` // 挂节点类型
|
PointType int32 `csv:"挂节点类型"`
|
||||||
GatherId int32 `csv:"GatherId"` // ID
|
GatherId int32 `csv:"ID"`
|
||||||
GadgetId int32 `csv:"GadgetId"` // 采集物ID
|
GadgetId int32 `csv:"采集物ID"`
|
||||||
ItemId int32 `csv:"ItemId"` // 获得物品ID
|
ItemId int32 `csv:"获得物品ID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadGatherData() {
|
func (g *GameDataConfig) loadGatherData() {
|
||||||
g.GatherDataMap = make(map[int32]*GatherData)
|
g.GatherDataMap = make(map[int32]*GatherData)
|
||||||
data := g.readCsvFileData("GatherData.csv")
|
gatherDataList := make([]*GatherData, 0)
|
||||||
var gatherDataList []*GatherData
|
readTable[GatherData](g.tablePrefix+"GatherData.txt", &gatherDataList)
|
||||||
err := csvutil.Unmarshal(data, &gatherDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
g.GatherDataPointTypeMap = make(map[int32]*GatherData)
|
g.GatherDataPointTypeMap = make(map[int32]*GatherData)
|
||||||
for _, gatherData := range gatherDataList {
|
for _, gatherData := range gatherDataList {
|
||||||
// list -> map
|
// list -> map
|
||||||
|
|||||||
@@ -1,40 +1,28 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GCGCharData 角色卡牌配置表
|
// GCGCharData 角色卡牌配置表
|
||||||
type GCGCharData struct {
|
type GCGCharData struct {
|
||||||
CharId int32 `csv:"CharId"` // ID
|
CharId int32 `csv:"ID"`
|
||||||
TagId1 int32 `csv:"TagId1,omitempty"` // 卡牌标签列表1
|
TagId1 int32 `csv:"[卡牌标签列表]1,omitempty"`
|
||||||
TagId2 int32 `csv:"TagId2,omitempty"` // 卡牌标签列表2
|
TagId2 int32 `csv:"[卡牌标签列表]2,omitempty"`
|
||||||
TagId3 int32 `csv:"TagId3,omitempty"` // 卡牌标签列表3
|
TagId3 int32 `csv:"[卡牌标签列表]3,omitempty"`
|
||||||
TagId4 int32 `csv:"TagId4,omitempty"` // 卡牌标签列表4
|
TagId4 int32 `csv:"[卡牌标签列表]4,omitempty"`
|
||||||
TagId5 int32 `csv:"TagId5,omitempty"` // 卡牌标签列表5
|
TagId5 int32 `csv:"[卡牌标签列表]5,omitempty"`
|
||||||
SkillListStr string `csv:"SkillListStr,omitempty"` // 卡牌技能列表文本
|
SkillList IntArray `csv:"卡牌技能列表,omitempty"`
|
||||||
HPBase int32 `csv:"HPBase,omitempty"` // 角色生命值
|
HPBase int32 `csv:"角色生命值,omitempty"`
|
||||||
MaxElemVal int32 `csv:"MaxElemVal,omitempty"` // 角色充能上限
|
MaxElemVal int32 `csv:"角色充能上限,omitempty"`
|
||||||
|
|
||||||
TagList []uint32 // 卡牌标签列表
|
TagList []uint32 // 卡牌标签列表
|
||||||
SkillList []uint32 // 卡牌技能列表
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadGCGCharData() {
|
func (g *GameDataConfig) loadGCGCharData() {
|
||||||
g.GCGCharDataMap = make(map[int32]*GCGCharData)
|
g.GCGCharDataMap = make(map[int32]*GCGCharData)
|
||||||
data := g.readCsvFileData("GCGCharData.csv")
|
gcgCharDataList := make([]*GCGCharData, 0)
|
||||||
var gcgCharDataList []*GCGCharData
|
readTable[GCGCharData](g.tablePrefix+"GCGCharData.txt", &gcgCharDataList)
|
||||||
err := csvutil.Unmarshal(data, &gcgCharDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, gcgCharData := range gcgCharDataList {
|
for _, gcgCharData := range gcgCharDataList {
|
||||||
// 将TagId整合进TagList
|
// 将TagId整合进TagList
|
||||||
gcgCharData.TagList = make([]uint32, 0, 5)
|
gcgCharData.TagList = make([]uint32, 0, 5)
|
||||||
@@ -47,17 +35,6 @@ func (g *GameDataConfig) loadGCGCharData() {
|
|||||||
}
|
}
|
||||||
gcgCharData.TagList = append(gcgCharData.TagList, uint32(tagId))
|
gcgCharData.TagList = append(gcgCharData.TagList, uint32(tagId))
|
||||||
}
|
}
|
||||||
// 技能列表读取转换
|
|
||||||
tempSkillList := strings.Split(strings.ReplaceAll(gcgCharData.SkillListStr, " ", ""), "#")
|
|
||||||
gcgCharData.SkillList = make([]uint32, 0, len(tempSkillList))
|
|
||||||
for _, s := range tempSkillList {
|
|
||||||
skillId, err := strconv.Atoi(s)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("skill id to i err, %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
gcgCharData.SkillList = append(gcgCharData.SkillList, uint32(skillId))
|
|
||||||
}
|
|
||||||
// list -> map
|
// list -> map
|
||||||
g.GCGCharDataMap[gcgCharData.CharId] = gcgCharData
|
g.GCGCharDataMap[gcgCharData.CharId] = gcgCharData
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,18 +7,16 @@ import (
|
|||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/hjson/hjson-go/v4"
|
"github.com/hjson/hjson-go/v4"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GCGSkillData 卡牌技能配置表
|
// GCGSkillData 卡牌技能配置表
|
||||||
type GCGSkillData struct {
|
type GCGSkillData struct {
|
||||||
SkillId int32 `csv:"SkillId"` // ID
|
SkillId int32 `csv:"ID"`
|
||||||
ConfigJson string `csv:"ConfigJson,omitempty"` // 效果config
|
ConfigJson string `csv:"效果JSON文件,omitempty"`
|
||||||
CostType1 int32 `csv:"CostType1,omitempty"` // 消耗的元素骰子类型1
|
CostType1 int32 `csv:"[技能费用]1类型,omitempty"`
|
||||||
CostValue1 int32 `csv:"CostValue1,omitempty"` // 消耗的元素骰子数量1
|
CostValue1 int32 `csv:"[技能费用]1值,omitempty"`
|
||||||
CostType2 int32 `csv:"CostType2,omitempty"` // 消耗的元素骰子类型2
|
CostType2 int32 `csv:"[技能费用]2类型,omitempty"`
|
||||||
CostValue2 int32 `csv:"CostValue2,omitempty"` // 消耗的元素骰子数量2
|
CostValue2 int32 `csv:"[技能费用]2值,omitempty"`
|
||||||
|
|
||||||
CostMap map[uint32]uint32 // 技能骰子消耗列表
|
CostMap map[uint32]uint32 // 技能骰子消耗列表
|
||||||
Damage uint32 // 技能伤害
|
Damage uint32 // 技能伤害
|
||||||
@@ -36,13 +34,8 @@ type ConfigSkillEffectValue struct {
|
|||||||
|
|
||||||
func (g *GameDataConfig) loadGCGSkillData() {
|
func (g *GameDataConfig) loadGCGSkillData() {
|
||||||
g.GCGSkillDataMap = make(map[int32]*GCGSkillData)
|
g.GCGSkillDataMap = make(map[int32]*GCGSkillData)
|
||||||
data := g.readCsvFileData("GCGSkillData.csv")
|
gcgSkillDataList := make([]*GCGSkillData, 0)
|
||||||
var gcgSkillDataList []*GCGSkillData
|
readTable[GCGSkillData](g.tablePrefix+"GCGSkillData.txt", &gcgSkillDataList)
|
||||||
err := csvutil.Unmarshal(data, &gcgSkillDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, gcgSkillData := range gcgSkillDataList {
|
for _, gcgSkillData := range gcgSkillDataList {
|
||||||
// 技能消耗整合进CostMap
|
// 技能消耗整合进CostMap
|
||||||
gcgSkillData.CostMap = map[uint32]uint32{
|
gcgSkillData.CostMap = map[uint32]uint32{
|
||||||
|
|||||||
@@ -1,57 +1,44 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"hk4e/common/constant"
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ItemData 道具分类分表整合配置表
|
// ItemData 道具分类分表整合配置表
|
||||||
type ItemData struct {
|
type ItemData struct {
|
||||||
// 公共表头字段
|
// 公共表头字段
|
||||||
ItemId int32 `csv:"ItemId"` // ID
|
ItemId int32 `csv:"ID"`
|
||||||
Type int32 `csv:"Type,omitempty"` // 类型
|
Type int32 `csv:"类型,omitempty"`
|
||||||
Weight int32 `csv:"Weight,omitempty"` // 重量
|
Weight int32 `csv:"重量,omitempty"`
|
||||||
RankLevel int32 `csv:"RankLevel,omitempty"` // 排序权重
|
RankLevel int32 `csv:"排序权重,omitempty"`
|
||||||
GadgetId int32 `csv:"GadgetId,omitempty"` // 物件ID
|
GadgetId int32 `csv:"物件ID,omitempty"`
|
||||||
Name string `csv:"Name,omitempty"` // 数值用类型
|
Name string `csv:"数值用类型,omitempty"`
|
||||||
// 材料
|
// 材料
|
||||||
MaterialType int32 `csv:"MaterialType,omitempty"` // 材料类型
|
MaterialType int32 `csv:"材料类型,omitempty"`
|
||||||
Use1Param1 string `csv:"Use1Param1,omitempty"` // [使用]1参数1
|
Use1Param1 string `csv:"[使用]1参数1,omitempty"`
|
||||||
// 武器
|
// 武器
|
||||||
EquipType int32 `csv:"EquipType,omitempty"` // 武器种类
|
EquipType int32 `csv:"武器种类,omitempty"`
|
||||||
EquipLevel int32 `csv:"EquipLevel,omitempty"` // 武器阶数
|
EquipLevel int32 `csv:"武器阶数,omitempty"`
|
||||||
SkillAffix1 int32 `csv:"SkillAffix1,omitempty"` // 初始技能词缀1
|
SkillAffix1 int32 `csv:"初始技能词缀1,omitempty"`
|
||||||
SkillAffix2 int32 `csv:"SkillAffix2,omitempty"` // 初始技能词缀2
|
SkillAffix2 int32 `csv:"初始技能词缀2,omitempty"`
|
||||||
PromoteId int32 `csv:"PromoteId,omitempty"` // 武器突破ID
|
PromoteId int32 `csv:"武器突破ID,omitempty"`
|
||||||
EquipBaseExp int32 `csv:"EquipBaseExp,omitempty"` // 武器初始经验
|
EquipBaseExp int32 `csv:"武器初始经验,omitempty"`
|
||||||
AwakenMaterial int32 `csv:"AwakenMaterial,omitempty"` // 武器精炼道具
|
AwakenMaterial int32 `csv:"精炼道具,omitempty"`
|
||||||
AwakenCoinCostStr string `csv:"AwakenCoinCostStr,omitempty"` // 精炼摩拉消耗
|
AwakenCoinCost IntArray `csv:"精炼摩拉消耗,omitempty"`
|
||||||
SkillAffix []int32
|
SkillAffix []int32
|
||||||
AwakenCoinCostList []uint32
|
|
||||||
// 圣遗物
|
// 圣遗物
|
||||||
ReliquaryType int32 `csv:"ReliquaryType,omitempty"` // 圣遗物类别
|
ReliquaryType int32 `csv:"圣遗物类别,omitempty"`
|
||||||
MainPropDepotId int32 `csv:"MainPropDepotId,omitempty"` // 主属性库ID
|
MainPropDepotId int32 `csv:"主属性库ID,omitempty"`
|
||||||
AppendPropDepotId int32 `csv:"AppendPropDepotId,omitempty"` // 追加属性库ID
|
AppendPropDepotId int32 `csv:"追加属性库ID,omitempty"`
|
||||||
AppendPropCount int32 `csv:"AppendPropCount,omitempty"` // 追加属性初始条数
|
AppendPropCount int32 `csv:"追加属性初始条数,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadItemData() {
|
func (g *GameDataConfig) loadItemData() {
|
||||||
g.ItemDataMap = make(map[int32]*ItemData)
|
g.ItemDataMap = make(map[int32]*ItemData)
|
||||||
fileNameList := []string{"MaterialData.csv", "WeaponData.csv", "ReliquaryData.csv", "FurnitureExcelData.csv"}
|
fileNameList := []string{"MaterialData.txt", "WeaponData.txt", "ReliquaryData.txt", "FurnitureExcelData.txt"}
|
||||||
for _, fileName := range fileNameList {
|
for _, fileName := range fileNameList {
|
||||||
data := g.readCsvFileData(fileName)
|
itemDataList := make([]*ItemData, 0)
|
||||||
var itemDataList []*ItemData
|
readTable[ItemData](g.tablePrefix+fileName, &itemDataList)
|
||||||
err := csvutil.Unmarshal(data, &itemDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, itemData := range itemDataList {
|
for _, itemData := range itemDataList {
|
||||||
// list -> map
|
// list -> map
|
||||||
itemData.SkillAffix = make([]int32, 0)
|
itemData.SkillAffix = make([]int32, 0)
|
||||||
@@ -61,19 +48,6 @@ func (g *GameDataConfig) loadItemData() {
|
|||||||
if itemData.SkillAffix2 != 0 {
|
if itemData.SkillAffix2 != 0 {
|
||||||
itemData.SkillAffix = append(itemData.SkillAffix, itemData.SkillAffix2)
|
itemData.SkillAffix = append(itemData.SkillAffix, itemData.SkillAffix2)
|
||||||
}
|
}
|
||||||
// 武器精炼摩拉消耗列表读取转换
|
|
||||||
if itemData.Type == constant.ITEM_TYPE_WEAPON && itemData.AwakenCoinCostStr != "" {
|
|
||||||
tempCostList := strings.Split(strings.ReplaceAll(itemData.AwakenCoinCostStr, " ", ""), "#")
|
|
||||||
itemData.AwakenCoinCostList = make([]uint32, 0, len(tempCostList))
|
|
||||||
for _, s := range tempCostList {
|
|
||||||
costCount, err := strconv.Atoi(s)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("cost count to i err, %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
itemData.AwakenCoinCostList = append(itemData.AwakenCoinCostList, uint32(costCount))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g.ItemDataMap[itemData.ItemId] = itemData
|
g.ItemDataMap[itemData.ItemId] = itemData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,19 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// PlayerLevelData 玩家等级配置表
|
// PlayerLevelData 玩家等级配置表
|
||||||
type PlayerLevelData struct {
|
type PlayerLevelData struct {
|
||||||
Level int32 `csv:"Level"` // 等级
|
Level int32 `csv:"等级"`
|
||||||
Exp int32 `csv:"Exp,omitempty"` // 升到下一级所需经验
|
Exp int32 `csv:"升到下一级所需经验,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadPlayerLevelData() {
|
func (g *GameDataConfig) loadPlayerLevelData() {
|
||||||
g.PlayerLevelDataMap = make(map[int32]*PlayerLevelData)
|
g.PlayerLevelDataMap = make(map[int32]*PlayerLevelData)
|
||||||
data := g.readCsvFileData("PlayerLevelData.csv")
|
playerLevelDataList := make([]*PlayerLevelData, 0)
|
||||||
var playerLevelDataList []*PlayerLevelData
|
readTable[PlayerLevelData](g.tablePrefix+"PlayerLevelData.txt", &playerLevelDataList)
|
||||||
err := csvutil.Unmarshal(data, &playerLevelDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, playerLevelData := range playerLevelDataList {
|
for _, playerLevelData := range playerLevelDataList {
|
||||||
// list -> map
|
// list -> map
|
||||||
g.PlayerLevelDataMap[playerLevelData.Level] = playerLevelData
|
g.PlayerLevelDataMap[playerLevelData.Level] = playerLevelData
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type QuestCond struct {
|
type QuestCond struct {
|
||||||
@@ -17,57 +13,57 @@ type QuestCond struct {
|
|||||||
|
|
||||||
// QuestData 任务配置表
|
// QuestData 任务配置表
|
||||||
type QuestData struct {
|
type QuestData struct {
|
||||||
QuestId int32 `csv:"QuestId"` // ID
|
QuestId int32 `csv:"子任务ID"`
|
||||||
ParentQuestId int32 `csv:"ParentQuestId,omitempty"` // 父任务ID
|
ParentQuestId int32 `csv:"父任务ID,omitempty"`
|
||||||
Sequence int32 `csv:"Sequence,omitempty"` // 序列
|
Sequence int32 `csv:"序列,omitempty"`
|
||||||
// 领取条件
|
// 领取条件
|
||||||
AcceptCondCompose int32 `csv:"AcceptCondCompose,omitempty"` // [领取条件]组合
|
AcceptCondCompose int32 `csv:"[领取条件]组合,omitempty"`
|
||||||
AcceptCondType1 int32 `csv:"AcceptCondType1,omitempty"` // [领取条件]1类型
|
AcceptCondType1 int32 `csv:"[领取条件]1类型,omitempty"`
|
||||||
AcceptCondType1Param1 int32 `csv:"AcceptCondType1Param1,omitempty"` // [领取条件]1参数1
|
AcceptCondType1Param1 int32 `csv:"[领取条件]1参数1,omitempty"`
|
||||||
AcceptCondType1Param2 int32 `csv:"AcceptCondType1Param2,omitempty"` // [领取条件]1参数2
|
AcceptCondType1Param2 int32 `csv:"[领取条件]1参数2,omitempty"`
|
||||||
AcceptCondType1Param3 int32 `csv:"AcceptCondType1Param3,omitempty"` // [领取条件]1参数3
|
AcceptCondType1Param3 int32 `csv:"[领取条件]1参数3,omitempty"`
|
||||||
AcceptCondType2 int32 `csv:"AcceptCondType2,omitempty"` // [领取条件]2类型
|
AcceptCondType2 int32 `csv:"[领取条件]2类型,omitempty"`
|
||||||
AcceptCondType2Param1 int32 `csv:"AcceptCondType2Param1,omitempty"` // [领取条件]2参数1
|
AcceptCondType2Param1 int32 `csv:"[领取条件]2参数1,omitempty"`
|
||||||
AcceptCondType2Param2 int32 `csv:"AcceptCondType2Param2,omitempty"` // [领取条件]2参数2
|
AcceptCondType2Param2 int32 `csv:"[领取条件]2参数2,omitempty"`
|
||||||
AcceptCondType2Param3 int32 `csv:"AcceptCondType2Param3,omitempty"` // [领取条件]2参数3
|
AcceptCondType2Param3 int32 `csv:"[领取条件]2参数3,omitempty"`
|
||||||
AcceptCondType3 int32 `csv:"AcceptCondType3,omitempty"` // [领取条件]3类型
|
AcceptCondType3 int32 `csv:"[领取条件]3类型,omitempty"`
|
||||||
AcceptCondType3Param1 int32 `csv:"AcceptCondType3Param1,omitempty"` // [领取条件]3参数1
|
AcceptCondType3Param1 int32 `csv:"[领取条件]3参数1,omitempty"`
|
||||||
AcceptCondType3Param2 int32 `csv:"AcceptCondType3Param2,omitempty"` // [领取条件]3参数2
|
AcceptCondType3Param2 int32 `csv:"[领取条件]3参数2,omitempty"`
|
||||||
AcceptCondType3Param3 int32 `csv:"AcceptCondType3Param3,omitempty"` // [领取条件]3参数3
|
AcceptCondType3Param3 int32 `csv:"[领取条件]3参数3,omitempty"`
|
||||||
// 完成条件
|
// 完成条件
|
||||||
FinishCondCompose int32 `csv:"FinishCondCompose,omitempty"` // [完成条件]组合
|
FinishCondCompose int32 `csv:"[完成条件]组合,omitempty"`
|
||||||
FinishCondType1 int32 `csv:"FinishCondType1,omitempty"` // [完成条件]1类型
|
FinishCondType1 int32 `csv:"[完成条件]1类型,omitempty"`
|
||||||
FinishCondType1Param1 int32 `csv:"FinishCondType1Param1,omitempty"` // [完成条件]1参数1
|
FinishCondType1Param1 int32 `csv:"[完成条件]1参数1,omitempty"`
|
||||||
FinishCondType1Param2 int32 `csv:"FinishCondType1Param2,omitempty"` // [完成条件]1参数2
|
FinishCondType1Param2 int32 `csv:"[完成条件]1参数2,omitempty"`
|
||||||
FinishCondType1ComplexParam string `csv:"FinishCondType1ComplexParam,omitempty"` // [完成条件]1复杂参数
|
FinishCondType1ComplexParam string `csv:"[完成条件]1复杂参数,omitempty"`
|
||||||
FinishCondType1Count int32 `csv:"FinishCondType1Count,omitempty"` // [完成条件]1次数
|
FinishCondType1Count int32 `csv:"[完成条件]1次数,omitempty"`
|
||||||
FinishCondType2 int32 `csv:"FinishCondType2,omitempty"` // [完成条件]2类型
|
FinishCondType2 int32 `csv:"[完成条件]2类型,omitempty"`
|
||||||
FinishCondType2Param1 int32 `csv:"FinishCondType2Param1,omitempty"` // [完成条件]2参数1
|
FinishCondType2Param1 int32 `csv:"[完成条件]2参数1,omitempty"`
|
||||||
FinishCondType2Param2 int32 `csv:"FinishCondType2Param2,omitempty"` // [完成条件]2参数2
|
FinishCondType2Param2 int32 `csv:"[完成条件]2参数2,omitempty"`
|
||||||
FinishCondType2ComplexParam string `csv:"FinishCondType2ComplexParam,omitempty"` // [完成条件]2复杂参数
|
FinishCondType2ComplexParam string `csv:"[完成条件]2复杂参数,omitempty"`
|
||||||
FinishCondType2Count int32 `csv:"FinishCondType2Count,omitempty"` // [完成条件]2次数
|
FinishCondType2Count int32 `csv:"[完成条件]2次数,omitempty"`
|
||||||
FinishCondType3 int32 `csv:"FinishCondType3,omitempty"` // [完成条件]3类型
|
FinishCondType3 int32 `csv:"[完成条件]3类型,omitempty"`
|
||||||
FinishCondType3Param1 int32 `csv:"FinishCondType3Param1,omitempty"` // [完成条件]3参数1
|
FinishCondType3Param1 int32 `csv:"[完成条件]3参数1,omitempty"`
|
||||||
FinishCondType3Param2 int32 `csv:"FinishCondType3Param2,omitempty"` // [完成条件]3参数2
|
FinishCondType3Param2 int32 `csv:"[完成条件]3参数2,omitempty"`
|
||||||
FinishCondType3ComplexParam string `csv:"FinishCondType3ComplexParam,omitempty"` // [完成条件]3复杂参数
|
FinishCondType3ComplexParam string `csv:"[完成条件]3复杂参数,omitempty"`
|
||||||
FinishCondType3Count int32 `csv:"FinishCondType3Count,omitempty"` // [完成条件]3次数
|
FinishCondType3Count int32 `csv:"[完成条件]3次数,omitempty"`
|
||||||
// 失败条件
|
// 失败条件
|
||||||
FailCondCompose int32 `csv:"FailCondCompose,omitempty"` // [失败条件]组合
|
FailCondCompose int32 `csv:"[失败条件]组合,omitempty"`
|
||||||
FailCondType1 int32 `csv:"FailCondType1,omitempty"` // [失败条件]1类型
|
FailCondType1 int32 `csv:"[失败条件]1类型,omitempty"`
|
||||||
FailCondType1Param1 int32 `csv:"FailCondType1Param1,omitempty"` // [失败条件]1参数1
|
FailCondType1Param1 int32 `csv:"[失败条件]1参数1,omitempty"`
|
||||||
FailCondType1Param2 int32 `csv:"FailCondType1Param2,omitempty"` // [失败条件]1参数2
|
FailCondType1Param2 int32 `csv:"[失败条件]1参数2,omitempty"`
|
||||||
FailCondType1ComplexParam string `csv:"FailCondType1ComplexParam,omitempty"` // [失败条件]1复杂参数
|
FailCondType1ComplexParam string `csv:"[失败条件]1复杂参数,omitempty"`
|
||||||
FailCondType1Count int32 `csv:"FailCondType1Count,omitempty"` // [失败条件]1次数
|
FailCondType1Count int32 `csv:"[失败条件]1次数,omitempty"`
|
||||||
FailCondType2 int32 `csv:"FailCondType2,omitempty"` // [失败条件]2类型
|
FailCondType2 int32 `csv:"[失败条件]2类型,omitempty"`
|
||||||
FailCondType2Param1 int32 `csv:"FailCondType2Param1,omitempty"` // [失败条件]2参数1
|
FailCondType2Param1 int32 `csv:"[失败条件]2参数1,omitempty"`
|
||||||
FailCondType2Param2 int32 `csv:"FailCondType2Param2,omitempty"` // [失败条件]2参数2
|
FailCondType2Param2 int32 `csv:"[失败条件]2参数2,omitempty"`
|
||||||
FailCondType2ComplexParam string `csv:"FailCondType2ComplexParam,omitempty"` // [失败条件]2复杂参数
|
FailCondType2ComplexParam string `csv:"[失败条件]2复杂参数,omitempty"`
|
||||||
FailCondType2Count int32 `csv:"FailCondType2Count,omitempty"` // [失败条件]2次数
|
FailCondType2Count int32 `csv:"[失败条件]2次数,omitempty"`
|
||||||
FailCondType3 int32 `csv:"FailCondType3,omitempty"` // [失败条件]3类型
|
FailCondType3 int32 `csv:"[失败条件]3类型,omitempty"`
|
||||||
FailCondType3Param1 int32 `csv:"FailCondType3Param1,omitempty"` // [失败条件]3参数1
|
FailCondType3Param1 int32 `csv:"[失败条件]3参数1,omitempty"`
|
||||||
FailCondType3Param2 int32 `csv:"FailCondType3Param2,omitempty"` // [失败条件]3参数2
|
FailCondType3Param2 int32 `csv:"[失败条件]3参数2,omitempty"`
|
||||||
FailCondType3ComplexParam string `csv:"FailCondType3ComplexParam,omitempty"` // [失败条件]3复杂参数
|
FailCondType3ComplexParam string `csv:"[失败条件]3复杂参数,omitempty"`
|
||||||
FailCondType3Count int32 `csv:"FailCondType3Count,omitempty"` // [失败条件]3次数
|
FailCondType3Count int32 `csv:"[失败条件]3次数,omitempty"`
|
||||||
|
|
||||||
AcceptCondList []*QuestCond // 领取条件
|
AcceptCondList []*QuestCond // 领取条件
|
||||||
FinishCondList []*QuestCond // 完成条件
|
FinishCondList []*QuestCond // 完成条件
|
||||||
@@ -76,15 +72,10 @@ type QuestData struct {
|
|||||||
|
|
||||||
func (g *GameDataConfig) loadQuestData() {
|
func (g *GameDataConfig) loadQuestData() {
|
||||||
g.QuestDataMap = make(map[int32]*QuestData)
|
g.QuestDataMap = make(map[int32]*QuestData)
|
||||||
fileNameList := []string{"QuestData.csv", "QuestData_Exported.csv"}
|
fileNameList := []string{"QuestData.txt", "QuestData_Exported.txt"}
|
||||||
for _, fileName := range fileNameList {
|
for _, fileName := range fileNameList {
|
||||||
data := g.readCsvFileData(fileName)
|
questDataList := make([]*QuestData, 0)
|
||||||
var questDataList []*QuestData
|
readTable[QuestData](g.tablePrefix+fileName, &questDataList)
|
||||||
err := csvutil.Unmarshal(data, &questDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, questData := range questDataList {
|
for _, questData := range questDataList {
|
||||||
// list -> map
|
// list -> map
|
||||||
// 领取条件
|
// 领取条件
|
||||||
|
|||||||
@@ -1,30 +1,21 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReliquaryAffixData 圣遗物追加属性配置表
|
// ReliquaryAffixData 圣遗物追加属性配置表
|
||||||
type ReliquaryAffixData struct {
|
type ReliquaryAffixData struct {
|
||||||
AppendPropId int32 `csv:"AppendPropId"` // 追加属性ID
|
AppendPropId int32 `csv:"追加属性ID"`
|
||||||
AppendPropDepotId int32 `csv:"AppendPropDepotId,omitempty"` // 追加属性库ID
|
AppendPropDepotId int32 `csv:"追加属性库ID,omitempty"`
|
||||||
PropType int32 `csv:"PropType,omitempty"` // 属性类别
|
PropType int32 `csv:"属性类别,omitempty"`
|
||||||
RandomWeight int32 `csv:"RandomWeight,omitempty"` // 随机权重
|
RandomWeight int32 `csv:"随机权重,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadReliquaryAffixData() {
|
func (g *GameDataConfig) loadReliquaryAffixData() {
|
||||||
g.ReliquaryAffixDataMap = make(map[int32]map[int32]*ReliquaryAffixData)
|
g.ReliquaryAffixDataMap = make(map[int32]map[int32]*ReliquaryAffixData)
|
||||||
data := g.readCsvFileData("ReliquaryAffixData.csv")
|
reliquaryAffixDataList := make([]*ReliquaryAffixData, 0)
|
||||||
var reliquaryAffixDataList []*ReliquaryAffixData
|
readTable[ReliquaryAffixData](g.tablePrefix+"ReliquaryAffixData.txt", &reliquaryAffixDataList)
|
||||||
err := csvutil.Unmarshal(data, &reliquaryAffixDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, reliquaryAffixData := range reliquaryAffixDataList {
|
for _, reliquaryAffixData := range reliquaryAffixDataList {
|
||||||
// 通过主属性库ID找到
|
// 通过主属性库ID找到
|
||||||
_, ok := g.ReliquaryAffixDataMap[reliquaryAffixData.AppendPropDepotId]
|
_, ok := g.ReliquaryAffixDataMap[reliquaryAffixData.AppendPropDepotId]
|
||||||
|
|||||||
@@ -1,30 +1,21 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReliquaryMainData 圣遗物主属性配置表
|
// ReliquaryMainData 圣遗物主属性配置表
|
||||||
type ReliquaryMainData struct {
|
type ReliquaryMainData struct {
|
||||||
MainPropId int32 `csv:"MainPropId"` // 主属性ID
|
MainPropId int32 `csv:"主属性ID"`
|
||||||
MainPropDepotId int32 `csv:"MainPropDepotId,omitempty"` // 主属性库ID
|
MainPropDepotId int32 `csv:"主属性库ID,omitempty"`
|
||||||
PropType int32 `csv:"PropType,omitempty"` // 属性类别
|
PropType int32 `csv:"属性类别,omitempty"`
|
||||||
RandomWeight int32 `csv:"RandomWeight,omitempty"` // 随机权重
|
RandomWeight int32 `csv:"随机权重,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadReliquaryMainData() {
|
func (g *GameDataConfig) loadReliquaryMainData() {
|
||||||
g.ReliquaryMainDataMap = make(map[int32]map[int32]*ReliquaryMainData)
|
g.ReliquaryMainDataMap = make(map[int32]map[int32]*ReliquaryMainData)
|
||||||
data := g.readCsvFileData("ReliquaryMainData.csv")
|
reliquaryMainDataList := make([]*ReliquaryMainData, 0)
|
||||||
var reliquaryMainDataList []*ReliquaryMainData
|
readTable[ReliquaryMainData](g.tablePrefix+"ReliquaryMainData.txt", &reliquaryMainDataList)
|
||||||
err := csvutil.Unmarshal(data, &reliquaryMainDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, reliquaryMainData := range reliquaryMainDataList {
|
for _, reliquaryMainData := range reliquaryMainDataList {
|
||||||
// 通过主属性库ID找到
|
// 通过主属性库ID找到
|
||||||
_, ok := g.ReliquaryMainDataMap[reliquaryMainData.MainPropDepotId]
|
_, ok := g.ReliquaryMainDataMap[reliquaryMainData.MainPropDepotId]
|
||||||
|
|||||||
@@ -1,47 +1,38 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RewardData 奖励配置表
|
// RewardData 奖励配置表
|
||||||
type RewardData struct {
|
type RewardData struct {
|
||||||
RewardID int32 `csv:"RewardID"` // 奖励ID
|
RewardID int32 `csv:"RewardID"`
|
||||||
RewardItem1ID int32 `csv:"RewardItem1ID,omitempty"` // Reward道具1ID
|
RewardItem1ID int32 `csv:"Reward道具1ID,omitempty"`
|
||||||
RewardItem1Count int32 `csv:"RewardItem1Count,omitempty"` // Reward道具1数量
|
RewardItem1Count int32 `csv:"Reward道具1数量,omitempty"`
|
||||||
RewardItem2ID int32 `csv:"RewardItem2ID,omitempty"` // Reward道具2ID
|
RewardItem2ID int32 `csv:"Reward道具2ID,omitempty"`
|
||||||
RewardItem2Count int32 `csv:"RewardItem2Count,omitempty"` // Reward道具2数量
|
RewardItem2Count int32 `csv:"Reward道具2数量,omitempty"`
|
||||||
RewardItem3ID int32 `csv:"RewardItem3ID,omitempty"` // Reward道具3ID
|
RewardItem3ID int32 `csv:"Reward道具3ID,omitempty"`
|
||||||
RewardItem3Count int32 `csv:"RewardItem3Count,omitempty"` // Reward道具3数量
|
RewardItem3Count int32 `csv:"Reward道具3数量,omitempty"`
|
||||||
RewardItem4ID int32 `csv:"RewardItem4ID,omitempty"` // Reward道具4ID
|
RewardItem4ID int32 `csv:"Reward道具4ID,omitempty"`
|
||||||
RewardItem4Count int32 `csv:"RewardItem4Count,omitempty"` // Reward道具4数量
|
RewardItem4Count int32 `csv:"Reward道具4数量,omitempty"`
|
||||||
RewardItem5ID int32 `csv:"RewardItem5ID,omitempty"` // Reward道具5ID
|
RewardItem5ID int32 `csv:"Reward道具5ID,omitempty"`
|
||||||
RewardItem5Count int32 `csv:"RewardItem5Count,omitempty"` // Reward道具5数量
|
RewardItem5Count int32 `csv:"Reward道具5数量,omitempty"`
|
||||||
RewardItem6ID int32 `csv:"RewardItem6ID,omitempty"` // Reward道具6ID
|
RewardItem6ID int32 `csv:"Reward道具6ID,omitempty"`
|
||||||
RewardItem6Count int32 `csv:"RewardItem6Count,omitempty"` // Reward道具6数量
|
RewardItem6Count int32 `csv:"Reward道具6数量,omitempty"`
|
||||||
RewardItem7ID int32 `csv:"RewardItem7ID,omitempty"` // Reward道具7ID
|
RewardItem7ID int32 `csv:"Reward道具7ID,omitempty"`
|
||||||
RewardItem7Count int32 `csv:"RewardItem7Count,omitempty"` // Reward道具7数量
|
RewardItem7Count int32 `csv:"Reward道具7数量,omitempty"`
|
||||||
RewardItem8ID int32 `csv:"RewardItem8ID,omitempty"` // Reward道具8ID
|
RewardItem8ID int32 `csv:"Reward道具8ID,omitempty"`
|
||||||
RewardItem8Count int32 `csv:"RewardItem8Count,omitempty"` // Reward道具8数量
|
RewardItem8Count int32 `csv:"Reward道具8数量,omitempty"`
|
||||||
RewardItem9ID int32 `csv:"RewardItem9ID,omitempty"` // Reward道具9ID
|
RewardItem9ID int32 `csv:"Reward道具9ID,omitempty"`
|
||||||
RewardItem9Count int32 `csv:"RewardItem9Count,omitempty"` // Reward道具9数量
|
RewardItem9Count int32 `csv:"Reward道具9数量,omitempty"`
|
||||||
|
|
||||||
RewardItemMap map[uint32]uint32
|
RewardItemMap map[uint32]uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadRewardData() {
|
func (g *GameDataConfig) loadRewardData() {
|
||||||
g.RewardDataMap = make(map[int32]*RewardData)
|
g.RewardDataMap = make(map[int32]*RewardData)
|
||||||
data := g.readCsvFileData("RewardData.csv")
|
rewardDataList := make([]*RewardData, 0)
|
||||||
var rewardDataList []*RewardData
|
readTable[RewardData](g.tablePrefix+"RewardData.txt", &rewardDataList)
|
||||||
err := csvutil.Unmarshal(data, &rewardDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, rewardData := range rewardDataList {
|
for _, rewardData := range rewardDataList {
|
||||||
// list -> map
|
// list -> map
|
||||||
// 奖励物品整合
|
// 奖励物品整合
|
||||||
|
|||||||
@@ -1,28 +1,19 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SceneData 场景配置表
|
// SceneData 场景配置表
|
||||||
type SceneData struct {
|
type SceneData struct {
|
||||||
SceneId int32 `csv:"SceneId"` // ID
|
SceneId int32 `csv:"ID"`
|
||||||
SceneType int32 `csv:"SceneType,omitempty"` // 类型
|
SceneType int32 `csv:"类型,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadSceneData() {
|
func (g *GameDataConfig) loadSceneData() {
|
||||||
g.SceneDataMap = make(map[int32]*SceneData)
|
g.SceneDataMap = make(map[int32]*SceneData)
|
||||||
data := g.readCsvFileData("SceneData.csv")
|
sceneDataList := make([]*SceneData, 0)
|
||||||
var sceneDataList []*SceneData
|
readTable[SceneData](g.tablePrefix+"SceneData.txt", &sceneDataList)
|
||||||
err := csvutil.Unmarshal(data, &sceneDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, sceneData := range sceneDataList {
|
for _, sceneData := range sceneDataList {
|
||||||
// list -> map
|
// list -> map
|
||||||
g.SceneDataMap[sceneData.SceneId] = sceneData
|
g.SceneDataMap[sceneData.SceneId] = sceneData
|
||||||
|
|||||||
@@ -1,28 +1,19 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SceneTagData 场景标签配置表
|
// SceneTagData 场景标签配置表
|
||||||
type SceneTagData struct {
|
type SceneTagData struct {
|
||||||
SceneTagId int32 `csv:"SceneTagId"` // ID
|
SceneTagId int32 `csv:"ID"`
|
||||||
SceneId int32 `csv:"SceneId,omitempty"` // 场景ID
|
SceneId int32 `csv:"场景ID,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadSceneTagData() {
|
func (g *GameDataConfig) loadSceneTagData() {
|
||||||
g.SceneTagDataMap = make(map[int32]*SceneTagData)
|
g.SceneTagDataMap = make(map[int32]*SceneTagData)
|
||||||
data := g.readCsvFileData("SceneTagData.csv")
|
sceneTagDataList := make([]*SceneTagData, 0)
|
||||||
var sceneTagDataList []*SceneTagData
|
readTable[SceneTagData](g.tablePrefix+"SceneTagData.txt", &sceneTagDataList)
|
||||||
err := csvutil.Unmarshal(data, &sceneTagDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, sceneTagData := range sceneTagDataList {
|
for _, sceneTagData := range sceneTagDataList {
|
||||||
// list -> map
|
// list -> map
|
||||||
g.SceneTagDataMap[sceneTagData.SceneTagId] = sceneTagData
|
g.SceneTagDataMap[sceneTagData.SceneTagId] = sceneTagData
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,30 +1,21 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TriggerData 场景LUA触发器配置表
|
// TriggerData 场景LUA触发器配置表
|
||||||
type TriggerData struct {
|
type TriggerData struct {
|
||||||
TriggerId int32 `csv:"TriggerId"` // ID
|
TriggerId int32 `csv:"ID"`
|
||||||
SceneId int32 `csv:"SceneId,omitempty"` // 场景ID
|
SceneId int32 `csv:"场景ID,omitempty"`
|
||||||
GroupId int32 `csv:"GroupId,omitempty"` // 组ID
|
GroupId int32 `csv:"组ID,omitempty"`
|
||||||
TriggerName string `csv:"TriggerName,omitempty"` // 触发器
|
TriggerName string `csv:"触发器,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadTriggerData() {
|
func (g *GameDataConfig) loadTriggerData() {
|
||||||
g.TriggerDataMap = make(map[int32]*TriggerData)
|
g.TriggerDataMap = make(map[int32]*TriggerData)
|
||||||
data := g.readCsvFileData("TriggerData.csv")
|
triggerDataList := make([]*TriggerData, 0)
|
||||||
var triggerDataList []*TriggerData
|
readTable[TriggerData](g.tablePrefix+"TriggerData.txt", &triggerDataList)
|
||||||
err := csvutil.Unmarshal(data, &triggerDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, triggerData := range triggerDataList {
|
for _, triggerData := range triggerDataList {
|
||||||
g.TriggerDataMap[triggerData.TriggerId] = triggerData
|
g.TriggerDataMap[triggerData.TriggerId] = triggerData
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,25 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// WeaponLevelData 武器等级配置表
|
// WeaponLevelData 武器等级配置表
|
||||||
type WeaponLevelData struct {
|
type WeaponLevelData struct {
|
||||||
Level int32 `csv:"Level"` // 等级
|
Level int32 `csv:"等级"`
|
||||||
ExpByStar1 int32 `csv:"ExpByStar1,omitempty"` // 武器升级经验1
|
ExpByStar1 int32 `csv:"武器升级经验1,omitempty"`
|
||||||
ExpByStar2 int32 `csv:"ExpByStar2,omitempty"` // 武器升级经验2
|
ExpByStar2 int32 `csv:"武器升级经验2,omitempty"`
|
||||||
ExpByStar3 int32 `csv:"ExpByStar3,omitempty"` // 武器升级经验3
|
ExpByStar3 int32 `csv:"武器升级经验3,omitempty"`
|
||||||
ExpByStar4 int32 `csv:"ExpByStar4,omitempty"` // 武器升级经验4
|
ExpByStar4 int32 `csv:"武器升级经验4,omitempty"`
|
||||||
ExpByStar5 int32 `csv:"ExpByStar5,omitempty"` // 武器升级经验5
|
ExpByStar5 int32 `csv:"武器升级经验5,omitempty"`
|
||||||
|
|
||||||
ExpByStarMap map[uint32]uint32 // 星级对应武器升级经验
|
ExpByStarMap map[uint32]uint32 // 星级对应武器升级经验
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadWeaponLevelData() {
|
func (g *GameDataConfig) loadWeaponLevelData() {
|
||||||
g.WeaponLevelDataMap = make(map[int32]*WeaponLevelData)
|
g.WeaponLevelDataMap = make(map[int32]*WeaponLevelData)
|
||||||
data := g.readCsvFileData("WeaponLevelData.csv")
|
weaponLevelDataList := make([]*WeaponLevelData, 0)
|
||||||
var weaponLevelDataList []*WeaponLevelData
|
readTable[WeaponLevelData](g.tablePrefix+"WeaponLevelData.txt", &weaponLevelDataList)
|
||||||
err := csvutil.Unmarshal(data, &weaponLevelDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, weaponLevelData := range weaponLevelDataList {
|
for _, weaponLevelData := range weaponLevelDataList {
|
||||||
// list -> map
|
// list -> map
|
||||||
weaponLevelData.ExpByStarMap = map[uint32]uint32{
|
weaponLevelData.ExpByStarMap = map[uint32]uint32{
|
||||||
|
|||||||
@@ -1,39 +1,30 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// WeaponPromoteData 武器突破配置表
|
// WeaponPromoteData 武器突破配置表
|
||||||
type WeaponPromoteData struct {
|
type WeaponPromoteData struct {
|
||||||
PromoteId int32 `csv:"PromoteId"` // 武器突破ID
|
PromoteId int32 `csv:"武器突破ID"`
|
||||||
PromoteLevel int32 `csv:"PromoteLevel,omitempty"` // 突破等级
|
PromoteLevel int32 `csv:"突破等级,omitempty"`
|
||||||
CostItemId1 int32 `csv:"CostItemId1,omitempty"` // [消耗物品]1ID
|
CostItemId1 int32 `csv:"[消耗物品]1ID,omitempty"`
|
||||||
CostItemCount1 int32 `csv:"CostItemCount1,omitempty"` // [消耗物品]1数量
|
CostItemCount1 int32 `csv:"[消耗物品]1数量,omitempty"`
|
||||||
CostItemId2 int32 `csv:"CostItemId2,omitempty"` // [消耗物品]2ID
|
CostItemId2 int32 `csv:"[消耗物品]2ID,omitempty"`
|
||||||
CostItemCount2 int32 `csv:"CostItemCount2,omitempty"` // [消耗物品]2数量
|
CostItemCount2 int32 `csv:"[消耗物品]2数量,omitempty"`
|
||||||
CostItemId3 int32 `csv:"CostItemId3,omitempty"` // [消耗物品]3ID
|
CostItemId3 int32 `csv:"[消耗物品]3ID,omitempty"`
|
||||||
CostItemCount3 int32 `csv:"CostItemCount3,omitempty"` // [消耗物品]3数量
|
CostItemCount3 int32 `csv:"[消耗物品]3数量,omitempty"`
|
||||||
CostCoin int32 `csv:"CostCoin,omitempty"` // 突破消耗金币
|
CostCoin int32 `csv:"突破消耗金币,omitempty"`
|
||||||
LevelLimit int32 `csv:"LevelLimit,omitempty"` // 突破后解锁等级上限
|
LevelLimit int32 `csv:"突破后解锁等级上限,omitempty"`
|
||||||
MinPlayerLevel int32 `csv:"MinPlayerLevel,omitempty"` // 冒险等级要求
|
MinPlayerLevel int32 `csv:"冒险等级要求,omitempty"`
|
||||||
|
|
||||||
CostItemMap map[uint32]uint32 // 消耗物品列表
|
CostItemMap map[uint32]uint32 // 消耗物品列表
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadWeaponPromoteData() {
|
func (g *GameDataConfig) loadWeaponPromoteData() {
|
||||||
g.WeaponPromoteDataMap = make(map[int32]map[int32]*WeaponPromoteData)
|
g.WeaponPromoteDataMap = make(map[int32]map[int32]*WeaponPromoteData)
|
||||||
data := g.readCsvFileData("WeaponPromoteData.csv")
|
weaponPromoteDataList := make([]*WeaponPromoteData, 0)
|
||||||
var weaponPromoteDataList []*WeaponPromoteData
|
readTable[WeaponPromoteData](g.tablePrefix+"WeaponPromoteData.txt", &weaponPromoteDataList)
|
||||||
err := csvutil.Unmarshal(data, &weaponPromoteDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, weaponPromoteData := range weaponPromoteDataList {
|
for _, weaponPromoteData := range weaponPromoteDataList {
|
||||||
// list -> map
|
// list -> map
|
||||||
_, ok := g.WeaponPromoteDataMap[weaponPromoteData.PromoteId]
|
_, ok := g.WeaponPromoteDataMap[weaponPromoteData.PromoteId]
|
||||||
|
|||||||
@@ -1,30 +1,21 @@
|
|||||||
package gdconf
|
package gdconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
|
|
||||||
"github.com/jszwec/csvutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// WorldAreaData 世界区域配置表
|
// WorldAreaData 世界区域配置表
|
||||||
type WorldAreaData struct {
|
type WorldAreaData struct {
|
||||||
WorldAreaId int32 `csv:"WorldAreaId"` // 条目ID
|
WorldAreaId int32 `csv:"条目ID"`
|
||||||
SceneId int32 `csv:"SceneId,omitempty"` // 场景ID
|
SceneId int32 `csv:"场景ID,omitempty"`
|
||||||
AreaId1 int32 `csv:"AreaId1,omitempty"` // 一级区域ID
|
AreaId1 int32 `csv:"一级区域ID,omitempty"`
|
||||||
AreaId2 int32 `csv:"AreaId2,omitempty"` // 二级区域ID
|
AreaId2 int32 `csv:"二级区域ID,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameDataConfig) loadWorldAreaData() {
|
func (g *GameDataConfig) loadWorldAreaData() {
|
||||||
g.WorldAreaDataMap = make(map[int32]*WorldAreaData)
|
g.WorldAreaDataMap = make(map[int32]*WorldAreaData)
|
||||||
data := g.readCsvFileData("WorldAreaData.csv")
|
worldAreaDataList := make([]*WorldAreaData, 0)
|
||||||
var worldAreaDataList []*WorldAreaData
|
readTable[WorldAreaData](g.tablePrefix+"WorldAreaData.txt", &worldAreaDataList)
|
||||||
err := csvutil.Unmarshal(data, &worldAreaDataList)
|
|
||||||
if err != nil {
|
|
||||||
info := fmt.Sprintf("parse file error: %v", err)
|
|
||||||
panic(info)
|
|
||||||
}
|
|
||||||
for _, worldAreaData := range worldAreaDataList {
|
for _, worldAreaData := range worldAreaDataList {
|
||||||
// list -> map
|
// list -> map
|
||||||
g.WorldAreaDataMap[worldAreaData.WorldAreaId] = worldAreaData
|
g.WorldAreaDataMap[worldAreaData.WorldAreaId] = worldAreaData
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package game
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hk4e/common/mq"
|
|
||||||
"hk4e/gate/kcp"
|
"hk4e/gate/kcp"
|
||||||
"hk4e/gs/model"
|
"hk4e/gs/model"
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
@@ -136,7 +135,7 @@ func (g *GameManager) SetEntityClientDataNotify(player *model.Player, payloadMsg
|
|||||||
g.SendMsg(cmd.SetEntityClientDataNotify, player.PlayerID, player.ClientSeq, ntf)
|
g.SendMsg(cmd.SetEntityClientDataNotify, player.PlayerID, player.ClientSeq, ntf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameManager) ServerAppidBindNotify(userId uint32, fightAppId string, joinHostUserId uint32) {
|
func (g *GameManager) ServerAppidBindNotify(userId uint32, anticheatAppId string, joinHostUserId uint32) {
|
||||||
player := USER_MANAGER.GetOnlineUser(userId)
|
player := USER_MANAGER.GetOnlineUser(userId)
|
||||||
if player == nil {
|
if player == nil {
|
||||||
logger.Error("player is nil, uid: %v", userId)
|
logger.Error("player is nil, uid: %v", userId)
|
||||||
@@ -151,18 +150,10 @@ func (g *GameManager) ServerAppidBindNotify(userId uint32, fightAppId string, jo
|
|||||||
g.JoinOtherWorld(player, hostPlayer)
|
g.JoinOtherWorld(player, hostPlayer)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Debug("server appid bind notify, uid: %v, fightAppId: %v", userId, fightAppId)
|
logger.Debug("server appid bind notify, uid: %v, anticheatAppId: %v", userId, anticheatAppId)
|
||||||
player.FightAppId = fightAppId
|
player.AnticheatAppId = anticheatAppId
|
||||||
// 创建世界
|
// 创建世界
|
||||||
world := WORLD_MANAGER.CreateWorld(player)
|
world := WORLD_MANAGER.CreateWorld(player)
|
||||||
MESSAGE_QUEUE.SendToFight(fightAppId, &mq.NetMsg{
|
|
||||||
MsgType: mq.MsgTypeFight,
|
|
||||||
EventId: mq.AddFightRoutine,
|
|
||||||
FightMsg: &mq.FightMsg{
|
|
||||||
FightRoutineId: world.GetId(),
|
|
||||||
GateServerAppId: player.GateAppId,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
world.AddPlayer(player, player.SceneId)
|
world.AddPlayer(player, player.SceneId)
|
||||||
player.WorldId = world.GetId()
|
player.WorldId = world.GetId()
|
||||||
// 进入场景
|
// 进入场景
|
||||||
|
|||||||
@@ -420,13 +420,6 @@ func (g *GameManager) UserWorldRemovePlayer(world *World, player *model.Player)
|
|||||||
if world.GetOwner().PlayerID == player.PlayerID {
|
if world.GetOwner().PlayerID == player.PlayerID {
|
||||||
// 房主离开销毁世界
|
// 房主离开销毁世界
|
||||||
WORLD_MANAGER.DestroyWorld(world.GetId())
|
WORLD_MANAGER.DestroyWorld(world.GetId())
|
||||||
MESSAGE_QUEUE.SendToFight(world.GetOwner().FightAppId, &mq.NetMsg{
|
|
||||||
MsgType: mq.MsgTypeFight,
|
|
||||||
EventId: mq.DelFightRoutine,
|
|
||||||
FightMsg: &mq.FightMsg{
|
|
||||||
FightRoutineId: world.GetId(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if world.GetMultiplayer() && world.GetWorldPlayerNum() > 0 {
|
if world.GetMultiplayer() && world.GetWorldPlayerNum() > 0 {
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ func (g *GameManager) WeaponAwakenReq(player *model.Player, payloadMsg pb.Messag
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 确保获取消耗的摩拉索引不越界
|
// 确保获取消耗的摩拉索引不越界
|
||||||
if int(weapon.Refinement) >= len(weaponConfig.AwakenCoinCostList) {
|
if int(weapon.Refinement) >= len(weaponConfig.AwakenCoinCost) {
|
||||||
logger.Error("weapon config cost coin error, itemId: %v", weapon.ItemId)
|
logger.Error("weapon config cost coin error, itemId: %v", weapon.ItemId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -217,7 +217,7 @@ func (g *GameManager) WeaponAwakenReq(player *model.Player, payloadMsg pb.Messag
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 消耗摩拉
|
// 消耗摩拉
|
||||||
ok = g.CostUserItem(player.PlayerID, []*ChangeItem{{ItemId: constant.ITEM_ID_SCOIN, ChangeCount: weaponConfig.AwakenCoinCostList[weapon.Refinement]}})
|
ok = g.CostUserItem(player.PlayerID, []*ChangeItem{{ItemId: constant.ITEM_ID_SCOIN, ChangeCount: uint32(weaponConfig.AwakenCoinCost[weapon.Refinement])}})
|
||||||
if !ok {
|
if !ok {
|
||||||
logger.Error("item count not enough, uid: %v", player.PlayerID)
|
logger.Error("item count not enough, uid: %v", player.PlayerID)
|
||||||
g.SendError(cmd.WeaponAwakenRsp, player, &proto.WeaponAwakenRsp{}, proto.Retcode_RET_SCOIN_NOT_ENOUGH)
|
g.SendError(cmd.WeaponAwakenRsp, player, &proto.WeaponAwakenRsp{}, proto.Retcode_RET_SCOIN_NOT_ENOUGH)
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ func (r *RouteManager) RouteHandle(netMsg *mq.NetMsg) {
|
|||||||
logger.Debug("remote user online state change, uid: %v, online: %v", serverMsg.UserId, serverMsg.IsOnline)
|
logger.Debug("remote user online state change, uid: %v, online: %v", serverMsg.UserId, serverMsg.IsOnline)
|
||||||
USER_MANAGER.SetRemoteUserOnlineState(serverMsg.UserId, serverMsg.IsOnline, netMsg.OriginServerAppId)
|
USER_MANAGER.SetRemoteUserOnlineState(serverMsg.UserId, serverMsg.IsOnline, netMsg.OriginServerAppId)
|
||||||
case mq.ServerAppidBindNotify:
|
case mq.ServerAppidBindNotify:
|
||||||
GAME_MANAGER.ServerAppidBindNotify(serverMsg.UserId, serverMsg.FightServerAppId, serverMsg.JoinHostUserId)
|
GAME_MANAGER.ServerAppidBindNotify(serverMsg.UserId, serverMsg.AnticheatServerAppId, serverMsg.JoinHostUserId)
|
||||||
case mq.ServerUserMpReq:
|
case mq.ServerUserMpReq:
|
||||||
GAME_MANAGER.ServerUserMpReq(serverMsg.UserMpInfo, netMsg.OriginServerAppId)
|
GAME_MANAGER.ServerUserMpReq(serverMsg.UserMpInfo, netMsg.OriginServerAppId)
|
||||||
case mq.ServerUserMpRsp:
|
case mq.ServerUserMpRsp:
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hk4e/common/constant"
|
"hk4e/common/constant"
|
||||||
"hk4e/common/mq"
|
|
||||||
"hk4e/gs/model"
|
"hk4e/gs/model"
|
||||||
"hk4e/pkg/logger"
|
"hk4e/pkg/logger"
|
||||||
"hk4e/protocol/cmd"
|
"hk4e/protocol/cmd"
|
||||||
@@ -163,17 +162,6 @@ func (s *Scene) CreateEntityAvatar(player *model.Player, avatarId uint32) uint32
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
s.CreateEntity(entity, 0)
|
s.CreateEntity(entity, 0)
|
||||||
MESSAGE_QUEUE.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{
|
|
||||||
MsgType: mq.MsgTypeFight,
|
|
||||||
EventId: mq.FightRoutineAddEntity,
|
|
||||||
FightMsg: &mq.FightMsg{
|
|
||||||
FightRoutineId: s.world.id,
|
|
||||||
EntityId: entity.id,
|
|
||||||
FightPropMap: entity.fightProp,
|
|
||||||
Uid: entity.avatarEntity.uid,
|
|
||||||
AvatarGuid: dbAvatar.AvatarMap[avatarId].Guid,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return entity.id
|
return entity.id
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,15 +208,6 @@ func (s *Scene) CreateEntityMonster(pos, rot *model.Vector, monsterId uint32, le
|
|||||||
objectId: objectId,
|
objectId: objectId,
|
||||||
}
|
}
|
||||||
s.CreateEntity(entity, objectId)
|
s.CreateEntity(entity, objectId)
|
||||||
MESSAGE_QUEUE.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{
|
|
||||||
MsgType: mq.MsgTypeFight,
|
|
||||||
EventId: mq.FightRoutineAddEntity,
|
|
||||||
FightMsg: &mq.FightMsg{
|
|
||||||
FightRoutineId: s.world.id,
|
|
||||||
EntityId: entity.id,
|
|
||||||
FightPropMap: entity.fightProp,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return entity.id
|
return entity.id
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,14 +399,6 @@ func (s *Scene) DestroyEntity(entityId uint32) {
|
|||||||
}
|
}
|
||||||
delete(s.entityMap, entity.id)
|
delete(s.entityMap, entity.id)
|
||||||
delete(s.objectIdEntityMap, entity.objectId)
|
delete(s.objectIdEntityMap, entity.objectId)
|
||||||
MESSAGE_QUEUE.SendToFight(s.world.owner.FightAppId, &mq.NetMsg{
|
|
||||||
MsgType: mq.MsgTypeFight,
|
|
||||||
EventId: mq.FightRoutineDelEntity,
|
|
||||||
FightMsg: &mq.FightMsg{
|
|
||||||
FightRoutineId: s.world.id,
|
|
||||||
EntityId: entity.id,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scene) GetEntity(entityId uint32) *Entity {
|
func (s *Scene) GetEntity(entityId uint32) *Entity {
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ type Player struct {
|
|||||||
CombatInvokeHandler *InvokeHandler[proto.CombatInvokeEntry] `bson:"-" msgpack:"-"` // combat转发器
|
CombatInvokeHandler *InvokeHandler[proto.CombatInvokeEntry] `bson:"-" msgpack:"-"` // combat转发器
|
||||||
AbilityInvokeHandler *InvokeHandler[proto.AbilityInvokeEntry] `bson:"-" msgpack:"-"` // ability转发器
|
AbilityInvokeHandler *InvokeHandler[proto.AbilityInvokeEntry] `bson:"-" msgpack:"-"` // ability转发器
|
||||||
GateAppId string `bson:"-" msgpack:"-"` // 网关服务器的appid
|
GateAppId string `bson:"-" msgpack:"-"` // 网关服务器的appid
|
||||||
FightAppId string `bson:"-" msgpack:"-"` // 战斗服务器的appid
|
AnticheatAppId string `bson:"-" msgpack:"-"` // 反作弊服务器的appid
|
||||||
GCGCurGameGuid uint32 `bson:"-" msgpack:"-"` // GCG玩家所在的游戏guid
|
GCGCurGameGuid uint32 `bson:"-" msgpack:"-"` // GCG玩家所在的游戏guid
|
||||||
GCGInfo *GCGInfo `bson:"-" msgpack:"-"` // 七圣召唤信息
|
GCGInfo *GCGInfo `bson:"-" msgpack:"-"` // 七圣召唤信息
|
||||||
XLuaDebug bool `bson:"-" msgpack:"-"` // 是否开启客户端XLUA调试
|
XLuaDebug bool `bson:"-" msgpack:"-"` // 是否开启客户端XLUA调试
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ package api
|
|||||||
const (
|
const (
|
||||||
GATE = "GATE"
|
GATE = "GATE"
|
||||||
GS = "GS"
|
GS = "GS"
|
||||||
FIGHT = "FIGHT"
|
ANTICHEAT = "ANTICHEAT"
|
||||||
PATHFINDING = "PATHFINDING"
|
PATHFINDING = "PATHFINDING"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func NewDiscoveryService() *DiscoveryService {
|
|||||||
r.serverInstanceMap = make(map[string]*sync.Map)
|
r.serverInstanceMap = make(map[string]*sync.Map)
|
||||||
r.serverInstanceMap[api.GATE] = new(sync.Map)
|
r.serverInstanceMap[api.GATE] = new(sync.Map)
|
||||||
r.serverInstanceMap[api.GS] = new(sync.Map)
|
r.serverInstanceMap[api.GS] = new(sync.Map)
|
||||||
r.serverInstanceMap[api.FIGHT] = new(sync.Map)
|
r.serverInstanceMap[api.ANTICHEAT] = new(sync.Map)
|
||||||
r.serverInstanceMap[api.PATHFINDING] = new(sync.Map)
|
r.serverInstanceMap[api.PATHFINDING] = new(sync.Map)
|
||||||
r.serverAppIdMap = new(sync.Map)
|
r.serverAppIdMap = new(sync.Map)
|
||||||
go r.removeDeadServer()
|
go r.removeDeadServer()
|
||||||
|
|||||||
Reference in New Issue
Block a user