版本更新
This commit is contained in:
commit
da25ec4b84
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
.idea
|
||||
.vscode
|
||||
*.exe
|
||||
src/server/log
|
||||
csv_output/
|
||||
json/
|
||||
csv_output/
|
||||
docs/
|
||||
src/server/log/
|
||||
src/server/*.exe
|
||||
src/server/gamedata/config/*.json
|
||||
src/server/unit_test.go
|
||||
191
LICENSE
Normal file
191
LICENSE
Normal file
@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015-2017 Name5566.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
8
README.md
Normal file
8
README.md
Normal file
@ -0,0 +1,8 @@
|
||||
Leaf server
|
||||
===========
|
||||
A game server based on [Leaf framework](https://github.com/name5566/leaf).
|
||||
|
||||
Licensing
|
||||
---------
|
||||
|
||||
Leaf server is licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/name5566/leafserver/blob/master/LICENSE) for the full license text.
|
||||
12
bin/conf/server.json
Normal file
12
bin/conf/server.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"LogLevel": "debug",
|
||||
"LogPath": "",
|
||||
"TCPAddr": "192.168.0.104:3562",
|
||||
"WSAddr": "192.168.0.104:3563",
|
||||
"MySqlUsr": "root",
|
||||
"MySqlPwd": "xijing123456",
|
||||
"MaxConnNum": 20000,
|
||||
"ServerID": 1,
|
||||
"DbName": "Merge_Pet",
|
||||
"HttpPort": ":8081"
|
||||
}
|
||||
2
bin/gamedata/.gitignore
vendored
Normal file
2
bin/gamedata/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
2
bin/log/.gitignore
vendored
Normal file
2
bin/log/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
179
src/server/GoUtil/GoUtil.go
Normal file
179
src/server/GoUtil/GoUtil.go
Normal file
@ -0,0 +1,179 @@
|
||||
package GoUtil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 实例化一个通过字符串映射函数切片的map
|
||||
var eventByName = make(map[string][]*EventObj)
|
||||
|
||||
type EventObj struct {
|
||||
Callback func([]interface{})
|
||||
Obj interface{}
|
||||
}
|
||||
|
||||
func (o *EventObj) isEqual(tar *EventObj) bool {
|
||||
if reflect.ValueOf(o.Callback).Pointer() == reflect.ValueOf(tar.Callback).Pointer() && o.Obj == tar.Obj {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 注册事件,提供事件名和回调函数
|
||||
func RegisterEvent(name string, callback func([]interface{}), Obj interface{}) {
|
||||
|
||||
eo := new(EventObj)
|
||||
eo.Callback = callback
|
||||
eo.Obj = Obj
|
||||
// 通过名字查找事件列表
|
||||
list := eventByName[name]
|
||||
|
||||
// 在列表切片中添加函数
|
||||
list = append(list, eo)
|
||||
|
||||
// 将修改的事件列表切片保存回去
|
||||
eventByName[name] = list
|
||||
}
|
||||
|
||||
// 调用事件
|
||||
func CallEvent(name string, param []interface{}) {
|
||||
|
||||
// 通过名字找到事件列表
|
||||
list := eventByName[name]
|
||||
|
||||
// 遍历这个事件的所有回调
|
||||
for _, eo := range list {
|
||||
// 传入参数调用回调
|
||||
eo.Callback(param)
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveEvent(name string, callback func([]interface{}), Obj interface{}) {
|
||||
// 通过名字找到事件列表
|
||||
list := eventByName[name]
|
||||
j := 0
|
||||
eo := new(EventObj)
|
||||
eo.Callback = callback
|
||||
eo.Obj = Obj
|
||||
// 遍历这个事件的所有回调
|
||||
for _, v := range list {
|
||||
if !v.isEqual(eo) {
|
||||
list[j] = v
|
||||
j++
|
||||
}
|
||||
}
|
||||
eventByName[name] = list[:j]
|
||||
// fmt.Println("len eventByName[name]:", len(eventByName[name]))
|
||||
//fmt.Println("len eventByName[name]:", len(eventByName))
|
||||
// fmt.Println("len list:", len(list))
|
||||
}
|
||||
|
||||
func DeleteEleByValue(list []int, ele int) []int {
|
||||
j := 0
|
||||
for _, v := range list {
|
||||
if v != ele {
|
||||
list[j] = v
|
||||
j++
|
||||
}
|
||||
}
|
||||
ret := list[:j]
|
||||
return ret
|
||||
}
|
||||
|
||||
func BoolToInt32(b bool) int32 {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func IfTrue(a bool, b, c interface{}) interface{} {
|
||||
if a {
|
||||
return b
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func Int64(a interface{}) int64 {
|
||||
if a == nil {
|
||||
return 0
|
||||
}
|
||||
switch v := a.(type) {
|
||||
case int:
|
||||
return int64(v)
|
||||
case int32:
|
||||
return int64(v)
|
||||
case int64:
|
||||
return v
|
||||
case float64:
|
||||
return int64(v)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func Int(a interface{}) int {
|
||||
if a == nil {
|
||||
return 0
|
||||
}
|
||||
switch v := a.(type) {
|
||||
case int:
|
||||
return v
|
||||
case int32:
|
||||
return int(v)
|
||||
case int64:
|
||||
return int(v)
|
||||
case float64:
|
||||
return int(v)
|
||||
case string:
|
||||
r, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return r
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func GobMarshal(data interface{}) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
encode := gob.NewEncoder(&buf)
|
||||
err := encode.Encode(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func GobUnmarshal(data []byte, obj interface{}) error {
|
||||
decode := gob.NewDecoder(bytes.NewReader(data))
|
||||
err := decode.Decode(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetServerIdByUid(uid int) int {
|
||||
return int(uid / 100000)
|
||||
}
|
||||
|
||||
func CreateOrderSn(uid int) string {
|
||||
Now := time.Now()
|
||||
return "order_" + strconv.Itoa(uid) + "_" + Now.Format("20060102150405") + RandString(6)
|
||||
}
|
||||
|
||||
// 生成指定长度的随机字符串
|
||||
func RandString(n int) string {
|
||||
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
b[i] = letters[r.Intn(len(letters))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
67
src/server/GoUtil/mapUtil.go
Normal file
67
src/server/GoUtil/mapUtil.go
Normal file
@ -0,0 +1,67 @@
|
||||
package GoUtil
|
||||
|
||||
import (
|
||||
dailyTaskCfg "server/conf/dailyTask"
|
||||
"server/game/mod/item"
|
||||
)
|
||||
|
||||
func MapIntToSlice(m map[int]struct{}) []int32 {
|
||||
var s []int32
|
||||
for k := range m {
|
||||
s = append(s, int32(k))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func MapIntToInt32(m map[int]int) map[int32]int32 {
|
||||
r := make(map[int32]int32)
|
||||
for k, v := range m {
|
||||
r[int32(k)] = int32(v)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func GetMapKey(v any) []int {
|
||||
if v == nil {
|
||||
return []int{}
|
||||
}
|
||||
switch m := v.(type) {
|
||||
case map[int]int:
|
||||
var keys []int
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys
|
||||
case map[int32]int32:
|
||||
var keys []int
|
||||
for k := range m {
|
||||
keys = append(keys, int(k))
|
||||
}
|
||||
return keys
|
||||
case map[int]struct{}:
|
||||
var keys []int
|
||||
for k := range m {
|
||||
keys = append(keys, int(k))
|
||||
}
|
||||
return keys
|
||||
case map[int]string:
|
||||
var keys []int
|
||||
for k := range m {
|
||||
keys = append(keys, int(k))
|
||||
}
|
||||
return keys
|
||||
case map[int][]*item.Item:
|
||||
var keys []int
|
||||
for k := range m {
|
||||
keys = append(keys, int(k))
|
||||
}
|
||||
return keys
|
||||
case map[int]dailyTaskCfg.Jackpot:
|
||||
var keys []int
|
||||
for k := range m {
|
||||
keys = append(keys, int(k))
|
||||
}
|
||||
return keys
|
||||
}
|
||||
return []int{}
|
||||
}
|
||||
8
src/server/GoUtil/mathUtil.go
Normal file
8
src/server/GoUtil/mathUtil.go
Normal file
@ -0,0 +1,8 @@
|
||||
package GoUtil
|
||||
|
||||
func RandNum(start int, end int) int {
|
||||
if start > end {
|
||||
return 0
|
||||
}
|
||||
return start + GetRand().Intn(end-start+1)
|
||||
}
|
||||
51
src/server/GoUtil/randUtil.go
Normal file
51
src/server/GoUtil/randUtil.go
Normal file
@ -0,0 +1,51 @@
|
||||
package GoUtil
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
func RandMap(d map[int]int) int {
|
||||
total := 0
|
||||
for _, v := range d {
|
||||
total += v
|
||||
}
|
||||
|
||||
// 生成一个 [0, total) 范围内的随机数
|
||||
r := rand.Intn(total)
|
||||
|
||||
// 根据随机数选择一个键
|
||||
for k, v := range d {
|
||||
if r < v {
|
||||
return k
|
||||
}
|
||||
r -= v
|
||||
}
|
||||
|
||||
// 如果没有找到,返回一个默认值
|
||||
return -1
|
||||
}
|
||||
|
||||
// 从d中随机选取n个元素 不放回
|
||||
func RandMapNum(d map[int]int, n int) []int {
|
||||
if n <= 0 || n > len(d) {
|
||||
return nil
|
||||
}
|
||||
if n == len(d) {
|
||||
for k := range d {
|
||||
return []int{k}
|
||||
}
|
||||
}
|
||||
r := make([]int, 0, n)
|
||||
for i := 0; i < n; i++ {
|
||||
k := RandMap(d)
|
||||
r = append(r, k)
|
||||
delete(d, k)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func GetRand() *rand.Rand {
|
||||
randS := rand.NewSource(time.Now().UnixNano())
|
||||
return rand.New(randS)
|
||||
}
|
||||
172
src/server/GoUtil/sliceUtil.go
Normal file
172
src/server/GoUtil/sliceUtil.go
Normal file
@ -0,0 +1,172 @@
|
||||
package GoUtil
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func IntToInt32(d []int) []int32 {
|
||||
r := make([]int32, 0, len(d))
|
||||
for _, d := range d {
|
||||
r = append(r, int32(d))
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func RandPopSlice(slice []int) ([]int, int) {
|
||||
slen := len(slice)
|
||||
if slen == 0 {
|
||||
return slice, -1
|
||||
}
|
||||
Id := GetRand().Intn(slen)
|
||||
return append(slice[0:Id], slice[Id+1:]...), slice[Id]
|
||||
}
|
||||
|
||||
func RandSlice(slice []int) int {
|
||||
slen := len(slice)
|
||||
if slen == 0 {
|
||||
return 0
|
||||
}
|
||||
Id := GetRand().Intn(slen)
|
||||
return slice[Id]
|
||||
}
|
||||
|
||||
func RandSliceNum(slice []int, num int) []int {
|
||||
r := make([]int, 0, num)
|
||||
if num <= 0 || len(slice) < num {
|
||||
return slice
|
||||
}
|
||||
|
||||
for i := 0; i < num; i++ {
|
||||
Id := GetRand().Intn(len(slice))
|
||||
r = append(r, slice[Id])
|
||||
slice = append(slice[0:Id], slice[Id+1:]...)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func RandSliceNumNonAdjacent(slice []int, num int) []int {
|
||||
if len(slice) < 2*num {
|
||||
return nil
|
||||
}
|
||||
sort.Ints(slice)
|
||||
result := make([]int, 0, num)
|
||||
for len(result) < num {
|
||||
Id := GetRand().Intn(len(slice))
|
||||
result = append(result, slice[Id])
|
||||
slice = SubAdjacentElemSlice(slice, Id)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func SubAdjacentElemSlice(s []int, Id int) []int {
|
||||
r := make([]int, 0, len(s))
|
||||
for k, v := range s {
|
||||
if k < Id-1 || k > Id+1 {
|
||||
r = append(r, v)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func RandStringSlice(slice []string) string {
|
||||
slen := len(slice)
|
||||
if slen == 0 {
|
||||
return ""
|
||||
}
|
||||
Id := GetRand().Intn(slen)
|
||||
return slice[Id]
|
||||
}
|
||||
|
||||
func SliceStringToInt(s []string) []int {
|
||||
if len(s) == 0 {
|
||||
return []int{}
|
||||
}
|
||||
r := make([]int, 0, len(s))
|
||||
for _, v := range s {
|
||||
v1, _ := strconv.Atoi(v)
|
||||
r = append(r, v1)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func SliceIntToInt32(s []int) []int32 {
|
||||
r := make([]int32, 0, len(s))
|
||||
for _, v := range s {
|
||||
r = append(r, int32(v))
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func PopElemSlice(s []int, Id int) ([]int, bool) {
|
||||
for k, v := range s {
|
||||
if v == Id {
|
||||
return append(s[0:k], s[k+1:]...), true
|
||||
}
|
||||
}
|
||||
return s, false
|
||||
}
|
||||
|
||||
func ElemInSlice(s []int, Id int) bool {
|
||||
for _, v := range s {
|
||||
if v == Id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GetElemNum(s []int, Id int) int {
|
||||
n := 0
|
||||
for _, v := range s {
|
||||
if v == Id {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func InArray(Id int, s []int) bool {
|
||||
for _, v := range s {
|
||||
if v == Id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func InStringArray(Id string, s []string) bool {
|
||||
for _, v := range s {
|
||||
if v == Id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// toInterfaceSlice converts a slice of strings to a slice of empty interfaces
|
||||
func ToInterfaceSlice(slice []string) []interface{} {
|
||||
result := make([]interface{}, len(slice))
|
||||
for i, v := range slice {
|
||||
result[i] = v
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// a - b
|
||||
func SubSlices(a, b []int) []int {
|
||||
result := make([]int, 0, len(a))
|
||||
for _, num := range a {
|
||||
if !InArray(num, b) {
|
||||
result = append(result, num)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func PopSlice(s []int) (int, []int) {
|
||||
if len(s) == 0 {
|
||||
return -1, s
|
||||
}
|
||||
return s[0], s[1:]
|
||||
}
|
||||
120
src/server/GoUtil/timeUtil.go
Normal file
120
src/server/GoUtil/timeUtil.go
Normal file
@ -0,0 +1,120 @@
|
||||
package GoUtil
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
SEVENDAYS = 604800
|
||||
MONTHDAYS = 2592000
|
||||
)
|
||||
|
||||
func ZeroTimestamp() int64 {
|
||||
now := time.Now()
|
||||
midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
return midnight.Unix()
|
||||
}
|
||||
|
||||
func NoonTimestamp() int64 {
|
||||
now := time.Now()
|
||||
midDay := time.Date(now.Year(), now.Month(), now.Day(), 12, 0, 0, 0, now.Location())
|
||||
return midDay.Unix()
|
||||
}
|
||||
|
||||
func MonthZeroTimestamp() int64 {
|
||||
now := time.Now()
|
||||
midnight := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
|
||||
return midnight.Unix()
|
||||
}
|
||||
|
||||
func NextZeroTimestampDuration() int64 {
|
||||
now := time.Now()
|
||||
midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
return midnight.AddDate(0, 0, 1).Unix() - now.Unix()
|
||||
}
|
||||
|
||||
// 获取距离下个中午十二点时间戳的秒数
|
||||
func NextNoonTimestampDuration() int64 {
|
||||
now := time.Now()
|
||||
nextNoon := time.Date(now.Year(), now.Month(), now.Day(), 12, 0, 0, 0, now.Location())
|
||||
|
||||
// 如果当前时间已经过了今天的中午十二点,则计算明天的中午十二点
|
||||
if now.After(nextNoon) {
|
||||
nextNoon = nextNoon.Add(24 * time.Hour)
|
||||
}
|
||||
|
||||
return int64(nextNoon.Sub(now).Seconds())
|
||||
}
|
||||
|
||||
func NextHourRemain() float64 {
|
||||
now := time.Now()
|
||||
nextHour := now.Truncate(time.Hour).Add(time.Hour)
|
||||
return nextHour.Sub(now).Seconds()
|
||||
}
|
||||
|
||||
func NextWeekTimestampDuration() int64 {
|
||||
now := time.Now()
|
||||
weekday := int(now.Weekday())
|
||||
if weekday == 0 {
|
||||
weekday = 7
|
||||
}
|
||||
midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
return midnight.AddDate(0, 0, 8-weekday).Unix() - now.Unix()
|
||||
}
|
||||
|
||||
func WeekZeroTimestamp() int64 {
|
||||
now := time.Now()
|
||||
weekday := int(now.Weekday())
|
||||
if weekday == 0 {
|
||||
weekday = 7
|
||||
}
|
||||
midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
return midnight.Unix() - int64((weekday-1)*86400)
|
||||
}
|
||||
|
||||
func Now() int64 {
|
||||
return time.Now().Unix()
|
||||
}
|
||||
func NowNano() int64 {
|
||||
return int64(time.Now().Nanosecond())
|
||||
}
|
||||
func GetWeekdayAndHour() (int, int) {
|
||||
now := time.Now()
|
||||
weekday := int(now.Weekday())
|
||||
if weekday == 0 {
|
||||
weekday = 7
|
||||
}
|
||||
hour := now.Hour()
|
||||
return weekday, hour
|
||||
}
|
||||
|
||||
func ParseTime(timeStr string) int64 {
|
||||
t, _ := time.Parse("2006-01-02 15:04:05", timeStr)
|
||||
return t.Unix()
|
||||
}
|
||||
|
||||
// 获取时间戳距离现在过了多少个自然周
|
||||
func WeeksSince(timestamp int64) int {
|
||||
// 将时间戳转换为 time.Time 对象
|
||||
t := time.Unix(timestamp, 0)
|
||||
|
||||
// 获取当前时间
|
||||
now := time.Now()
|
||||
|
||||
// 计算两个时间之间的周数差
|
||||
weeks := int(now.Sub(t).Hours() / (24 * 7))
|
||||
return weeks
|
||||
}
|
||||
|
||||
// 计算给定时间戳距离现在跨过了多少个自然周
|
||||
func FullWeeksSince(timestamp int64) int {
|
||||
// 将时间戳转换为 time.Time 对象
|
||||
t := time.Unix(timestamp, 0)
|
||||
|
||||
// 获取当前时间
|
||||
now := time.Now()
|
||||
|
||||
// 计算两个时间之间跨过的自然周数
|
||||
startWeek := t.Year()*52 + t.YearDay()/7
|
||||
currentWeek := now.Year()*52 + now.YearDay()/7
|
||||
|
||||
return currentWeek - startWeek
|
||||
}
|
||||
103
src/server/MergeConst/ErrorCode.go
Normal file
103
src/server/MergeConst/ErrorCode.go
Normal file
@ -0,0 +1,103 @@
|
||||
package MergeConst
|
||||
|
||||
type ProtocolType int32
|
||||
|
||||
const (
|
||||
Protocol_Error_Account_Exist int32 = 100
|
||||
Protocol_Error_Account_OR_PWD_ERROR int32 = 101
|
||||
Protocol_Error_Account_OR_PWD_Short int32 = 102
|
||||
Protocol_Error_Account_Fail int32 = 103
|
||||
Protocol_Error_Account_NoExsit int32 = 104
|
||||
Protocol_Res_Buy_Cnt_Limit int32 = 110
|
||||
Protocol_Res_Buy_CD int32 = 111
|
||||
Protocol_Email_Find_Fail int32 = 120
|
||||
Protocol_Active_No_Exsit int32 = 130
|
||||
Protocol_Active_7Day_Rewarded int32 = 131
|
||||
Protocol_Active_Card_NoEnough int32 = 132
|
||||
Protocol_Active_CardFragment_NoEnough int32 = 133
|
||||
Protocol_Active_CardTime_NoEnough int32 = 134
|
||||
Protocol_Active_CardTime_Outline int32 = 135
|
||||
Protocol_Exchange_Card_No_Exsit int32 = 136
|
||||
Protocol_PigID_No_Exsit int32 = 140
|
||||
Protocol_LvUpPack_No_Exsit int32 = 150
|
||||
Protocol_LvUpPack_Buyed int32 = 151
|
||||
Protocol_GrowthFund_Geted int32 = 160
|
||||
Protocol_Illustrate_InActive int32 = 170
|
||||
Protocol_Illustrate_Geted int32 = 171
|
||||
Protocol_Active_Card_Rewarded int32 = 180
|
||||
Protocol_Active_GoldCardTime_Cnt_NoEnouch int32 = 181
|
||||
Protocol_Active_GoldCard_illegal_Swap int32 = 182
|
||||
Protocol_Active_GoldCard_illegal_Donate int32 = 183
|
||||
|
||||
Protocol_Champship_End int32 = 200
|
||||
Protocol_Champship_No_Exsit int32 = 201
|
||||
Protocol_Champship_No_Join int32 = 202
|
||||
Protocol_Champship_Have_GetWarded int32 = 203
|
||||
|
||||
Protocol_Newbie_Pack_Opened int32 = 210
|
||||
Protocol_Newbie_Pack_OutLine int32 = 211
|
||||
Protocol_Ad_Pack_Geted int32 = 212
|
||||
|
||||
Protocol_Player_Not_Exsit int32 = 220 ///玩家不存在
|
||||
Protocol_Player_Is_Friend int32 = 221 ///该玩家已经是你的好友
|
||||
Protocol_AddFriend_Is_Send int32 = 222 ///已经发送过添加好友请求
|
||||
Protocol_AddFriend_Is_NoExsit int32 = 223 ///添加的好友不存在
|
||||
Protocol_AddFriend_Is_YourSelf int32 = 224 ///搜索玩家是你自己
|
||||
Protocol_AddFriend_Is_UpLimit int32 = 225 ///好友数量已达上限
|
||||
Protocol_AddFriend_Is_Target_Send int32 = 226 ///
|
||||
Protocol_AddFriend_Get_Invite_Reward int32 = 230 ///
|
||||
|
||||
Protocol_FaceBook_Binded int32 = 250 //账号已经绑定过
|
||||
Protocol_FaceBook_Binded_other int32 = 251 //账号已经绑定过其他设备
|
||||
|
||||
)
|
||||
|
||||
const (
|
||||
Notify_Socket_Closed string = "Notify_Socket_Closed"
|
||||
Notify_Limit_Active_Open string = "Notify_Limit_Active_Open"
|
||||
Notify_Socket_Connect string = "Notify_Socket_Connect"
|
||||
Notify_Daily_Renew string = "Notify_Daily_Renew"
|
||||
Notify_Midday_Renew string = "Notify_Midday_Renew"
|
||||
Notify_Card_Renew string = "Notify_Card_Renew"
|
||||
Notify_Clock_Tick_Sec string = "Notify_Clock_Tick_Sec"
|
||||
ResPlayerEmitUnlockData string = "ResPlayerEmitUnlockData"
|
||||
ResPlayerPackData string = "ResPlayerPackData"
|
||||
|
||||
OpenNewLimitActivity string = "OpenNewLimitActivity"
|
||||
CloseNewLimitActivity string = "CloseNewLimitActivity"
|
||||
|
||||
Notify_MileStone_Renew string = "Notify_MileStone_Renew"
|
||||
|
||||
Notify_Champion_Renew string = "Notify_Champion_Renew"
|
||||
Notify_OpenChampShipTimes string = "Notify_OpenChampShipTimes"
|
||||
Notify_CloseChampShipTimes string = "Notify_CloseChampShipTimes"
|
||||
Notify_EndChampShip string = "Notify_EndChampShip"
|
||||
Notify_Champion_Enter_Rank string = "Notify_Champion_Enter_Rank"
|
||||
|
||||
Notify_Renew_Ad_Pack string = "Notify_Renew_Ad_Pack"
|
||||
OpenNewLimitEvent string = "OpenNewLimitEvent"
|
||||
)
|
||||
|
||||
const G_Sta_RecoverTime = 120 // 2分钟恢复一次能量
|
||||
const G_Sta_Limit int32 = 100
|
||||
const G_Sta_Buy_Cnt int32 = 5
|
||||
const G_Sta_Buy_CD int32 = 60 * 2
|
||||
const G_Clear_Read_Email_Limit = 3600 * 24 * 3
|
||||
const G_Pig_Limite = 7 * 3600 * 24
|
||||
const G_PigIsOne = true
|
||||
const G_MailStone_Period = 3600 * 24 * 2
|
||||
const G_Champion_Start_Offset = 1800
|
||||
const G_Champion_Start_Effect_Time = 3600 * 18
|
||||
const G_Champion_Start_Effect_Durtion = 1800
|
||||
const G_Champion_Duration = 3600*24 - 1800
|
||||
const G_Champion_settlement_Duration = 3600 * 23
|
||||
const G_Champion_Unlock_Score = 2
|
||||
const G_Champion_Max_Score = 44650
|
||||
const G_Champion_People_Cnt = 50
|
||||
|
||||
const (
|
||||
ORDER_STATUS_IDLE = 0 // 订单未完成
|
||||
ORDER_STATUS_PAY = 1 // 订单已支付
|
||||
ORDER_STATUS_CANCLE = 2 // 订单取消
|
||||
ORDER_STATUS_SHIP = 3 // 订单已发货
|
||||
)
|
||||
18
src/server/base/skeleton.go
Normal file
18
src/server/base/skeleton.go
Normal file
@ -0,0 +1,18 @@
|
||||
package base
|
||||
|
||||
import (
|
||||
"server/conf"
|
||||
"server/pkg/github.com/name5566/leaf/chanrpc"
|
||||
"server/pkg/github.com/name5566/leaf/module"
|
||||
)
|
||||
|
||||
func NewSkeleton() *module.Skeleton {
|
||||
skeleton := &module.Skeleton{
|
||||
GoLen: conf.GoLen,
|
||||
TimerDispatcherLen: conf.TimerDispatcherLen,
|
||||
AsynCallLen: conf.AsynCallLen,
|
||||
ChanRPCServer: chanrpc.NewServer(conf.ChanRPCLen),
|
||||
}
|
||||
skeleton.Init()
|
||||
return skeleton
|
||||
}
|
||||
111
src/server/cluster/Cluster.go
Normal file
111
src/server/cluster/Cluster.go
Normal file
@ -0,0 +1,111 @@
|
||||
package mergeCluster
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"server/GoUtil"
|
||||
"server/conf"
|
||||
"server/game/mod/msg"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"server/pkg/github.com/name5566/leaf/network"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
ClusterCenterId = 0 // 集群中心
|
||||
)
|
||||
|
||||
var FuncMap = map[int]func(*Agent, *msg.Msg) error{} // 消息处理函数
|
||||
|
||||
var (
|
||||
server *network.TCPServer // 服务器
|
||||
Center *network.TCPClient // 集群中心
|
||||
clients []*network.TCPClient // 集群客户端
|
||||
MsgChan = make(chan *msg.Msg, 1000) // 消息队列
|
||||
serverAgent sync.Map // 服务器Agent
|
||||
)
|
||||
|
||||
func Init() {
|
||||
if conf.Server.ListenAddr != "" {
|
||||
server = new(network.TCPServer)
|
||||
server.Addr = conf.Server.ListenAddr
|
||||
server.MaxConnNum = int(math.MaxInt32)
|
||||
server.PendingWriteNum = conf.PendingWriteNum
|
||||
server.LenMsgLen = 4
|
||||
server.MaxMsgLen = 4096
|
||||
server.NewAgent = newServerAgent
|
||||
server.Start()
|
||||
}
|
||||
|
||||
if conf.Server.CenterAddr != "" {
|
||||
connectRemote(conf.Server.CenterAddr, ClusterCenterId, "center")
|
||||
}
|
||||
|
||||
registerFunc(msg.CLUSTER_HANDSHAKE_1, HandShakeRecv)
|
||||
registerFunc(msg.CLUSTER_HANDSHAKE_2, HandShakeRecv2)
|
||||
registerFunc(msg.CLUSTER_JOIN, ClusterJoin)
|
||||
registerFunc(msg.CLUSTER_EXIT, ClusterExit)
|
||||
}
|
||||
|
||||
func Destroy() {
|
||||
if server != nil {
|
||||
log.Release("closing cluster server")
|
||||
server.Close()
|
||||
}
|
||||
|
||||
for _, client := range clients {
|
||||
client.Close()
|
||||
}
|
||||
}
|
||||
|
||||
type Agent struct {
|
||||
conn *network.TCPConn
|
||||
ServerId int
|
||||
Type int
|
||||
}
|
||||
|
||||
func newAgent(conn *network.TCPConn) network.Agent {
|
||||
a := new(Agent)
|
||||
a.conn = conn
|
||||
return a
|
||||
}
|
||||
|
||||
func newServerAgent(conn *network.TCPConn) network.Agent {
|
||||
a := new(Agent)
|
||||
a.conn = conn
|
||||
a.Type = 1
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *Agent) Run() {
|
||||
HandShake(a)
|
||||
for {
|
||||
data, err := a.conn.ReadMsg()
|
||||
if err != nil {
|
||||
log.Debug("read message error: %v", err)
|
||||
break
|
||||
}
|
||||
m := msg.Msg{}
|
||||
err = GoUtil.GobUnmarshal(data, &m)
|
||||
if err != nil {
|
||||
log.Debug("decode err: %v", err)
|
||||
return
|
||||
}
|
||||
err = processMsg(a, &m)
|
||||
if err != nil {
|
||||
log.Debug("ProcessMsg err: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Agent) WriteMsg(data interface{}) {
|
||||
err := a.conn.WriteMsg(data.([]byte))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Agent) OnClose() {
|
||||
log.Debug("server %d close", a.ServerId)
|
||||
serverAgent.Delete(a.ServerId)
|
||||
}
|
||||
155
src/server/cluster/ClusterFunc.go
Normal file
155
src/server/cluster/ClusterFunc.go
Normal file
@ -0,0 +1,155 @@
|
||||
package mergeCluster
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"server/GoUtil"
|
||||
"server/conf"
|
||||
"server/game/mod/msg"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"server/pkg/github.com/name5566/leaf/network"
|
||||
"time"
|
||||
)
|
||||
|
||||
func RevcServerMsg(m *msg.Msg) error {
|
||||
log.Debug("RevcServerMsg m %v", m)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 连接成功 之后同步区服信息
|
||||
func HandShake(a *Agent) {
|
||||
m := &msg.Msg{
|
||||
Type: msg.CLUSTER_HANDSHAKE_1,
|
||||
From: conf.Server.ServerID,
|
||||
Extra: conf.Server.RemoteAddr,
|
||||
}
|
||||
data, err := GoUtil.GobMarshal(m)
|
||||
if err != nil {
|
||||
log.Debug("HandShake GobMarshal err %v", err)
|
||||
return
|
||||
}
|
||||
log.Debug("握手 server id :%d", conf.Server.ServerID)
|
||||
a.WriteMsg(data)
|
||||
}
|
||||
|
||||
// 握手回调
|
||||
func HandShakeRecv(a *Agent, m *msg.Msg) error {
|
||||
ServerId := m.From
|
||||
log.Debug("收到握手回复 ServerId %v", ServerId)
|
||||
a.ServerId = ServerId
|
||||
serverAgent.Store(ServerId, a)
|
||||
|
||||
if conf.Server.ServerID == ClusterCenterId {
|
||||
log.Debug("通知区服:%d加入网路", m.From)
|
||||
SendMsgAll(&msg.Msg{
|
||||
Type: msg.CLUSTER_JOIN,
|
||||
From: conf.Server.ServerID,
|
||||
Extra: &ClusterJoinData{
|
||||
ServerId: m.From,
|
||||
RemoteAddr: m.Extra.(string),
|
||||
},
|
||||
})
|
||||
}
|
||||
syncMsg := &msg.Msg{
|
||||
Type: msg.CLUSTER_FRIEND_SYNC,
|
||||
To: ServerId,
|
||||
}
|
||||
sendGameMsg(syncMsg)
|
||||
fmt.Print("现有区服连接:")
|
||||
serverAgent.Range(func(key, value interface{}) bool {
|
||||
fmt.Print(key)
|
||||
fmt.Print(",")
|
||||
return true
|
||||
})
|
||||
fmt.Println()
|
||||
return nil
|
||||
}
|
||||
|
||||
func HandShakeRecv2(a *Agent, m *msg.Msg) error {
|
||||
ServerId := m.From
|
||||
a.ServerId = ServerId
|
||||
log.Debug("HandShakeRecv2 ServerId %v", ServerId)
|
||||
serverAgent.Store(ServerId, a)
|
||||
return nil
|
||||
}
|
||||
|
||||
func ClusterJoin(a *Agent, m *msg.Msg) error {
|
||||
clusterJoin := m.Extra.(*ClusterJoinData)
|
||||
if conf.Server.ServerID == clusterJoin.ServerId {
|
||||
log.Debug("区服加入通知为本服, 不处理")
|
||||
return nil
|
||||
}
|
||||
log.Debug("ClusterJoin ServerId %v", clusterJoin.ServerId)
|
||||
connectRemote(clusterJoin.RemoteAddr, clusterJoin.ServerId, "server")
|
||||
return nil
|
||||
}
|
||||
|
||||
func ClusterExit(a *Agent, m *msg.Msg) error {
|
||||
clusterExit := m.Extra.(*ClusterExitData)
|
||||
if conf.Server.ServerID == clusterExit.ServerId {
|
||||
return nil
|
||||
}
|
||||
serverAgent.Delete(clusterExit.ServerId)
|
||||
return nil
|
||||
}
|
||||
|
||||
func connectRemote(RemoteAddr string, ConnType int, ConnLabel string) error {
|
||||
client := new(network.TCPClient)
|
||||
client.Addr = RemoteAddr
|
||||
client.ConnNum = 1
|
||||
client.PendingWriteNum = conf.PendingWriteNum
|
||||
client.LenMsgLen = 4
|
||||
client.MaxMsgLen = 4096
|
||||
client.NewAgent = newAgent
|
||||
client.ConnType = ConnType
|
||||
client.ConnLabel = ConnLabel
|
||||
client.ConnectInterval = time.Duration(time.Minute * 5)
|
||||
if ConnType == ClusterCenterId { // 中心服断开重连
|
||||
client.AutoReconnect = true
|
||||
}
|
||||
client.Start()
|
||||
Center = client
|
||||
clients = append(clients, client)
|
||||
return nil
|
||||
}
|
||||
|
||||
func SendServerMsg(m *msg.Msg, serverId int) error {
|
||||
if v, ok := serverAgent.Load(serverId); ok {
|
||||
data, err := GoUtil.GobMarshal(m)
|
||||
if err != nil {
|
||||
log.Debug("SendServerMsg GobMarshal err %v", err)
|
||||
return err
|
||||
}
|
||||
v.(network.Agent).WriteMsg(data)
|
||||
}
|
||||
return fmt.Errorf("server %d not online", serverId)
|
||||
}
|
||||
|
||||
func SendMsgAll(m *msg.Msg) {
|
||||
data, err := GoUtil.GobMarshal(m)
|
||||
if err != nil {
|
||||
log.Debug("SendMsgAll GobMarshal err %v", err)
|
||||
return
|
||||
}
|
||||
serverAgent.Range(func(key, value interface{}) bool {
|
||||
value.(network.Agent).WriteMsg(data)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func processMsg(a *Agent, m *msg.Msg) error {
|
||||
var err error
|
||||
if fun, ok := FuncMap[m.Type]; ok {
|
||||
err = fun(a, m)
|
||||
} else {
|
||||
MsgChan <- m //交由game Module消息处理
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func registerFunc(key int, fun func(*Agent, *msg.Msg) error) {
|
||||
FuncMap[key] = fun
|
||||
}
|
||||
|
||||
func sendGameMsg(m *msg.Msg) {
|
||||
MsgChan <- m
|
||||
}
|
||||
20
src/server/cluster/Type.go
Normal file
20
src/server/cluster/Type.go
Normal file
@ -0,0 +1,20 @@
|
||||
package mergeCluster
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"server/game/mod/msg"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gob.Register(&msg.Msg{})
|
||||
gob.Register(&ClusterJoinData{})
|
||||
}
|
||||
|
||||
type ClusterJoinData struct {
|
||||
ServerId int
|
||||
RemoteAddr string
|
||||
}
|
||||
|
||||
type ClusterExitData struct {
|
||||
ServerId int
|
||||
}
|
||||
41
src/server/conf/StartOrder/StartOrderCfg.go
Normal file
41
src/server/conf/StartOrder/StartOrderCfg.go
Normal file
@ -0,0 +1,41 @@
|
||||
package startOrderCfg
|
||||
|
||||
import (
|
||||
"server/gamedata"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type StartOrderCfg struct {
|
||||
}
|
||||
|
||||
var CFG_NAME = "StartOrder"
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(CFG_NAME)
|
||||
}
|
||||
|
||||
// 根据step 获取初始订单
|
||||
func GetStartOrderByStep(id int) []*gamedata.StartOrderData {
|
||||
ret := make([]*gamedata.StartOrderData, 0)
|
||||
data, err := gamedata.GetData(CFG_NAME)
|
||||
if err != nil {
|
||||
return ret
|
||||
}
|
||||
for k, v := range data {
|
||||
record := v.(map[string]interface{})
|
||||
stepVal := gamedata.ParseInt(record["step"])
|
||||
var MergeList []int
|
||||
for _, vv := range record["merge_id_list"].([]interface{}) {
|
||||
MergeList = append(MergeList, gamedata.ParseInt(vv))
|
||||
}
|
||||
if int(stepVal) == id {
|
||||
OrderId, _ := strconv.Atoi(k)
|
||||
ret = append(ret, &gamedata.StartOrderData{
|
||||
Id: OrderId,
|
||||
Step: int(stepVal),
|
||||
MergeList: MergeList,
|
||||
})
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
46
src/server/conf/activity/ActivityCfg.go
Normal file
46
src/server/conf/activity/ActivityCfg.go
Normal file
@ -0,0 +1,46 @@
|
||||
package activityCfg
|
||||
|
||||
import (
|
||||
"server/GoUtil"
|
||||
"server/gamedata"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
CFG_ACTIVITY = "Activity"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(CFG_ACTIVITY)
|
||||
}
|
||||
|
||||
func GetActivityList() []*gamedata.ActivityData {
|
||||
data, err := gamedata.GetData(CFG_ACTIVITY)
|
||||
if err != nil {
|
||||
log.Debug("GetActivityList err:%v", err)
|
||||
}
|
||||
Now := GoUtil.Now()
|
||||
var List []*gamedata.ActivityData
|
||||
|
||||
for k, v := range data {
|
||||
StartTimeStr := gamedata.GetStringValue(v, "StartTime")
|
||||
EndTimeStr := gamedata.GetStringValue(v, "EndTime")
|
||||
StartTime := GoUtil.ParseTime(StartTimeStr)
|
||||
EndTime := GoUtil.ParseTime(EndTimeStr)
|
||||
if Now >= StartTime && Now <= EndTime {
|
||||
Id, _ := strconv.Atoi(k)
|
||||
Type := gamedata.GetIntValue(v, "Type")
|
||||
Name := gamedata.GetStringValue(v, "Name")
|
||||
Title := gamedata.GetStringValue(v, "Title")
|
||||
ActivityData := &gamedata.ActivityData{
|
||||
Id: Id,
|
||||
Type: Type,
|
||||
Name: Name,
|
||||
Title: Title,
|
||||
}
|
||||
List = append(List, ActivityData)
|
||||
}
|
||||
}
|
||||
return List
|
||||
}
|
||||
42
src/server/conf/avatar/AvatarCfg.go
Normal file
42
src/server/conf/avatar/AvatarCfg.go
Normal file
@ -0,0 +1,42 @@
|
||||
package avatarCfg
|
||||
|
||||
import (
|
||||
"server/gamedata"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
CFG_AVATAR = "Avatar"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(CFG_AVATAR)
|
||||
}
|
||||
|
||||
func GetInitList() []int {
|
||||
data, err := gamedata.GetData(CFG_AVATAR)
|
||||
if err != nil {
|
||||
log.Debug("GetInitList err: %v", err)
|
||||
return nil
|
||||
}
|
||||
r := make([]int, 0)
|
||||
for k, v := range data {
|
||||
IsInit := gamedata.GetIntValue(v, "Init")
|
||||
if IsInit == 1 {
|
||||
k, _ := strconv.Atoi(k)
|
||||
r = append(r, k)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func CheckExist(Id int) bool {
|
||||
data, err := gamedata.GetData(CFG_AVATAR)
|
||||
if err != nil {
|
||||
log.Debug("CheckExist err: %v", err)
|
||||
return false
|
||||
}
|
||||
_, ok := data[strconv.Itoa(Id)]
|
||||
return ok
|
||||
}
|
||||
39
src/server/conf/base/BaseCfg.go
Normal file
39
src/server/conf/base/BaseCfg.go
Normal file
@ -0,0 +1,39 @@
|
||||
package baseCfg
|
||||
|
||||
import (
|
||||
"server/gamedata"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
CFG_BASE = "Base"
|
||||
)
|
||||
|
||||
const (
|
||||
ENERGY_SHOP_MUL = "energy_shop_mul"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(CFG_BASE)
|
||||
}
|
||||
|
||||
func GetEnergyByMul(T int) float64 {
|
||||
data, err := gamedata.GetDataByKey(CFG_BASE, ENERGY_SHOP_MUL)
|
||||
if err != nil {
|
||||
log.Debug("GetEnergyByMul err:%v", err)
|
||||
return 0
|
||||
}
|
||||
d := data["Value"].(map[string]interface{})
|
||||
if len(d) == 0 {
|
||||
return 0
|
||||
}
|
||||
T = min(T, len(d))
|
||||
T1 := strconv.Itoa(T)
|
||||
if v, ok := d[T1]; ok {
|
||||
return v.(float64)
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
|
||||
}
|
||||
179
src/server/conf/card/CardCfg.go
Normal file
179
src/server/conf/card/CardCfg.go
Normal file
@ -0,0 +1,179 @@
|
||||
package cardCfg
|
||||
|
||||
import (
|
||||
"server/GoUtil"
|
||||
"server/game/mod/item"
|
||||
"server/gamedata"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
CARD_CONST_CFG_NAME = "CardConst"
|
||||
CARD_DETAIL_CFG_NAME = "CardDetail"
|
||||
CARD_PACK_CFG_NAME = "CardPack"
|
||||
CARD_COLLECT_CFG_NAME = "CardCollect"
|
||||
CARD_EXCHANGE_CFG = "CardExchange"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(CARD_CONST_CFG_NAME)
|
||||
gamedata.InitCfg(CARD_DETAIL_CFG_NAME)
|
||||
gamedata.InitCfg(CARD_PACK_CFG_NAME)
|
||||
gamedata.InitCfg(CARD_COLLECT_CFG_NAME)
|
||||
gamedata.InitCfg(CARD_EXCHANGE_CFG)
|
||||
}
|
||||
|
||||
func GetAllCollectReward() []*item.Item {
|
||||
data, err := gamedata.GetDataByKey(CARD_CONST_CFG_NAME, "all_collect_reward")
|
||||
if err != nil {
|
||||
log.Debug("GetAllCollectReward data not found")
|
||||
}
|
||||
return item.ParseItem(data["Value"])
|
||||
}
|
||||
func GetStarById(Id int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CARD_DETAIL_CFG_NAME, Id)
|
||||
if err != nil {
|
||||
log.Debug("GetStarById data not found")
|
||||
}
|
||||
return gamedata.GetIntValue(data, "Star")
|
||||
}
|
||||
|
||||
// 获取开启卡包获得的卡牌数量
|
||||
func GetPackRewardCnt(Star int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CARD_PACK_CFG_NAME, Star)
|
||||
|
||||
if err != nil {
|
||||
log.Debug("GetPackRewardCnt data not found")
|
||||
}
|
||||
|
||||
return gamedata.GetIntValue(data, "RewardCnt")
|
||||
}
|
||||
|
||||
// 获取开启开包比得x星卡
|
||||
func GetPackMustHave(Star int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CARD_PACK_CFG_NAME, Star)
|
||||
if err != nil {
|
||||
log.Debug("GetPackMustHave data not found")
|
||||
}
|
||||
|
||||
return gamedata.GetIntValue(data, "MustHave")
|
||||
}
|
||||
|
||||
// 根据星级获取卡牌列表
|
||||
func GetCardListByStar(Star, IsGold int) []int {
|
||||
var CardList []int
|
||||
data, err := gamedata.GetData(CARD_DETAIL_CFG_NAME)
|
||||
if err != nil {
|
||||
log.Debug("GetCardListByStar data not found")
|
||||
}
|
||||
for k, v := range data {
|
||||
vStar := gamedata.GetIntValue(v, "Star")
|
||||
isGold := gamedata.GetIntValue(v, "IsGold")
|
||||
if vStar == Star && IsGold == isGold {
|
||||
id, _ := strconv.Atoi(k)
|
||||
CardList = append(CardList, id)
|
||||
}
|
||||
}
|
||||
return CardList
|
||||
}
|
||||
|
||||
// 获取随机卡牌
|
||||
func GetRandListByStar(Star int) []int {
|
||||
var randList []int
|
||||
data, err := gamedata.GetDataByIntKey(CARD_PACK_CFG_NAME, Star)
|
||||
if err != nil {
|
||||
log.Debug("GetRandListByStar data not found")
|
||||
}
|
||||
r1 := gamedata.GetStringValue(data, "RandRate")
|
||||
r2 := strings.Split(r1, ",")
|
||||
randList = GoUtil.SliceStringToInt(r2)
|
||||
return randList
|
||||
}
|
||||
|
||||
// 获取卡牌收集奖励
|
||||
func GetCollectReward(Color int) ([]*item.Item, int) {
|
||||
data, err := gamedata.GetDataByIntKey(CARD_COLLECT_CFG_NAME, Color)
|
||||
if err != nil {
|
||||
log.Debug("GetCollectReward data not found")
|
||||
return nil, 0
|
||||
}
|
||||
itemCfg := gamedata.GetValue(data, "Item")
|
||||
Chess := gamedata.GetIntValue(data, "Chess")
|
||||
itemList := item.ParseItem(itemCfg)
|
||||
return itemList, Chess
|
||||
}
|
||||
|
||||
// 获取兑换奖励
|
||||
func GetExchangeCfg(Id int) (int, []*item.Item, []int) {
|
||||
data, err := gamedata.GetDataByIntKey(CARD_EXCHANGE_CFG, Id)
|
||||
if err != nil {
|
||||
log.Debug("GetExchangeCfg data not found")
|
||||
return 0, nil, nil
|
||||
}
|
||||
itemNum := gamedata.GetIntValue(data, "Item")
|
||||
itemList := []*item.Item{item.NewItem(item.ITEM_ENERGY_ID, itemNum)}
|
||||
CostStar := gamedata.GetIntValue(data, "CostStar")
|
||||
CardPackStr := gamedata.GetStringValue(data, "CardPack")
|
||||
s1 := CardPackStr[1 : len(CardPackStr)-1]
|
||||
CardPack := GoUtil.SliceStringToInt(strings.Split(s1, ","))
|
||||
return CostStar, itemList, CardPack
|
||||
}
|
||||
|
||||
// 根据系列获取卡牌列表
|
||||
func GetCardListByColor(Id int) []int {
|
||||
data, err := gamedata.GetData(CARD_DETAIL_CFG_NAME)
|
||||
if err != nil {
|
||||
log.Debug("GetCardListByColor data not found")
|
||||
return []int{}
|
||||
}
|
||||
var r []int
|
||||
for k, v := range data {
|
||||
color := gamedata.GetIntValue(v, "PictureAlbum")
|
||||
if color == Id {
|
||||
k1, _ := strconv.Atoi(k)
|
||||
r = append(r, k1)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// 获取所有卡牌id
|
||||
func GetAllCardId() []int {
|
||||
data, err := gamedata.GetData(CARD_DETAIL_CFG_NAME)
|
||||
if err != nil {
|
||||
log.Debug("GetCardListByColor data not found")
|
||||
return []int{}
|
||||
}
|
||||
var r []int
|
||||
for k := range data {
|
||||
k1, _ := strconv.Atoi(k)
|
||||
r = append(r, k1)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func GetCardDuration() int64 {
|
||||
data, err := gamedata.GetDataByKey(CARD_CONST_CFG_NAME, "duration")
|
||||
if err != nil {
|
||||
log.Debug("GetCardDuration data not found")
|
||||
}
|
||||
return int64(gamedata.GetIntValue(data, "Value"))
|
||||
}
|
||||
|
||||
func GetExTimes() int {
|
||||
data, err := gamedata.GetDataByKey(CARD_CONST_CFG_NAME, "exchange_times")
|
||||
if err != nil {
|
||||
log.Debug("GetExTimes data not found")
|
||||
}
|
||||
return gamedata.GetIntValue(data, "Value")
|
||||
}
|
||||
|
||||
func GetReqTimes() int {
|
||||
data, err := gamedata.GetDataByKey(CARD_CONST_CFG_NAME, "request_times")
|
||||
if err != nil {
|
||||
log.Debug("GetReqTimes data not found")
|
||||
}
|
||||
return gamedata.GetIntValue(data, "Value")
|
||||
}
|
||||
47
src/server/conf/champship/ChampshipCfg.go
Normal file
47
src/server/conf/champship/ChampshipCfg.go
Normal file
@ -0,0 +1,47 @@
|
||||
package champshipCfg
|
||||
|
||||
import (
|
||||
"server/GoUtil"
|
||||
"server/game/mod/item"
|
||||
"server/gamedata"
|
||||
)
|
||||
|
||||
const (
|
||||
CFG_CHAMPSHIP_SCORE = "ChampshipScore"
|
||||
CFG_CHAMPSHIP_RANK = "ChampshipRank"
|
||||
CFG_CHAMPSHIP_JACKPOT = "ChampshipJackpot"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(CFG_CHAMPSHIP_SCORE)
|
||||
gamedata.InitCfg(CFG_CHAMPSHIP_RANK)
|
||||
gamedata.InitCfg(CFG_CHAMPSHIP_JACKPOT)
|
||||
}
|
||||
|
||||
func GetChessScore(ChessLv int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_CHAMPSHIP_SCORE, ChessLv)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetIntValue(data, "Score")
|
||||
}
|
||||
|
||||
func GetReward(Reward, Score int) (int, []*item.Item) {
|
||||
data, err := gamedata.GetData(CFG_CHAMPSHIP_JACKPOT)
|
||||
if err != nil {
|
||||
return Reward, nil
|
||||
}
|
||||
r := make([]*item.Item, 0)
|
||||
for k, v := range data {
|
||||
Id := GoUtil.Int(k)
|
||||
if Reward >= Id {
|
||||
continue
|
||||
}
|
||||
Reward = max(Reward, Id)
|
||||
if Score >= gamedata.GetIntValue(v, "Score") {
|
||||
Items := item.ParseItem(gamedata.GetStringValue(v, "Items"))
|
||||
r = item.Merge(r, Items)
|
||||
}
|
||||
}
|
||||
return Reward, r
|
||||
}
|
||||
253
src/server/conf/charge/ChargeCfg.go
Normal file
253
src/server/conf/charge/ChargeCfg.go
Normal file
@ -0,0 +1,253 @@
|
||||
package chargeCfg
|
||||
|
||||
import (
|
||||
"server/GoUtil"
|
||||
"server/game/mod/item"
|
||||
"server/gamedata"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
CFG_CHARGE = "Charge"
|
||||
CFG_DIAMOND_SHOP = "DiamondShop"
|
||||
CFG_ENERGY_SHOP = "EnergyShop"
|
||||
CFG_SEPCIAL_SHOP = "SpecialShop"
|
||||
CFG_FREE_SHOP = "FreeShop"
|
||||
CFG_CHARGE_CONST = "ChargeConst"
|
||||
CFG_CHARGE_GIFT = "ChargeGift"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(CFG_CHARGE)
|
||||
gamedata.InitCfg(CFG_DIAMOND_SHOP)
|
||||
gamedata.InitCfg(CFG_ENERGY_SHOP)
|
||||
gamedata.InitCfg(CFG_SEPCIAL_SHOP)
|
||||
gamedata.InitCfg(CFG_FREE_SHOP)
|
||||
gamedata.InitCfg(CFG_CHARGE_CONST)
|
||||
gamedata.InitCfg(CFG_CHARGE_GIFT)
|
||||
}
|
||||
|
||||
func GetMoneyCharge(ChargeId int) float64 {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_CHARGE, ChargeId)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetFloatValue(data, "Money")
|
||||
}
|
||||
|
||||
func GetDiamondShopReward(ChargeId int) []*item.Item {
|
||||
data, err := gamedata.GetData(CFG_DIAMOND_SHOP)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
for _, v := range data {
|
||||
if gamedata.GetIntValue(v, "ChargeId") == ChargeId {
|
||||
return []*item.Item{item.NewItem(item.ITEM_DIAMOND_ID, gamedata.GetIntValue(v, "Diamond"))}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetEnergyShopId(ChargeId int) int {
|
||||
data, err := gamedata.GetData(CFG_ENERGY_SHOP)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
for k, v := range data {
|
||||
if gamedata.GetIntValue(v, "ChargeId") == ChargeId {
|
||||
return GoUtil.Int(k)
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetEnergyShopReward(ChargeId int, First bool) []*item.Item {
|
||||
data, err := gamedata.GetData(CFG_ENERGY_SHOP)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
for _, v := range data {
|
||||
if gamedata.GetIntValue(v, "ChargeId") == ChargeId {
|
||||
Energy := gamedata.GetIntValue(v, "Energy")
|
||||
if !First {
|
||||
Energy += gamedata.GetIntValue(v, "FirstCharge")
|
||||
}
|
||||
return []*item.Item{item.NewItem(item.ITEM_ENERGY_ID, Energy)}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetSpecialShopReward(ChargeId int) []*item.Item {
|
||||
data, err := gamedata.GetData(CFG_SEPCIAL_SHOP)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
for _, v := range data {
|
||||
if gamedata.GetIntValue(v, "ChargeId") == ChargeId {
|
||||
return item.ParseItem(gamedata.GetValue(v, "Items"))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetSpecialShopType(ChargeId int) int {
|
||||
data, err := gamedata.GetData(CFG_SEPCIAL_SHOP)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
for _, v := range data {
|
||||
if gamedata.GetIntValue(v, "ChargeId") == ChargeId {
|
||||
return gamedata.GetIntValue(v, "Type")
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetFreeShopReward(ChargeId int) []*item.Item {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_FREE_SHOP, ChargeId)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
Item := gamedata.GetValue(data, "Items")
|
||||
return item.ParseItem(Item)
|
||||
}
|
||||
|
||||
func GetSpecialShopGrade(Money float64, Type int) int {
|
||||
type grade struct {
|
||||
id int
|
||||
money float64
|
||||
}
|
||||
data, err := gamedata.GetData(CFG_SEPCIAL_SHOP)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
l := make([]grade, 0)
|
||||
for _, v := range data {
|
||||
if gamedata.GetIntValue(v, "Type") != Type {
|
||||
continue
|
||||
}
|
||||
l = append(l, grade{
|
||||
id: gamedata.GetIntValue(v, "Grade"),
|
||||
money: GetMoneyCharge(gamedata.GetIntValue(v, "ChargeId")),
|
||||
})
|
||||
}
|
||||
sort.Slice(l, func(i, j int) bool {
|
||||
return l[i].money < l[j].money
|
||||
})
|
||||
|
||||
for _, v := range l {
|
||||
if Money < v.money {
|
||||
return v.id
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetUnlockShopLv() int {
|
||||
data, err := gamedata.GetDataByKey(CFG_CHARGE_CONST, "shop_unlock_lv")
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetIntValue(data, "Value")
|
||||
}
|
||||
|
||||
func GetSpecialShopCount() int {
|
||||
data, err := gamedata.GetDataByKey(CFG_CHARGE_CONST, "special_shop_count")
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetIntValue(data, "Value")
|
||||
}
|
||||
|
||||
func GetAdChargeId() int {
|
||||
data, err := gamedata.GetDataByKey(CFG_CHARGE_CONST, "ad_charge_id")
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetIntValue(data, "Value")
|
||||
}
|
||||
|
||||
func GetPiggyDuration() int {
|
||||
data, err := gamedata.GetDataByKey(CFG_CHARGE_CONST, "pig_duration")
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetIntValue(data, "Value")
|
||||
}
|
||||
|
||||
func GetPiggyMaxDia() int {
|
||||
data, err := gamedata.GetDataByKey(CFG_CHARGE_CONST, "pig_max_diamond")
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetIntValue(data, "Value")
|
||||
}
|
||||
|
||||
func GetPiggyRandDia() (int, int) {
|
||||
data, err := gamedata.GetDataByKey(CFG_CHARGE_CONST, "pig_diamond_rand")
|
||||
if err != nil {
|
||||
return 0, 0
|
||||
}
|
||||
str := gamedata.GetStringValue(data, "Value")
|
||||
strArr := strings.Split(str, ",")
|
||||
if len(strArr) != 2 {
|
||||
return 0, 0
|
||||
}
|
||||
return GoUtil.Int(strArr[0]), GoUtil.Int(strArr[1])
|
||||
}
|
||||
|
||||
func GetPiggyBankChargeId() int {
|
||||
data, err := gamedata.GetDataByKey(CFG_CHARGE_CONST, "pig_charge_id")
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetIntValue(data, "Value")
|
||||
}
|
||||
|
||||
func GetGiftReward(ChargeId int) []*item.Item {
|
||||
data, err := gamedata.GetData(CFG_CHARGE_GIFT)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
for _, v := range data {
|
||||
if gamedata.GetIntValue(v, "ChargeId") == ChargeId {
|
||||
return item.ParseItem(gamedata.GetValue(v, "Items"))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetGiftLimit(ChargeId int) int {
|
||||
data, err := gamedata.GetData(CFG_CHARGE_GIFT)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
for _, v := range data {
|
||||
if gamedata.GetIntValue(v, "ChargeId") == ChargeId {
|
||||
return gamedata.GetIntValue(v, "Count")
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func GetGiftId(ChargeId int) int {
|
||||
data, err := gamedata.GetData(CFG_CHARGE_GIFT)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
for k, v := range data {
|
||||
if gamedata.GetIntValue(v, "ChargeId") == ChargeId {
|
||||
return GoUtil.Int(k)
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetChargeInfo(ChargeId int) (float64, string) {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_CHARGE, ChargeId)
|
||||
if err != nil {
|
||||
return 0, ""
|
||||
}
|
||||
return gamedata.GetFloatValue(data, "Money"), gamedata.GetStringValue(data, "Unit")
|
||||
}
|
||||
24
src/server/conf/conf.go
Normal file
24
src/server/conf/conf.go
Normal file
@ -0,0 +1,24 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// log conf
|
||||
LogFlag = log.LstdFlags
|
||||
|
||||
// gate conf
|
||||
PendingWriteNum = 2000
|
||||
MaxMsgLen uint32 = 16384 // 16KB
|
||||
HTTPTimeout = 10 * time.Second
|
||||
LenMsgLen = 2
|
||||
LittleEndian = false
|
||||
|
||||
// skeleton conf
|
||||
GoLen = 10000
|
||||
TimerDispatcherLen = 10000
|
||||
AsynCallLen = 10000
|
||||
ChanRPCLen = 10000
|
||||
)
|
||||
89
src/server/conf/dailyTask/DailyTaskCfg.go
Normal file
89
src/server/conf/dailyTask/DailyTaskCfg.go
Normal file
@ -0,0 +1,89 @@
|
||||
package dailyTaskCfg
|
||||
|
||||
import (
|
||||
"server/game/mod/item"
|
||||
"server/gamedata"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
DAILY_TASK_CONST = "DailyTaskConst"
|
||||
DAILY_TASK = "DailyTask"
|
||||
DAILY_TASK_ACTIVE = "DailyTaskActive"
|
||||
DAILY_TASK_JACKPOT = "DailyTaskJackpot"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(DAILY_TASK_CONST)
|
||||
gamedata.InitCfg(DAILY_TASK)
|
||||
gamedata.InitCfg(DAILY_TASK_ACTIVE)
|
||||
gamedata.InitCfg(DAILY_TASK_JACKPOT)
|
||||
}
|
||||
|
||||
// 获取任务列表
|
||||
func GetTaskList(Lv int) map[int]string {
|
||||
r := make(map[int]string)
|
||||
data, err := gamedata.GetData(DAILY_TASK)
|
||||
if err != nil {
|
||||
log.Debug("GetTaskList get data nil")
|
||||
return r
|
||||
}
|
||||
for k, v := range data {
|
||||
lv := gamedata.GetIntValue(v, "Lv")
|
||||
if Lv >= lv {
|
||||
k1, _ := strconv.Atoi(k)
|
||||
r[k1] = gamedata.GetStringValue(v, "Task")
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func GetTaskActiveId() []int {
|
||||
data, err := gamedata.GetData(DAILY_TASK_ACTIVE)
|
||||
if err != nil {
|
||||
log.Debug("GetTaskActiveId get data nil")
|
||||
return []int{}
|
||||
}
|
||||
r := make([]int, 0, len(data))
|
||||
for k := range data {
|
||||
Id, _ := strconv.Atoi(k)
|
||||
r = append(r, Id)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func GetTaskActiveById(Id int) int {
|
||||
data, err := gamedata.GetDataByIntKey(DAILY_TASK_ACTIVE, Id)
|
||||
if err != nil {
|
||||
log.Debug("GetTaskActiveById get data nil")
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetIntValue(data, "Num")
|
||||
}
|
||||
|
||||
type Jackpot struct {
|
||||
Items []*item.Item
|
||||
Is_card int
|
||||
}
|
||||
|
||||
func GetTaskWeekJackpot() map[int]Jackpot {
|
||||
r := make(map[int]Jackpot)
|
||||
|
||||
data, err := gamedata.GetData(DAILY_TASK_JACKPOT)
|
||||
if err != nil {
|
||||
log.Debug("GetTaskWeekJackpot get data nil")
|
||||
return r
|
||||
}
|
||||
|
||||
for k, v := range data {
|
||||
Id, _ := strconv.Atoi(k)
|
||||
isCard := gamedata.GetIntValue(v, "CardPack")
|
||||
Item := item.ParseItem(gamedata.GetValue(v, "Items"))
|
||||
r[Id] = Jackpot{
|
||||
Items: Item,
|
||||
Is_card: isCard,
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
95
src/server/conf/decorate/DecorateCfg.go
Normal file
95
src/server/conf/decorate/DecorateCfg.go
Normal file
@ -0,0 +1,95 @@
|
||||
package decorateCfg
|
||||
|
||||
import (
|
||||
"server/game/mod/item"
|
||||
"server/gamedata"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
DECORATE_COST = "DecorateCost"
|
||||
INDOOR_PROGRESS = "IndoorProgress"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg("DecorateCost")
|
||||
gamedata.InitCfg("IndoorProgress")
|
||||
}
|
||||
|
||||
func GetStarCost(AreaId, SortId int) int {
|
||||
data, err := gamedata.GetData(DECORATE_COST)
|
||||
if err != nil {
|
||||
log.Debug("DecorateCost GetStarCost not found")
|
||||
return 0
|
||||
}
|
||||
for _, v := range data {
|
||||
v1 := v.(map[string]interface{})
|
||||
if gamedata.ParseInt(v1["AreaId"]) == AreaId && gamedata.ParseInt(v1["SortId"]) == SortId {
|
||||
return gamedata.ParseInt(v1["CostCount"])
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetAreaId(id int) int {
|
||||
value, err := gamedata.GetDataByIntKey("DecorateCost", id)
|
||||
if err != nil {
|
||||
log.Debug("DecorateCost GetAreaId id:%v not found", id)
|
||||
return 0
|
||||
}
|
||||
return gamedata.ParseInt(value["AreaId"])
|
||||
}
|
||||
|
||||
func GetNextAreaId(AreaId, SortId int) int {
|
||||
data, err := gamedata.GetData(DECORATE_COST)
|
||||
if err != nil {
|
||||
log.Debug("DecorateCost GetStarCost not found")
|
||||
return 0
|
||||
}
|
||||
for k, v := range data {
|
||||
v1 := v.(map[string]interface{})
|
||||
if gamedata.ParseInt(v1["AreaId"]) == AreaId && gamedata.ParseInt(v1["SortId"]) == SortId {
|
||||
UnionKey, _ := strconv.Atoi(k)
|
||||
nextId := UnionKey + 1
|
||||
AreaId = GetAreaId(nextId)
|
||||
return AreaId
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetAllSortIdByAreaId(AreaId int) []int {
|
||||
data, err := gamedata.GetData(DECORATE_COST)
|
||||
if err != nil {
|
||||
log.Debug("DecorateCost GetAllSortIdByAreaId not found")
|
||||
return nil
|
||||
}
|
||||
var SortIdList []int
|
||||
for _, v := range data {
|
||||
v1 := v.(map[string]interface{})
|
||||
if gamedata.ParseInt(v1["AreaId"]) == AreaId {
|
||||
Sort := gamedata.ParseInt(v1["SortId"])
|
||||
if Sort == 0 {
|
||||
continue
|
||||
}
|
||||
SortIdList = append(SortIdList, Sort)
|
||||
}
|
||||
}
|
||||
return SortIdList
|
||||
}
|
||||
|
||||
func GetProgressReward(Scene, Lv int) []*item.Item {
|
||||
value, err := gamedata.GetData("IndoorProgress")
|
||||
if err != nil {
|
||||
log.Debug("IndoorProgress GetProgressReward not found")
|
||||
return nil
|
||||
}
|
||||
for _, v := range value {
|
||||
v1 := v.(map[string]interface{})
|
||||
if gamedata.ParseInt(v1["Scene"]) == Scene && gamedata.ParseInt(v1["Lv"]) == Lv {
|
||||
return item.ParseItem(v1["Item"])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
108
src/server/conf/endless/EndlessCfg.go
Normal file
108
src/server/conf/endless/EndlessCfg.go
Normal file
@ -0,0 +1,108 @@
|
||||
package endlessCfg
|
||||
|
||||
import (
|
||||
"server/game/mod/item"
|
||||
"server/gamedata"
|
||||
)
|
||||
|
||||
const (
|
||||
CFG_ENDLESS = "Endless"
|
||||
CFG_ENDLESS_JACKPOT = "EndlessJackpot"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(CFG_ENDLESS)
|
||||
gamedata.InitCfg(CFG_ENDLESS_JACKPOT)
|
||||
}
|
||||
|
||||
func GetDiamond(Money float64) float64 {
|
||||
data, err := gamedata.GetData(CFG_ENDLESS)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
for _, v := range data {
|
||||
if Money == gamedata.GetFloatValue(v, "Money") {
|
||||
return gamedata.GetFloatValue(v, "Diamond")
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func NextMoney(Money float64) float64 {
|
||||
data, err := gamedata.GetData(CFG_ENDLESS)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
for _, v := range data {
|
||||
if Money == gamedata.GetFloatValue(v, "Money") {
|
||||
return gamedata.GetFloatValue(v, "NextMoney")
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetChargeId(Money float64) int {
|
||||
data, err := gamedata.GetData(CFG_ENDLESS)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
for _, v := range data {
|
||||
if Money == gamedata.GetFloatValue(v, "Money") {
|
||||
return gamedata.GetIntValue(v, "ChargeId")
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetPerDiamond(Id int) float64 {
|
||||
data, err := gamedata.GetData(CFG_ENDLESS_JACKPOT)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
for _, v := range data {
|
||||
if Id == gamedata.GetIntValue(v, "ItemId") {
|
||||
return gamedata.GetFloatValue(v, "Diamond")
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetItemId(Diamond float64, Type int) []int {
|
||||
data, err := gamedata.GetData(CFG_ENDLESS_JACKPOT)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
var ItemId []int
|
||||
for _, v := range data {
|
||||
if Diamond >= gamedata.GetFloatValue(v, "Diamond") && Type != gamedata.GetIntValue(v, "Type") && gamedata.GetIntValue(v, "ItemId") != item.ITEM_ENERGY_ID {
|
||||
ItemId = append(ItemId, gamedata.GetIntValue(v, "ItemId"))
|
||||
}
|
||||
}
|
||||
return ItemId
|
||||
}
|
||||
|
||||
func GetType(ItemId int) int {
|
||||
data, err := gamedata.GetData(CFG_ENDLESS_JACKPOT)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
for _, v := range data {
|
||||
if ItemId == gamedata.GetIntValue(v, "ItemId") {
|
||||
return gamedata.GetIntValue(v, "Type")
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func GeDiamondByItemId(ItemId int) float64 {
|
||||
data, err := gamedata.GetData(CFG_ENDLESS_JACKPOT)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
for _, v := range data {
|
||||
if ItemId == gamedata.GetIntValue(v, "ItemId") {
|
||||
return gamedata.GetFloatValue(v, "Diamond")
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
42
src/server/conf/face/FaceCfg.go
Normal file
42
src/server/conf/face/FaceCfg.go
Normal file
@ -0,0 +1,42 @@
|
||||
package faceCfg
|
||||
|
||||
import (
|
||||
"server/gamedata"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
CFG_FACE = "Face"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(CFG_FACE)
|
||||
}
|
||||
|
||||
func GetInitList() []int {
|
||||
data, err := gamedata.GetData(CFG_FACE)
|
||||
if err != nil {
|
||||
log.Debug("GetInitList err: %v", err)
|
||||
return nil
|
||||
}
|
||||
r := make([]int, 0)
|
||||
for k, v := range data {
|
||||
IsInit := gamedata.GetIntValue(v, "Init")
|
||||
if IsInit == 1 {
|
||||
k, _ := strconv.Atoi(k)
|
||||
r = append(r, k)
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func CheckExist(Id int) bool {
|
||||
data, err := gamedata.GetData(CFG_FACE)
|
||||
if err != nil {
|
||||
log.Debug("CheckExist err: %v", err)
|
||||
return false
|
||||
}
|
||||
_, ok := data[strconv.Itoa(Id)]
|
||||
return ok
|
||||
}
|
||||
24
src/server/conf/guild/GuildCfg.go
Normal file
24
src/server/conf/guild/GuildCfg.go
Normal file
@ -0,0 +1,24 @@
|
||||
package guildCfg
|
||||
|
||||
import (
|
||||
"server/game/mod/item"
|
||||
"server/gamedata"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
)
|
||||
|
||||
const (
|
||||
GUILD_REWARD = "GuildReward"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(GUILD_REWARD)
|
||||
}
|
||||
|
||||
func GetGuildReward(Id int) ([]*item.Item, int) {
|
||||
data, err := gamedata.GetDataByIntKey(GUILD_REWARD, Id)
|
||||
if err != nil {
|
||||
log.Debug("GuildCfg GetGuildReward Id:%v not found", Id)
|
||||
return nil, 0
|
||||
}
|
||||
return item.ParseItem(gamedata.GetValue(data, "Items")), gamedata.GetIntValue(data, "Num")
|
||||
}
|
||||
48
src/server/conf/item/ItemCfg.go
Normal file
48
src/server/conf/item/ItemCfg.go
Normal file
@ -0,0 +1,48 @@
|
||||
package itemCfg
|
||||
|
||||
import (
|
||||
"server/gamedata"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var CFG_NAME = "Item"
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(CFG_NAME)
|
||||
}
|
||||
|
||||
func GetItemType(Id int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, Id)
|
||||
if err != nil {
|
||||
log.Debug("ItemCfg GetItemType Id:%v not found", Id)
|
||||
return 0
|
||||
}
|
||||
return gamedata.ParseInt(data["IType"])
|
||||
}
|
||||
|
||||
func GetItemEffect(Id int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, Id)
|
||||
if err != nil {
|
||||
log.Debug("ItemCfg GetItemEffect Id:%v not found", Id)
|
||||
return 0
|
||||
}
|
||||
return gamedata.ParseInt(data["Effect"])
|
||||
}
|
||||
|
||||
func GetItemEffectList(Id int) []int {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, Id)
|
||||
if err != nil {
|
||||
log.Debug("ItemCfg GetItemEffect Id:%v not found", Id)
|
||||
return []int{}
|
||||
}
|
||||
var res []int
|
||||
str := gamedata.GetStringValue(data, "Effect")
|
||||
a := strings.Split(str, ",")
|
||||
for _, v := range a {
|
||||
b, _ := strconv.Atoi(v)
|
||||
res = append(res, b)
|
||||
}
|
||||
return res
|
||||
}
|
||||
61
src/server/conf/json.go
Normal file
61
src/server/conf/json.go
Normal file
@ -0,0 +1,61 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
)
|
||||
|
||||
var Server struct {
|
||||
LogLevel string
|
||||
LogPath string
|
||||
WSAddr string
|
||||
CertFile string
|
||||
KeyFile string
|
||||
TCPAddr string
|
||||
MaxConnNum int
|
||||
ConsolePort int
|
||||
ProfilePath string
|
||||
|
||||
MySqlAddr string
|
||||
MySqlUsr string
|
||||
MySqlPort string
|
||||
MySqlPwd string
|
||||
DbName string
|
||||
|
||||
RedisAddr string
|
||||
RedisPort string
|
||||
RedisPwd string
|
||||
|
||||
GameName string
|
||||
ServerType string
|
||||
|
||||
ServerID int
|
||||
HttpPort string
|
||||
ServerOpenTime string
|
||||
ServerName string
|
||||
|
||||
ListenAddr string
|
||||
CenterAddr string
|
||||
|
||||
RemoteAddr string
|
||||
}
|
||||
|
||||
func init() {
|
||||
// data, err := ioutil.ReadFile("conf/server.json")
|
||||
file, err := os.Open("conf/server.json")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
data, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
log.Fatal("%v", err)
|
||||
}
|
||||
err = json.Unmarshal(data, &Server)
|
||||
if err != nil {
|
||||
log.Fatal("%v", err)
|
||||
}
|
||||
}
|
||||
219
src/server/conf/limitedTimeEvent/LimitedTimeEventCfg.go
Normal file
219
src/server/conf/limitedTimeEvent/LimitedTimeEventCfg.go
Normal file
@ -0,0 +1,219 @@
|
||||
package limitedTimeEventCfg
|
||||
|
||||
import (
|
||||
"server/GoUtil"
|
||||
"server/game/mod/item"
|
||||
"server/gamedata"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
CFG_LIMITED_TIME_EVENT = "LimitedTimeEvent"
|
||||
CFG_LIMITED_TIME_EVENT_METEOR = "LimitedTimeEventMeteor"
|
||||
CFG_LIMITED_TIME_EVENT_CHEST = "LimitedTimeEventChest"
|
||||
CFG_LIMITED_TIME_EVENT_ORDER = "LimitedTimeEventOrder"
|
||||
CFG_LIMITED_TIME_EVENT_SENCE = "LimitedTimeEventSence"
|
||||
CFG_LIMITED_TIME_EVENT_SENCE_JACKPOT = "LimitedTimeEventSenceJackpot"
|
||||
CFG_LIMITED_TIME_EVENT_FAST = "LimitedTimeEventFast"
|
||||
CFG_LIMITED_TIME_EVENT_JACKPOT = "LimitedTimeEventJackpot"
|
||||
CFG_LIMITED_TIME_EVENT_CONST = "LimitedTimeEventConst"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(CFG_LIMITED_TIME_EVENT)
|
||||
gamedata.InitCfg(CFG_LIMITED_TIME_EVENT_METEOR)
|
||||
gamedata.InitCfg(CFG_LIMITED_TIME_EVENT_CHEST)
|
||||
gamedata.InitCfg(CFG_LIMITED_TIME_EVENT_ORDER)
|
||||
gamedata.InitCfg(CFG_LIMITED_TIME_EVENT_SENCE)
|
||||
gamedata.InitCfg(CFG_LIMITED_TIME_EVENT_SENCE_JACKPOT)
|
||||
gamedata.InitCfg(CFG_LIMITED_TIME_EVENT_FAST)
|
||||
gamedata.InitCfg(CFG_LIMITED_TIME_EVENT_JACKPOT)
|
||||
gamedata.InitCfg(CFG_LIMITED_TIME_EVENT_CONST)
|
||||
}
|
||||
|
||||
// 获取限时事件触发列表
|
||||
func GetLimitedTimeEventCfg() []*gamedata.LimitedTimeEventData {
|
||||
data, err := gamedata.GetData(CFG_LIMITED_TIME_EVENT)
|
||||
if err != nil {
|
||||
log.Debug("GetLimitedTimeEventCfg err:%v", err)
|
||||
return nil
|
||||
}
|
||||
var res []*gamedata.LimitedTimeEventData
|
||||
Day, Hour := GoUtil.GetWeekdayAndHour()
|
||||
for k, v := range data {
|
||||
weekDay := gamedata.GetIntValue(v, "WeekDay")
|
||||
startTime := gamedata.GetIntValue(v, "StartTime")
|
||||
endTime := gamedata.GetIntValue(v, "EndTime")
|
||||
if weekDay == Day && Hour >= startTime && Hour < endTime {
|
||||
Id, _ := strconv.Atoi(k)
|
||||
res = append(res, &gamedata.LimitedTimeEventData{
|
||||
Id: Id,
|
||||
EventId: gamedata.GetIntValue(v, "EventId"),
|
||||
Duration: int64(gamedata.GetIntValue(v, "Duration")),
|
||||
})
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// 获取流星雨加成
|
||||
func GetMeteorAdd(ChessLv int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_LIMITED_TIME_EVENT_METEOR, ChessLv)
|
||||
if err != nil {
|
||||
log.Debug("GetMeteorAdd err:%v", err)
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetIntValue(data, "Add")
|
||||
}
|
||||
|
||||
// 获取宝箱雨奖励
|
||||
func GetChestReward(Star int) []*item.Item {
|
||||
data, err := gamedata.GetData(CFG_LIMITED_TIME_EVENT_CHEST)
|
||||
if err != nil {
|
||||
log.Debug("GetChestReward err:%v", err)
|
||||
return nil
|
||||
}
|
||||
for _, v := range data {
|
||||
Min := gamedata.GetIntValue(v, "Min")
|
||||
Max := gamedata.GetIntValue(v, "Max")
|
||||
if Star >= Min && Star <= Max {
|
||||
return gamedata.GetItemList(v, "Items")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取超级订单奖励
|
||||
func GetSuperOrderReward(Star int) []*item.Item {
|
||||
data, err := gamedata.GetData(CFG_LIMITED_TIME_EVENT_ORDER)
|
||||
if err != nil {
|
||||
log.Debug("GetSuperOrderReward err:%v", err)
|
||||
return nil
|
||||
}
|
||||
for _, v := range data {
|
||||
Min := gamedata.GetIntValue(v, "Min")
|
||||
Max := gamedata.GetIntValue(v, "Max")
|
||||
if Star >= Min && Star <= Max {
|
||||
return gamedata.GetItemList(v, "Items")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取场景冲刺奖励
|
||||
func GetSceneDashReward(Sence, Progress int) (int, []*item.Item) {
|
||||
data, err := gamedata.GetData(CFG_LIMITED_TIME_EVENT_SENCE)
|
||||
if err != nil {
|
||||
log.Debug("GetSceneDashReward err:%v", err)
|
||||
return 0, nil
|
||||
}
|
||||
for k, v := range data {
|
||||
if Sence == gamedata.GetIntValue(v, "Sence") && Progress == gamedata.GetIntValue(v, "Progress") {
|
||||
return GoUtil.Int(k), gamedata.GetItemList(v, "Items")
|
||||
}
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func GetSenceJackpotProb() map[int]int {
|
||||
r := make(map[int]int)
|
||||
data, err := gamedata.GetData(CFG_LIMITED_TIME_EVENT_SENCE_JACKPOT)
|
||||
if err != nil {
|
||||
log.Debug("GetSenceJackpotReward err:%v", err)
|
||||
return nil
|
||||
}
|
||||
for k, v := range data {
|
||||
Id := GoUtil.Int(k)
|
||||
r[Id] = gamedata.GetIntValue(v, "Prob")
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func GetSenceJackpotReward(Id int) []*item.Item {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_LIMITED_TIME_EVENT_SENCE_JACKPOT, Id)
|
||||
if err != nil {
|
||||
log.Debug("GetSenceJackpotReward err:%v", err)
|
||||
return nil
|
||||
}
|
||||
return gamedata.GetItemList(data, "Items")
|
||||
}
|
||||
|
||||
// 获取连击快手奖励
|
||||
func GetFastProduceReward(Times, Energy int) []*item.Item {
|
||||
data, err := gamedata.GetData(CFG_LIMITED_TIME_EVENT_FAST)
|
||||
if err != nil {
|
||||
log.Debug("GetSceneDashReward err:%v", err)
|
||||
return nil
|
||||
}
|
||||
for _, v := range data {
|
||||
if Times == gamedata.GetIntValue(v, "Times") && Energy <= gamedata.GetIntValue(v, "Max") && Energy >= gamedata.GetIntValue(v, "Min") {
|
||||
return gamedata.GetItemList(v, "Items")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetProgressMax() int {
|
||||
data, err := gamedata.GetDataByKey(CFG_LIMITED_TIME_EVENT_CONST, "Progress_max")
|
||||
if err != nil {
|
||||
log.Debug("GetProgressMax err:%v", err)
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetIntValue(data, "value")
|
||||
}
|
||||
|
||||
func GetProgressRewardRand(Lv int) map[int]int {
|
||||
data, err := gamedata.GetData(CFG_LIMITED_TIME_EVENT_JACKPOT)
|
||||
if err != nil {
|
||||
log.Debug("GetProgressRewardRand err:%v", err)
|
||||
return nil
|
||||
}
|
||||
r := make(map[int]int)
|
||||
for k, v := range data {
|
||||
if Lv >= gamedata.GetIntValue(v, "Min") && Lv <= gamedata.GetIntValue(v, "Max") {
|
||||
Id := GoUtil.Int(k)
|
||||
r[Id] = gamedata.GetIntValue(v, "Prob")
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func GetProgressSelectNum(Lv int) int {
|
||||
data, err := gamedata.GetDataByKey(CFG_LIMITED_TIME_EVENT_CONST, "Progress_lv_num")
|
||||
if err != nil {
|
||||
log.Debug("GetProgressSelectNum err:%v", err)
|
||||
return 0
|
||||
}
|
||||
Str := gamedata.GetStringValue(data, "value")
|
||||
Strarr := strings.Split(Str, ";")
|
||||
for _, v := range Strarr {
|
||||
a := strings.Split(v, ",")
|
||||
if len(a) != 3 {
|
||||
continue
|
||||
}
|
||||
Min, _ := strconv.Atoi(a[0])
|
||||
Max, _ := strconv.Atoi(a[1])
|
||||
if Lv >= Min && Lv <= Max {
|
||||
Num, _ := strconv.Atoi(a[2])
|
||||
return Num
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetProgressReward(RewardId int) []*item.Item {
|
||||
data, err := gamedata.GetData(CFG_LIMITED_TIME_EVENT_JACKPOT)
|
||||
if err != nil {
|
||||
log.Debug("GetProgressReward err:%v", err)
|
||||
return nil
|
||||
}
|
||||
for k, v := range data {
|
||||
Id := GoUtil.Int(k)
|
||||
if Id == RewardId {
|
||||
return gamedata.GetItemList(v, "Items")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
188
src/server/conf/mergeData/MergeDataCfg.go
Normal file
188
src/server/conf/mergeData/MergeDataCfg.go
Normal file
@ -0,0 +1,188 @@
|
||||
package mergeDataCfg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"server/gamedata"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
CFG_NAME = "MergeData"
|
||||
CONST_NAME = "MergeDataConst"
|
||||
|
||||
// 棋子类型
|
||||
CHESS_PRODUCT_MAIN_TYPE = 1 // 主产物
|
||||
CHESS_PRODUCT_SUB_TYPE = 2 // 次产物
|
||||
CHESS_PRODUCT_SUB_EMIT_TYPE = 3 // 次发射器产物
|
||||
)
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(CFG_NAME)
|
||||
gamedata.InitCfg(CONST_NAME)
|
||||
}
|
||||
|
||||
// 获取单个数据
|
||||
func GetOne(Id int) (*gamedata.MergeDataRecord, error) {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, Id)
|
||||
if err != nil {
|
||||
log.Debug("MergeDataCfg GetOne Id:%v not found", Id)
|
||||
return &gamedata.MergeDataRecord{}, errors.New("not found")
|
||||
}
|
||||
return &gamedata.MergeDataRecord{
|
||||
Id: gamedata.ParseInt(data["Id"]),
|
||||
Lv: gamedata.ParseInt(data["Lv"]),
|
||||
MaxLv: gamedata.ParseInt(data["MaxLv"]),
|
||||
SellType: gamedata.ParseString(data["SellType"]),
|
||||
SellNum: gamedata.ParseInt(data["SellNum"]),
|
||||
SellDiamond: gamedata.ParseInt(data["SellDiamond"]),
|
||||
Color: gamedata.ParseString(data["Color"]),
|
||||
Star: gamedata.ParseInt(data["Star"]),
|
||||
Type: gamedata.ParseString(data["Type"]),
|
||||
Emit_Product: gamedata.ParseString(data["Emit_Product"]),
|
||||
CoolTime: gamedata.ParseInt(data["CoolTime"]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 根据id获取棋子获得的星星
|
||||
func GetStarById(Id int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, Id)
|
||||
if err != nil {
|
||||
log.Debug("MergeDataCfg GetOne Id:%v not found", Id)
|
||||
return 0
|
||||
}
|
||||
return gamedata.ParseInt(data["Star"])
|
||||
}
|
||||
|
||||
// 根据等级和颜色获取棋子id
|
||||
func GetChessIdByLvAndColor(Lv int, Color string) int {
|
||||
if Lv == 0 || Color == "" {
|
||||
return 0
|
||||
}
|
||||
data, err := gamedata.GetData(CFG_NAME)
|
||||
if err != nil {
|
||||
log.Debug("MergeDataCfg GetChessIdByLvAndColor lv:%v Color:%v not found", Lv, Color)
|
||||
return 0
|
||||
}
|
||||
for k, v := range data {
|
||||
lv := gamedata.GetIntValue(v, "Lv")
|
||||
color := gamedata.GetStringValue(v, "Color")
|
||||
if Lv == lv && color == Color {
|
||||
Id, _ := strconv.Atoi(k)
|
||||
return Id
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// 根据Id获取棋子等级
|
||||
func GetLvById(Id int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, Id)
|
||||
if err != nil {
|
||||
log.Debug("GetLvById GetOne Id:%v not found", Id)
|
||||
return 0
|
||||
}
|
||||
return gamedata.ParseInt(data["Lv"])
|
||||
}
|
||||
|
||||
// 根据Id获取棋子最大等级
|
||||
func GetMaxLvById(Id int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, Id)
|
||||
if err != nil {
|
||||
log.Debug("GetMaxLvById GetOne Id:%v not found", Id)
|
||||
return 0
|
||||
}
|
||||
return gamedata.ParseInt(data["MaxLv"])
|
||||
}
|
||||
|
||||
// 根据Id获取棋子类型
|
||||
func GetTypeById(Id int) string {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, Id)
|
||||
if err != nil {
|
||||
log.Debug("GetTypeById GetOne Id:%v not found", Id)
|
||||
return ""
|
||||
}
|
||||
return gamedata.ParseString(data["Type"])
|
||||
}
|
||||
|
||||
// 根据Id获取棋子类型
|
||||
func GetColorById(Id int) string {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, Id)
|
||||
if err != nil {
|
||||
log.Debug("GetColorById GetOne Id:%v not found", Id)
|
||||
return ""
|
||||
}
|
||||
return gamedata.ParseString(data["Color"])
|
||||
}
|
||||
|
||||
// 根据Id获取发射器产出类型
|
||||
func GetEmitProduceType(Id int) []string {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, Id)
|
||||
if err != nil {
|
||||
log.Debug("GetTypeById GetOne Id:%v not found", Id)
|
||||
return []string{}
|
||||
}
|
||||
return strings.Split(gamedata.ParseString(data["Emit_Product"]), ",")
|
||||
}
|
||||
|
||||
// 根据Id获取发射器Id
|
||||
func GetEmitId(Id int) string {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, Id)
|
||||
if err != nil {
|
||||
log.Debug("GetTypeById GetOne Id:%v not found", Id)
|
||||
return ""
|
||||
}
|
||||
return gamedata.ParseString(data["Emit_ID"])
|
||||
}
|
||||
|
||||
// 获取常量
|
||||
func GetConst(Key string) string {
|
||||
data, err := gamedata.GetDataByKey(CONST_NAME, Key)
|
||||
if err != nil {
|
||||
log.Debug("GetConst GetOne Id:%s not found", Key)
|
||||
return ""
|
||||
}
|
||||
return gamedata.ParseString(data["Value"])
|
||||
}
|
||||
|
||||
// 获取常量
|
||||
func GetConstInt(Key string) int {
|
||||
data, err := gamedata.GetDataByKey(CONST_NAME, Key)
|
||||
if err != nil {
|
||||
log.Debug("GetConst GetOne Id:%s not found", Key)
|
||||
return 0
|
||||
}
|
||||
return gamedata.ParseInt(data["Value"])
|
||||
}
|
||||
|
||||
func GetExtraEmitId() map[string]struct{} {
|
||||
Value := GetConst("EmitId_Extra_Order")
|
||||
arr := strings.Split(Value, ",")
|
||||
var r = make(map[string]struct{})
|
||||
for _, v := range arr {
|
||||
r[v] = struct{}{}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func GetProductType(Chess int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, Chess)
|
||||
if err != nil {
|
||||
log.Debug("GetProductType GetOne Id:%v not found", Chess)
|
||||
return 0
|
||||
}
|
||||
return gamedata.ParseInt(data["PType"])
|
||||
}
|
||||
|
||||
func GetChessBagMaxGrid() int {
|
||||
return GetConstInt("chess_bag_max")
|
||||
}
|
||||
|
||||
func GetChessBagBugNum() int {
|
||||
return GetConstInt("chess_bag_buy")
|
||||
}
|
||||
|
||||
func GetChessBagInitNum() int {
|
||||
return GetConstInt("chess_bag_init")
|
||||
}
|
||||
38
src/server/conf/order/orderCfg.go
Normal file
38
src/server/conf/order/orderCfg.go
Normal file
@ -0,0 +1,38 @@
|
||||
package orderCfg
|
||||
|
||||
import (
|
||||
"server/gamedata"
|
||||
)
|
||||
|
||||
const (
|
||||
CFG_ORDER_DATA = "OrderData"
|
||||
CFG_ORDER_CHESS_DATA = "OrderChessData"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(CFG_ORDER_DATA)
|
||||
gamedata.InitCfg(CFG_ORDER_CHESS_DATA)
|
||||
}
|
||||
|
||||
func GetLvMin(EnergyMul int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_ORDER_DATA, EnergyMul)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetIntValue(data, "LvMin")
|
||||
}
|
||||
|
||||
func GetLvMax(EnergyMul, N int) int {
|
||||
if v, ok := gamedata.G_AllConfigsJsonData["OrderChessData"]; ok {
|
||||
data := v.GetData()
|
||||
for _, v := range data {
|
||||
dEnergy := gamedata.GetIntValue(v, "EnergyMul")
|
||||
Min := gamedata.GetIntValue(v, "MinN")
|
||||
Max := gamedata.GetIntValue(v, "MaxN")
|
||||
if dEnergy == EnergyMul && N >= Min && N <= Max {
|
||||
return gamedata.GetIntValue(v, "MaxLv")
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
32
src/server/conf/server.json
Normal file
32
src/server/conf/server.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"LogLevel": "debug",
|
||||
"LogPath": "",
|
||||
"TCPAddr": ":3565",
|
||||
"WSAddr": ":3566",
|
||||
"MySqlAddr": "127.0.0.1",
|
||||
"MySqlPort": "3306",
|
||||
"MySqlUsr": "root",
|
||||
"MySqlPwd": "root",
|
||||
"MaxConnNum": 20000,
|
||||
"DbName": "Merge_Pet",
|
||||
"HttpPort": ":8081",
|
||||
"RemoteAddr":"host.docker.internal:9001",
|
||||
|
||||
"GameName": "Merge_Pet",
|
||||
"GameID": 1,
|
||||
"ServerType":"node",
|
||||
|
||||
"ServerID": 1,
|
||||
"ServerOpenTime": "2018-01-01 00:00:00",
|
||||
"ServerName": "Merge_Pet",
|
||||
"ServerStatus" : 1,
|
||||
"ServerCenter" : 1,
|
||||
|
||||
|
||||
"RedisAddr":"127.0.0.1",
|
||||
"RedisPort" :"6379",
|
||||
"RedisPwd" :"",
|
||||
|
||||
"ListenAddr": ":9001",
|
||||
"CenterAddr": ":3560"
|
||||
}
|
||||
98
src/server/conf/sevenLogin/SevenLoginCfg.go
Normal file
98
src/server/conf/sevenLogin/SevenLoginCfg.go
Normal file
@ -0,0 +1,98 @@
|
||||
package sevenLoginCfg
|
||||
|
||||
import (
|
||||
"math"
|
||||
"server/game/mod/item"
|
||||
"server/gamedata"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
CFG_SEVEN_LOGIN = "SevenLogin"
|
||||
CFG_SEVEN_LOGIN_JACKPOT = "SevenLoginJackpot"
|
||||
CFG_SEVEN_LOGIN_MONTH = "SevenLoginMonth"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(CFG_SEVEN_LOGIN)
|
||||
gamedata.InitCfg(CFG_SEVEN_LOGIN_JACKPOT)
|
||||
gamedata.InitCfg(CFG_SEVEN_LOGIN_MONTH)
|
||||
}
|
||||
|
||||
func GetSevenLoginReward() []*gamedata.SevenLoginRewardData {
|
||||
data, err := gamedata.GetData(CFG_SEVEN_LOGIN)
|
||||
if err != nil {
|
||||
log.Debug("GetSevenLoginReward err:%v", err)
|
||||
return nil
|
||||
}
|
||||
var result []*gamedata.SevenLoginRewardData
|
||||
for k, v := range data {
|
||||
Id, _ := strconv.Atoi(k)
|
||||
Diamond := gamedata.GetIntValue(v, "Diamond")
|
||||
RewardNum := gamedata.GetIntValue(v, "RewardNum")
|
||||
result = append(result, &gamedata.SevenLoginRewardData{
|
||||
Id: Id,
|
||||
Diamond: Diamond,
|
||||
RewardNum: RewardNum,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func GetSevenLoginMonthReward() []*gamedata.SevenLoginRewardData {
|
||||
data, err := gamedata.GetData(CFG_SEVEN_LOGIN_MONTH)
|
||||
if err != nil {
|
||||
log.Debug("GetSevenLoginReward err:%v", err)
|
||||
return nil
|
||||
}
|
||||
var result []*gamedata.SevenLoginRewardData
|
||||
for k, v := range data {
|
||||
Id, _ := strconv.Atoi(k)
|
||||
Diamond := gamedata.GetIntValue(v, "Diamond")
|
||||
RewardNum := gamedata.GetIntValue(v, "RewardNum")
|
||||
result = append(result, &gamedata.SevenLoginRewardData{
|
||||
Id: Id,
|
||||
Diamond: Diamond,
|
||||
RewardNum: RewardNum,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func GetSevenLoginJackpot(IsMonth int) []*gamedata.SevenLoginJackpotData {
|
||||
data, err := gamedata.GetData(CFG_SEVEN_LOGIN_JACKPOT)
|
||||
if err != nil {
|
||||
log.Debug("GetSevenLoginJackpot err:%v", err)
|
||||
return nil
|
||||
}
|
||||
var result []*gamedata.SevenLoginJackpotData
|
||||
for k, v := range data {
|
||||
Id, _ := strconv.Atoi(k)
|
||||
Diamond := gamedata.GetIntValue(v, "Diamond")
|
||||
Type := gamedata.GetIntValue(v, "Type")
|
||||
Month := gamedata.GetIntValue(v, "Month")
|
||||
if IsMonth != Month && IsMonth != 0 {
|
||||
continue
|
||||
}
|
||||
ItemMap := gamedata.GetValue(v, "Item")
|
||||
Items := item.ParseItem(ItemMap)
|
||||
result = append(result, &gamedata.SevenLoginJackpotData{
|
||||
Id: Id,
|
||||
Diamond: Diamond,
|
||||
Items: Items,
|
||||
Type: Type,
|
||||
Month: Month,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func GetMonthActive(Id int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_SEVEN_LOGIN_MONTH, Id)
|
||||
if err != nil {
|
||||
log.Debug("GetSevenLoginReward err:%v", err)
|
||||
return int(math.Inf(1))
|
||||
}
|
||||
return gamedata.GetIntValue(data, "Active")
|
||||
}
|
||||
38
src/server/conf/startMerge/StartMergeCfg.go
Normal file
38
src/server/conf/startMerge/StartMergeCfg.go
Normal file
@ -0,0 +1,38 @@
|
||||
package startMergeCfg
|
||||
|
||||
import (
|
||||
"server/gamedata"
|
||||
)
|
||||
|
||||
var CFG_NAME = "StartMerge"
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(CFG_NAME)
|
||||
}
|
||||
|
||||
func GetStartChessList() []int {
|
||||
data, err := gamedata.GetData(CFG_NAME)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
var ChessList []int
|
||||
for _, v := range data {
|
||||
v1 := v.(map[string]interface{})
|
||||
ChessList = append(ChessList, gamedata.ParseInt(v1["MergeId"]))
|
||||
}
|
||||
return ChessList
|
||||
}
|
||||
|
||||
func GetInitChessList() []int {
|
||||
data, err := gamedata.GetData(CFG_NAME)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
var ChessList []int
|
||||
for _, v := range data {
|
||||
if gamedata.GetIntValue(v, "Lock") == 0 {
|
||||
ChessList = append(ChessList, gamedata.GetIntValue(v, "MergeId"))
|
||||
}
|
||||
}
|
||||
return ChessList
|
||||
}
|
||||
85
src/server/conf/user/UserData.go
Normal file
85
src/server/conf/user/UserData.go
Normal file
@ -0,0 +1,85 @@
|
||||
package userCfg
|
||||
|
||||
import (
|
||||
"server/game/mod/item"
|
||||
"server/gamedata"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
)
|
||||
|
||||
var CFG_NAME = "UserData"
|
||||
|
||||
func init() {
|
||||
gamedata.InitCfg(CFG_NAME)
|
||||
}
|
||||
|
||||
// 获取用户能量倍数
|
||||
func GetEnergyMulByLv(lv int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, lv)
|
||||
if err != nil {
|
||||
log.Debug("UserDataCfg GetEnergyMulByLv lv:%v not found", lv)
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetIntValue(data, "EnergyMul")
|
||||
}
|
||||
|
||||
// 获取七天登录加成
|
||||
func GetSevenloginAdd(Lv int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, Lv)
|
||||
if err != nil {
|
||||
log.Debug("UserDataCfg GetSevenloginAdd lv:%v not found", Lv)
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetIntValue(data, "SevenLogin")
|
||||
}
|
||||
|
||||
// 获取订单系数
|
||||
func GetOrderNByLv(lv int) (int, error) {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, lv)
|
||||
if err != nil {
|
||||
log.Debug("UserDataCfg GetOrderNByLv lv:%v not found", lv)
|
||||
return 0, err
|
||||
}
|
||||
return gamedata.GetIntValue(data, "OrderN"), nil
|
||||
}
|
||||
|
||||
// 获取升级经验
|
||||
func GetLevUpExp(lv int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, lv)
|
||||
if err != nil {
|
||||
log.Debug("UserDataCfg GetLevUpExp lv:%v not found", lv)
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetIntValue(data, "Exp")
|
||||
}
|
||||
|
||||
// 获取能量回复时间
|
||||
func GetRecover(lv int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, lv)
|
||||
if err != nil {
|
||||
log.Debug("UserDataCfg GetRecover lv:%v not found", lv)
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetIntValue(data, "Recover")
|
||||
}
|
||||
|
||||
// 获取解锁背包数量
|
||||
func GetUnlockPack(lv int) int {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, lv)
|
||||
if err != nil {
|
||||
log.Debug("UserDataCfg GetUnlockPack lv:%v not found", lv)
|
||||
return 0
|
||||
}
|
||||
return gamedata.GetIntValue(data, "UnlockPack")
|
||||
}
|
||||
|
||||
// 获取升级奖励
|
||||
func GetLevUpReward(lv int) []*item.Item {
|
||||
data, err := gamedata.GetDataByIntKey(CFG_NAME, lv)
|
||||
if err != nil {
|
||||
log.Debug("UserDataCfg GetLevUpReward lv:%v not found", lv)
|
||||
return nil
|
||||
}
|
||||
itemMap := gamedata.GetValue(data, "Item")
|
||||
itemList := item.ParseItem(itemMap)
|
||||
return itemList
|
||||
}
|
||||
21
src/server/cron/LICENSE
Normal file
21
src/server/cron/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
Copyright (C) 2012 Rob Figueiredo
|
||||
All Rights Reserved.
|
||||
|
||||
MIT LICENSE
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
125
src/server/cron/README.md
Normal file
125
src/server/cron/README.md
Normal file
@ -0,0 +1,125 @@
|
||||
[](http://godoc.org/github.com/robfig/cron)
|
||||
[](https://travis-ci.org/robfig/cron)
|
||||
|
||||
# cron
|
||||
|
||||
Cron V3 has been released!
|
||||
|
||||
To download the specific tagged release, run:
|
||||
|
||||
go get github.com/robfig/cron/v3@v3.0.0
|
||||
|
||||
Import it in your program as:
|
||||
|
||||
import "github.com/robfig/cron/v3"
|
||||
|
||||
It requires Go 1.11 or later due to usage of Go Modules.
|
||||
|
||||
Refer to the documentation here:
|
||||
http://godoc.org/github.com/robfig/cron
|
||||
|
||||
The rest of this document describes the the advances in v3 and a list of
|
||||
breaking changes for users that wish to upgrade from an earlier version.
|
||||
|
||||
## Upgrading to v3 (June 2019)
|
||||
|
||||
cron v3 is a major upgrade to the library that addresses all outstanding bugs,
|
||||
feature requests, and rough edges. It is based on a merge of master which
|
||||
contains various fixes to issues found over the years and the v2 branch which
|
||||
contains some backwards-incompatible features like the ability to remove cron
|
||||
jobs. In addition, v3 adds support for Go Modules, cleans up rough edges like
|
||||
the timezone support, and fixes a number of bugs.
|
||||
|
||||
New features:
|
||||
|
||||
- Support for Go modules. Callers must now import this library as
|
||||
`github.com/robfig/cron/v3`, instead of `gopkg.in/...`
|
||||
|
||||
- Fixed bugs:
|
||||
- 0f01e6b parser: fix combining of Dow and Dom (#70)
|
||||
- dbf3220 adjust times when rolling the clock forward to handle non-existent midnight (#157)
|
||||
- eeecf15 spec_test.go: ensure an error is returned on 0 increment (#144)
|
||||
- 70971dc cron.Entries(): update request for snapshot to include a reply channel (#97)
|
||||
- 1cba5e6 cron: fix: removing a job causes the next scheduled job to run too late (#206)
|
||||
|
||||
- Standard cron spec parsing by default (first field is "minute"), with an easy
|
||||
way to opt into the seconds field (quartz-compatible). Although, note that the
|
||||
year field (optional in Quartz) is not supported.
|
||||
|
||||
- Extensible, key/value logging via an interface that complies with
|
||||
the https://github.com/go-logr/logr project.
|
||||
|
||||
- The new Chain & JobWrapper types allow you to install "interceptors" to add
|
||||
cross-cutting behavior like the following:
|
||||
- Recover any panics from jobs
|
||||
- Delay a job's execution if the previous run hasn't completed yet
|
||||
- Skip a job's execution if the previous run hasn't completed yet
|
||||
- Log each job's invocations
|
||||
- Notification when jobs are completed
|
||||
|
||||
It is backwards incompatible with both v1 and v2. These updates are required:
|
||||
|
||||
- The v1 branch accepted an optional seconds field at the beginning of the cron
|
||||
spec. This is non-standard and has led to a lot of confusion. The new default
|
||||
parser conforms to the standard as described by [the Cron wikipedia page].
|
||||
|
||||
UPDATING: To retain the old behavior, construct your Cron with a custom
|
||||
parser:
|
||||
|
||||
// Seconds field, required
|
||||
cron.New(cron.WithSeconds())
|
||||
|
||||
// Seconds field, optional
|
||||
cron.New(
|
||||
cron.WithParser(
|
||||
cron.SecondOptional | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor))
|
||||
|
||||
- The Cron type now accepts functional options on construction rather than the
|
||||
previous ad-hoc behavior modification mechanisms (setting a field, calling a setter).
|
||||
|
||||
UPDATING: Code that sets Cron.ErrorLogger or calls Cron.SetLocation must be
|
||||
updated to provide those values on construction.
|
||||
|
||||
- CRON_TZ is now the recommended way to specify the timezone of a single
|
||||
schedule, which is sanctioned by the specification. The legacy "TZ=" prefix
|
||||
will continue to be supported since it is unambiguous and easy to do so.
|
||||
|
||||
UPDATING: No update is required.
|
||||
|
||||
- By default, cron will no longer recover panics in jobs that it runs.
|
||||
Recovering can be surprising (see issue #192) and seems to be at odds with
|
||||
typical behavior of libraries. Relatedly, the `cron.WithPanicLogger` option
|
||||
has been removed to accommodate the more general JobWrapper type.
|
||||
|
||||
UPDATING: To opt into panic recovery and configure the panic logger:
|
||||
|
||||
cron.New(cron.WithChain(
|
||||
cron.Recover(logger), // or use cron.DefaultLogger
|
||||
))
|
||||
|
||||
- In adding support for https://github.com/go-logr/logr, `cron.WithVerboseLogger` was
|
||||
removed, since it is duplicative with the leveled logging.
|
||||
|
||||
UPDATING: Callers should use `WithLogger` and specify a logger that does not
|
||||
discard `Info` logs. For convenience, one is provided that wraps `*log.Logger`:
|
||||
|
||||
cron.New(
|
||||
cron.WithLogger(cron.VerbosePrintfLogger(logger)))
|
||||
|
||||
|
||||
### Background - Cron spec format
|
||||
|
||||
There are two cron spec formats in common usage:
|
||||
|
||||
- The "standard" cron format, described on [the Cron wikipedia page] and used by
|
||||
the cron Linux system utility.
|
||||
|
||||
- The cron format used by [the Quartz Scheduler], commonly used for scheduled
|
||||
jobs in Java software
|
||||
|
||||
[the Cron wikipedia page]: https://en.wikipedia.org/wiki/Cron
|
||||
[the Quartz Scheduler]: http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/crontrigger.html
|
||||
|
||||
The original version of this package included an optional "seconds" field, which
|
||||
made it incompatible with both of these formats. Now, the "standard" format is
|
||||
the default format accepted, and the Quartz format is opt-in.
|
||||
92
src/server/cron/chain.go
Normal file
92
src/server/cron/chain.go
Normal file
@ -0,0 +1,92 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// JobWrapper decorates the given Job with some behavior.
|
||||
type JobWrapper func(Job) Job
|
||||
|
||||
// Chain is a sequence of JobWrappers that decorates submitted jobs with
|
||||
// cross-cutting behaviors like logging or synchronization.
|
||||
type Chain struct {
|
||||
wrappers []JobWrapper
|
||||
}
|
||||
|
||||
// NewChain returns a Chain consisting of the given JobWrappers.
|
||||
func NewChain(c ...JobWrapper) Chain {
|
||||
return Chain{c}
|
||||
}
|
||||
|
||||
// Then decorates the given job with all JobWrappers in the chain.
|
||||
//
|
||||
// This:
|
||||
// NewChain(m1, m2, m3).Then(job)
|
||||
// is equivalent to:
|
||||
// m1(m2(m3(job)))
|
||||
func (c Chain) Then(j Job) Job {
|
||||
for i := range c.wrappers {
|
||||
j = c.wrappers[len(c.wrappers)-i-1](j)
|
||||
}
|
||||
return j
|
||||
}
|
||||
|
||||
// Recover panics in wrapped jobs and log them with the provided logger.
|
||||
func Recover(logger Logger) JobWrapper {
|
||||
return func(j Job) Job {
|
||||
return FuncJob(func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
const size = 64 << 10
|
||||
buf := make([]byte, size)
|
||||
buf = buf[:runtime.Stack(buf, false)]
|
||||
err, ok := r.(error)
|
||||
if !ok {
|
||||
err = fmt.Errorf("%v", r)
|
||||
}
|
||||
logger.Error(err, "panic", "stack", "...\n"+string(buf))
|
||||
}
|
||||
}()
|
||||
j.Run()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// DelayIfStillRunning serializes jobs, delaying subsequent runs until the
|
||||
// previous one is complete. Jobs running after a delay of more than a minute
|
||||
// have the delay logged at Info.
|
||||
func DelayIfStillRunning(logger Logger) JobWrapper {
|
||||
return func(j Job) Job {
|
||||
var mu sync.Mutex
|
||||
return FuncJob(func() {
|
||||
start := time.Now()
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if dur := time.Since(start); dur > time.Minute {
|
||||
logger.Info("delay", "duration", dur)
|
||||
}
|
||||
j.Run()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// SkipIfStillRunning skips an invocation of the Job if a previous invocation is
|
||||
// still running. It logs skips to the given logger at Info level.
|
||||
func SkipIfStillRunning(logger Logger) JobWrapper {
|
||||
var ch = make(chan struct{}, 1)
|
||||
ch <- struct{}{}
|
||||
return func(j Job) Job {
|
||||
return FuncJob(func() {
|
||||
select {
|
||||
case v := <-ch:
|
||||
j.Run()
|
||||
ch <- v
|
||||
default:
|
||||
logger.Info("skip")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
221
src/server/cron/chain_test.go
Normal file
221
src/server/cron/chain_test.go
Normal file
@ -0,0 +1,221 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func appendingJob(slice *[]int, value int) Job {
|
||||
var m sync.Mutex
|
||||
return FuncJob(func() {
|
||||
m.Lock()
|
||||
*slice = append(*slice, value)
|
||||
m.Unlock()
|
||||
})
|
||||
}
|
||||
|
||||
func appendingWrapper(slice *[]int, value int) JobWrapper {
|
||||
return func(j Job) Job {
|
||||
return FuncJob(func() {
|
||||
appendingJob(slice, value).Run()
|
||||
j.Run()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestChain(t *testing.T) {
|
||||
var nums []int
|
||||
var (
|
||||
append1 = appendingWrapper(&nums, 1)
|
||||
append2 = appendingWrapper(&nums, 2)
|
||||
append3 = appendingWrapper(&nums, 3)
|
||||
append4 = appendingJob(&nums, 4)
|
||||
)
|
||||
NewChain(append1, append2, append3).Then(append4).Run()
|
||||
if !reflect.DeepEqual(nums, []int{1, 2, 3, 4}) {
|
||||
t.Error("unexpected order of calls:", nums)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChainRecover(t *testing.T) {
|
||||
panickingJob := FuncJob(func() {
|
||||
panic("panickingJob panics")
|
||||
})
|
||||
|
||||
t.Run("panic exits job by default", func(t *testing.T) {
|
||||
defer func() {
|
||||
if err := recover(); err == nil {
|
||||
t.Errorf("panic expected, but none received")
|
||||
}
|
||||
}()
|
||||
NewChain().Then(panickingJob).
|
||||
Run()
|
||||
})
|
||||
|
||||
t.Run("Recovering JobWrapper recovers", func(t *testing.T) {
|
||||
NewChain(Recover(PrintfLogger(log.New(ioutil.Discard, "", 0)))).
|
||||
Then(panickingJob).
|
||||
Run()
|
||||
})
|
||||
|
||||
t.Run("composed with the *IfStillRunning wrappers", func(t *testing.T) {
|
||||
NewChain(Recover(PrintfLogger(log.New(ioutil.Discard, "", 0)))).
|
||||
Then(panickingJob).
|
||||
Run()
|
||||
})
|
||||
}
|
||||
|
||||
type countJob struct {
|
||||
m sync.Mutex
|
||||
started int
|
||||
done int
|
||||
delay time.Duration
|
||||
}
|
||||
|
||||
func (j *countJob) Run() {
|
||||
j.m.Lock()
|
||||
j.started++
|
||||
j.m.Unlock()
|
||||
time.Sleep(j.delay)
|
||||
j.m.Lock()
|
||||
j.done++
|
||||
j.m.Unlock()
|
||||
}
|
||||
|
||||
func (j *countJob) Started() int {
|
||||
defer j.m.Unlock()
|
||||
j.m.Lock()
|
||||
return j.started
|
||||
}
|
||||
|
||||
func (j *countJob) Done() int {
|
||||
defer j.m.Unlock()
|
||||
j.m.Lock()
|
||||
return j.done
|
||||
}
|
||||
|
||||
func TestChainDelayIfStillRunning(t *testing.T) {
|
||||
|
||||
t.Run("runs immediately", func(t *testing.T) {
|
||||
var j countJob
|
||||
wrappedJob := NewChain(DelayIfStillRunning(DiscardLogger)).Then(&j)
|
||||
go wrappedJob.Run()
|
||||
time.Sleep(2 * time.Millisecond) // Give the job 2ms to complete.
|
||||
if c := j.Done(); c != 1 {
|
||||
t.Errorf("expected job run once, immediately, got %d", c)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("second run immediate if first done", func(t *testing.T) {
|
||||
var j countJob
|
||||
wrappedJob := NewChain(DelayIfStillRunning(DiscardLogger)).Then(&j)
|
||||
go func() {
|
||||
go wrappedJob.Run()
|
||||
time.Sleep(time.Millisecond)
|
||||
go wrappedJob.Run()
|
||||
}()
|
||||
time.Sleep(3 * time.Millisecond) // Give both jobs 3ms to complete.
|
||||
if c := j.Done(); c != 2 {
|
||||
t.Errorf("expected job run twice, immediately, got %d", c)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("second run delayed if first not done", func(t *testing.T) {
|
||||
var j countJob
|
||||
j.delay = 10 * time.Millisecond
|
||||
wrappedJob := NewChain(DelayIfStillRunning(DiscardLogger)).Then(&j)
|
||||
go func() {
|
||||
go wrappedJob.Run()
|
||||
time.Sleep(time.Millisecond)
|
||||
go wrappedJob.Run()
|
||||
}()
|
||||
|
||||
// After 5ms, the first job is still in progress, and the second job was
|
||||
// run but should be waiting for it to finish.
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
started, done := j.Started(), j.Done()
|
||||
if started != 1 || done != 0 {
|
||||
t.Error("expected first job started, but not finished, got", started, done)
|
||||
}
|
||||
|
||||
// Verify that the second job completes.
|
||||
time.Sleep(25 * time.Millisecond)
|
||||
started, done = j.Started(), j.Done()
|
||||
if started != 2 || done != 2 {
|
||||
t.Error("expected both jobs done, got", started, done)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestChainSkipIfStillRunning(t *testing.T) {
|
||||
|
||||
t.Run("runs immediately", func(t *testing.T) {
|
||||
var j countJob
|
||||
wrappedJob := NewChain(SkipIfStillRunning(DiscardLogger)).Then(&j)
|
||||
go wrappedJob.Run()
|
||||
time.Sleep(2 * time.Millisecond) // Give the job 2ms to complete.
|
||||
if c := j.Done(); c != 1 {
|
||||
t.Errorf("expected job run once, immediately, got %d", c)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("second run immediate if first done", func(t *testing.T) {
|
||||
var j countJob
|
||||
wrappedJob := NewChain(SkipIfStillRunning(DiscardLogger)).Then(&j)
|
||||
go func() {
|
||||
go wrappedJob.Run()
|
||||
time.Sleep(time.Millisecond)
|
||||
go wrappedJob.Run()
|
||||
}()
|
||||
time.Sleep(3 * time.Millisecond) // Give both jobs 3ms to complete.
|
||||
if c := j.Done(); c != 2 {
|
||||
t.Errorf("expected job run twice, immediately, got %d", c)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("second run skipped if first not done", func(t *testing.T) {
|
||||
var j countJob
|
||||
j.delay = 10 * time.Millisecond
|
||||
wrappedJob := NewChain(SkipIfStillRunning(DiscardLogger)).Then(&j)
|
||||
go func() {
|
||||
go wrappedJob.Run()
|
||||
time.Sleep(time.Millisecond)
|
||||
go wrappedJob.Run()
|
||||
}()
|
||||
|
||||
// After 5ms, the first job is still in progress, and the second job was
|
||||
// aleady skipped.
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
started, done := j.Started(), j.Done()
|
||||
if started != 1 || done != 0 {
|
||||
t.Error("expected first job started, but not finished, got", started, done)
|
||||
}
|
||||
|
||||
// Verify that the first job completes and second does not run.
|
||||
time.Sleep(25 * time.Millisecond)
|
||||
started, done = j.Started(), j.Done()
|
||||
if started != 1 || done != 1 {
|
||||
t.Error("expected second job skipped, got", started, done)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("skip 10 jobs on rapid fire", func(t *testing.T) {
|
||||
var j countJob
|
||||
j.delay = 10 * time.Millisecond
|
||||
wrappedJob := NewChain(SkipIfStillRunning(DiscardLogger)).Then(&j)
|
||||
for i := 0; i < 11; i++ {
|
||||
go wrappedJob.Run()
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
done := j.Done()
|
||||
if done != 1 {
|
||||
t.Error("expected 1 jobs executed, 10 jobs dropped, got", done)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
27
src/server/cron/constantdelay.go
Normal file
27
src/server/cron/constantdelay.go
Normal file
@ -0,0 +1,27 @@
|
||||
package cron
|
||||
|
||||
import "time"
|
||||
|
||||
// ConstantDelaySchedule represents a simple recurring duty cycle, e.g. "Every 5 minutes".
|
||||
// It does not support jobs more frequent than once a second.
|
||||
type ConstantDelaySchedule struct {
|
||||
Delay time.Duration
|
||||
}
|
||||
|
||||
// Every returns a crontab Schedule that activates once every duration.
|
||||
// Delays of less than a second are not supported (will round up to 1 second).
|
||||
// Any fields less than a Second are truncated.
|
||||
func Every(duration time.Duration) ConstantDelaySchedule {
|
||||
if duration < time.Second {
|
||||
duration = time.Second
|
||||
}
|
||||
return ConstantDelaySchedule{
|
||||
Delay: duration - time.Duration(duration.Nanoseconds())%time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
// Next returns the next time this should be run.
|
||||
// This rounds so that the next activation time will be on the second.
|
||||
func (schedule ConstantDelaySchedule) Next(t time.Time) time.Time {
|
||||
return t.Add(schedule.Delay - time.Duration(t.Nanosecond())*time.Nanosecond)
|
||||
}
|
||||
54
src/server/cron/constantdelay_test.go
Normal file
54
src/server/cron/constantdelay_test.go
Normal file
@ -0,0 +1,54 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestConstantDelayNext(t *testing.T) {
|
||||
tests := []struct {
|
||||
time string
|
||||
delay time.Duration
|
||||
expected string
|
||||
}{
|
||||
// Simple cases
|
||||
{"Mon Jul 9 14:45 2012", 15*time.Minute + 50*time.Nanosecond, "Mon Jul 9 15:00 2012"},
|
||||
{"Mon Jul 9 14:59 2012", 15 * time.Minute, "Mon Jul 9 15:14 2012"},
|
||||
{"Mon Jul 9 14:59:59 2012", 15 * time.Minute, "Mon Jul 9 15:14:59 2012"},
|
||||
|
||||
// Wrap around hours
|
||||
{"Mon Jul 9 15:45 2012", 35 * time.Minute, "Mon Jul 9 16:20 2012"},
|
||||
|
||||
// Wrap around days
|
||||
{"Mon Jul 9 23:46 2012", 14 * time.Minute, "Tue Jul 10 00:00 2012"},
|
||||
{"Mon Jul 9 23:45 2012", 35 * time.Minute, "Tue Jul 10 00:20 2012"},
|
||||
{"Mon Jul 9 23:35:51 2012", 44*time.Minute + 24*time.Second, "Tue Jul 10 00:20:15 2012"},
|
||||
{"Mon Jul 9 23:35:51 2012", 25*time.Hour + 44*time.Minute + 24*time.Second, "Thu Jul 11 01:20:15 2012"},
|
||||
|
||||
// Wrap around months
|
||||
{"Mon Jul 9 23:35 2012", 91*24*time.Hour + 25*time.Minute, "Thu Oct 9 00:00 2012"},
|
||||
|
||||
// Wrap around minute, hour, day, month, and year
|
||||
{"Mon Dec 31 23:59:45 2012", 15 * time.Second, "Tue Jan 1 00:00:00 2013"},
|
||||
|
||||
// Round to nearest second on the delay
|
||||
{"Mon Jul 9 14:45 2012", 15*time.Minute + 50*time.Nanosecond, "Mon Jul 9 15:00 2012"},
|
||||
|
||||
// Round up to 1 second if the duration is less.
|
||||
{"Mon Jul 9 14:45:00 2012", 15 * time.Millisecond, "Mon Jul 9 14:45:01 2012"},
|
||||
|
||||
// Round to nearest second when calculating the next time.
|
||||
{"Mon Jul 9 14:45:00.005 2012", 15 * time.Minute, "Mon Jul 9 15:00 2012"},
|
||||
|
||||
// Round to nearest second for both.
|
||||
{"Mon Jul 9 14:45:00.005 2012", 15*time.Minute + 50*time.Nanosecond, "Mon Jul 9 15:00 2012"},
|
||||
}
|
||||
|
||||
for _, c := range tests {
|
||||
actual := Every(c.delay).Next(getTime(c.time))
|
||||
expected := getTime(c.expected)
|
||||
if actual != expected {
|
||||
t.Errorf("%s, \"%s\": (expected) %v != %v (actual)", c.time, c.delay, expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
350
src/server/cron/cron.go
Normal file
350
src/server/cron/cron.go
Normal file
@ -0,0 +1,350 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Cron keeps track of any number of entries, invoking the associated func as
|
||||
// specified by the schedule. It may be started, stopped, and the entries may
|
||||
// be inspected while running.
|
||||
type Cron struct {
|
||||
entries []*Entry
|
||||
chain Chain
|
||||
stop chan struct{}
|
||||
add chan *Entry
|
||||
remove chan EntryID
|
||||
snapshot chan chan []Entry
|
||||
running bool
|
||||
logger Logger
|
||||
runningMu sync.Mutex
|
||||
location *time.Location
|
||||
parser Parser
|
||||
nextID EntryID
|
||||
jobWaiter sync.WaitGroup
|
||||
}
|
||||
|
||||
// Job is an interface for submitted cron jobs.
|
||||
type Job interface {
|
||||
Run()
|
||||
}
|
||||
|
||||
// Schedule describes a job's duty cycle.
|
||||
type Schedule interface {
|
||||
// Next returns the next activation time, later than the given time.
|
||||
// Next is invoked initially, and then each time the job is run.
|
||||
Next(time.Time) time.Time
|
||||
}
|
||||
|
||||
// EntryID identifies an entry within a Cron instance
|
||||
type EntryID int
|
||||
|
||||
// Entry consists of a schedule and the func to execute on that schedule.
|
||||
type Entry struct {
|
||||
// ID is the cron-assigned ID of this entry, which may be used to look up a
|
||||
// snapshot or remove it.
|
||||
ID EntryID
|
||||
|
||||
// Schedule on which this job should be run.
|
||||
Schedule Schedule
|
||||
|
||||
// Next time the job will run, or the zero time if Cron has not been
|
||||
// started or this entry's schedule is unsatisfiable
|
||||
Next time.Time
|
||||
|
||||
// Prev is the last time this job was run, or the zero time if never.
|
||||
Prev time.Time
|
||||
|
||||
// WrappedJob is the thing to run when the Schedule is activated.
|
||||
WrappedJob Job
|
||||
|
||||
// Job is the thing that was submitted to cron.
|
||||
// It is kept around so that user code that needs to get at the job later,
|
||||
// e.g. via Entries() can do so.
|
||||
Job Job
|
||||
}
|
||||
|
||||
// Valid returns true if this is not the zero entry.
|
||||
func (e Entry) Valid() bool { return e.ID != 0 }
|
||||
|
||||
// byTime is a wrapper for sorting the entry array by time
|
||||
// (with zero time at the end).
|
||||
type byTime []*Entry
|
||||
|
||||
func (s byTime) Len() int { return len(s) }
|
||||
func (s byTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s byTime) Less(i, j int) bool {
|
||||
// Two zero times should return false.
|
||||
// Otherwise, zero is "greater" than any other time.
|
||||
// (To sort it at the end of the list.)
|
||||
if s[i].Next.IsZero() {
|
||||
return false
|
||||
}
|
||||
if s[j].Next.IsZero() {
|
||||
return true
|
||||
}
|
||||
return s[i].Next.Before(s[j].Next)
|
||||
}
|
||||
|
||||
// New returns a new Cron job runner, modified by the given options.
|
||||
//
|
||||
// Available Settings
|
||||
//
|
||||
// Time Zone
|
||||
// Description: The time zone in which schedules are interpreted
|
||||
// Default: time.Local
|
||||
//
|
||||
// Parser
|
||||
// Description: Parser converts cron spec strings into cron.Schedules.
|
||||
// Default: Accepts this spec: https://en.wikipedia.org/wiki/Cron
|
||||
//
|
||||
// Chain
|
||||
// Description: Wrap submitted jobs to customize behavior.
|
||||
// Default: A chain that recovers panics and logs them to stderr.
|
||||
//
|
||||
// See "cron.With*" to modify the default behavior.
|
||||
func New(opts ...Option) *Cron {
|
||||
c := &Cron{
|
||||
entries: nil,
|
||||
chain: NewChain(),
|
||||
add: make(chan *Entry),
|
||||
stop: make(chan struct{}),
|
||||
snapshot: make(chan chan []Entry),
|
||||
remove: make(chan EntryID),
|
||||
running: false,
|
||||
runningMu: sync.Mutex{},
|
||||
logger: DefaultLogger,
|
||||
location: time.Local,
|
||||
parser: standardParser,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(c)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// FuncJob is a wrapper that turns a func() into a cron.Job
|
||||
type FuncJob func()
|
||||
|
||||
func (f FuncJob) Run() { f() }
|
||||
|
||||
// AddFunc adds a func to the Cron to be run on the given schedule.
|
||||
// The spec is parsed using the time zone of this Cron instance as the default.
|
||||
// An opaque ID is returned that can be used to later remove it.
|
||||
func (c *Cron) AddFunc(spec string, cmd func()) (EntryID, error) {
|
||||
return c.AddJob(spec, FuncJob(cmd))
|
||||
}
|
||||
|
||||
// AddJob adds a Job to the Cron to be run on the given schedule.
|
||||
// The spec is parsed using the time zone of this Cron instance as the default.
|
||||
// An opaque ID is returned that can be used to later remove it.
|
||||
func (c *Cron) AddJob(spec string, cmd Job) (EntryID, error) {
|
||||
schedule, err := c.parser.Parse(spec)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return c.Schedule(schedule, cmd), nil
|
||||
}
|
||||
|
||||
// Schedule adds a Job to the Cron to be run on the given schedule.
|
||||
// The job is wrapped with the configured Chain.
|
||||
func (c *Cron) Schedule(schedule Schedule, cmd Job) EntryID {
|
||||
c.runningMu.Lock()
|
||||
defer c.runningMu.Unlock()
|
||||
c.nextID++
|
||||
entry := &Entry{
|
||||
ID: c.nextID,
|
||||
Schedule: schedule,
|
||||
WrappedJob: c.chain.Then(cmd),
|
||||
Job: cmd,
|
||||
}
|
||||
if !c.running {
|
||||
c.entries = append(c.entries, entry)
|
||||
} else {
|
||||
c.add <- entry
|
||||
}
|
||||
return entry.ID
|
||||
}
|
||||
|
||||
// Entries returns a snapshot of the cron entries.
|
||||
func (c *Cron) Entries() []Entry {
|
||||
c.runningMu.Lock()
|
||||
defer c.runningMu.Unlock()
|
||||
if c.running {
|
||||
replyChan := make(chan []Entry, 1)
|
||||
c.snapshot <- replyChan
|
||||
return <-replyChan
|
||||
}
|
||||
return c.entrySnapshot()
|
||||
}
|
||||
|
||||
// Location gets the time zone location
|
||||
func (c *Cron) Location() *time.Location {
|
||||
return c.location
|
||||
}
|
||||
|
||||
// Entry returns a snapshot of the given entry, or nil if it couldn't be found.
|
||||
func (c *Cron) Entry(id EntryID) Entry {
|
||||
for _, entry := range c.Entries() {
|
||||
if id == entry.ID {
|
||||
return entry
|
||||
}
|
||||
}
|
||||
return Entry{}
|
||||
}
|
||||
|
||||
// Remove an entry from being run in the future.
|
||||
func (c *Cron) Remove(id EntryID) {
|
||||
c.runningMu.Lock()
|
||||
defer c.runningMu.Unlock()
|
||||
if c.running {
|
||||
c.remove <- id
|
||||
} else {
|
||||
c.removeEntry(id)
|
||||
}
|
||||
}
|
||||
|
||||
// Start the cron scheduler in its own goroutine, or no-op if already started.
|
||||
func (c *Cron) Start() {
|
||||
c.runningMu.Lock()
|
||||
defer c.runningMu.Unlock()
|
||||
if c.running {
|
||||
return
|
||||
}
|
||||
c.running = true
|
||||
go c.run()
|
||||
}
|
||||
|
||||
// Run the cron scheduler, or no-op if already running.
|
||||
func (c *Cron) Run() {
|
||||
c.runningMu.Lock()
|
||||
if c.running {
|
||||
c.runningMu.Unlock()
|
||||
return
|
||||
}
|
||||
c.running = true
|
||||
c.runningMu.Unlock()
|
||||
c.run()
|
||||
}
|
||||
|
||||
// run the scheduler.. this is private just due to the need to synchronize
|
||||
// access to the 'running' state variable.
|
||||
func (c *Cron) run() {
|
||||
c.logger.Info("start")
|
||||
|
||||
// Figure out the next activation times for each entry.
|
||||
now := c.now()
|
||||
for _, entry := range c.entries {
|
||||
entry.Next = entry.Schedule.Next(now)
|
||||
c.logger.Info("schedule", "now", now, "entry", entry.ID, "next", entry.Next)
|
||||
}
|
||||
|
||||
for {
|
||||
// Determine the next entry to run.
|
||||
sort.Sort(byTime(c.entries))
|
||||
|
||||
var timer *time.Timer
|
||||
if len(c.entries) == 0 || c.entries[0].Next.IsZero() {
|
||||
// If there are no entries yet, just sleep - it still handles new entries
|
||||
// and stop requests.
|
||||
timer = time.NewTimer(100000 * time.Hour)
|
||||
} else {
|
||||
timer = time.NewTimer(c.entries[0].Next.Sub(now))
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case now = <-timer.C:
|
||||
now = now.In(c.location)
|
||||
c.logger.Info("wake", "now", now)
|
||||
|
||||
// Run every entry whose next time was less than now
|
||||
for _, e := range c.entries {
|
||||
if e.Next.After(now) || e.Next.IsZero() {
|
||||
break
|
||||
}
|
||||
c.startJob(e.WrappedJob)
|
||||
e.Prev = e.Next
|
||||
e.Next = e.Schedule.Next(now)
|
||||
c.logger.Info("run", "now", now, "entry", e.ID, "next", e.Next)
|
||||
}
|
||||
|
||||
case newEntry := <-c.add:
|
||||
timer.Stop()
|
||||
now = c.now()
|
||||
newEntry.Next = newEntry.Schedule.Next(now)
|
||||
c.entries = append(c.entries, newEntry)
|
||||
c.logger.Info("added", "now", now, "entry", newEntry.ID, "next", newEntry.Next)
|
||||
|
||||
case replyChan := <-c.snapshot:
|
||||
replyChan <- c.entrySnapshot()
|
||||
continue
|
||||
|
||||
case <-c.stop:
|
||||
timer.Stop()
|
||||
c.logger.Info("stop")
|
||||
return
|
||||
|
||||
case id := <-c.remove:
|
||||
timer.Stop()
|
||||
now = c.now()
|
||||
c.removeEntry(id)
|
||||
c.logger.Info("removed", "entry", id)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// startJob runs the given job in a new goroutine.
|
||||
func (c *Cron) startJob(j Job) {
|
||||
c.jobWaiter.Add(1)
|
||||
go func() {
|
||||
defer c.jobWaiter.Done()
|
||||
j.Run()
|
||||
}()
|
||||
}
|
||||
|
||||
// now returns current time in c location
|
||||
func (c *Cron) now() time.Time {
|
||||
return time.Now().In(c.location)
|
||||
}
|
||||
|
||||
// Stop stops the cron scheduler if it is running; otherwise it does nothing.
|
||||
// A context is returned so the caller can wait for running jobs to complete.
|
||||
func (c *Cron) Stop() context.Context {
|
||||
c.runningMu.Lock()
|
||||
defer c.runningMu.Unlock()
|
||||
if c.running {
|
||||
c.stop <- struct{}{}
|
||||
c.running = false
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
c.jobWaiter.Wait()
|
||||
cancel()
|
||||
}()
|
||||
return ctx
|
||||
}
|
||||
|
||||
// entrySnapshot returns a copy of the current cron entry list.
|
||||
func (c *Cron) entrySnapshot() []Entry {
|
||||
var entries = make([]Entry, len(c.entries))
|
||||
for i, e := range c.entries {
|
||||
entries[i] = *e
|
||||
}
|
||||
return entries
|
||||
}
|
||||
|
||||
func (c *Cron) removeEntry(id EntryID) {
|
||||
var entries []*Entry
|
||||
for _, e := range c.entries {
|
||||
if e.ID != id {
|
||||
entries = append(entries, e)
|
||||
}
|
||||
}
|
||||
c.entries = entries
|
||||
}
|
||||
702
src/server/cron/cron_test.go
Normal file
702
src/server/cron/cron_test.go
Normal file
@ -0,0 +1,702 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Many tests schedule a job for every second, and then wait at most a second
|
||||
// for it to run. This amount is just slightly larger than 1 second to
|
||||
// compensate for a few milliseconds of runtime.
|
||||
const OneSecond = 1*time.Second + 50*time.Millisecond
|
||||
|
||||
type syncWriter struct {
|
||||
wr bytes.Buffer
|
||||
m sync.Mutex
|
||||
}
|
||||
|
||||
func (sw *syncWriter) Write(data []byte) (n int, err error) {
|
||||
sw.m.Lock()
|
||||
n, err = sw.wr.Write(data)
|
||||
sw.m.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (sw *syncWriter) String() string {
|
||||
sw.m.Lock()
|
||||
defer sw.m.Unlock()
|
||||
return sw.wr.String()
|
||||
}
|
||||
|
||||
func newBufLogger(sw *syncWriter) Logger {
|
||||
return PrintfLogger(log.New(sw, "", log.LstdFlags))
|
||||
}
|
||||
|
||||
func TestFuncPanicRecovery(t *testing.T) {
|
||||
var buf syncWriter
|
||||
cron := New(WithParser(secondParser),
|
||||
WithChain(Recover(newBufLogger(&buf))))
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
cron.AddFunc("* * * * * ?", func() {
|
||||
panic("YOLO")
|
||||
})
|
||||
|
||||
select {
|
||||
case <-time.After(OneSecond):
|
||||
if !strings.Contains(buf.String(), "YOLO") {
|
||||
t.Error("expected a panic to be logged, got none")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type DummyJob struct{}
|
||||
|
||||
func (d DummyJob) Run() {
|
||||
panic("YOLO")
|
||||
}
|
||||
|
||||
func TestJobPanicRecovery(t *testing.T) {
|
||||
var job DummyJob
|
||||
|
||||
var buf syncWriter
|
||||
cron := New(WithParser(secondParser),
|
||||
WithChain(Recover(newBufLogger(&buf))))
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
cron.AddJob("* * * * * ?", job)
|
||||
|
||||
select {
|
||||
case <-time.After(OneSecond):
|
||||
if !strings.Contains(buf.String(), "YOLO") {
|
||||
t.Error("expected a panic to be logged, got none")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Start and stop cron with no entries.
|
||||
func TestNoEntries(t *testing.T) {
|
||||
cron := newWithSeconds()
|
||||
cron.Start()
|
||||
|
||||
select {
|
||||
case <-time.After(OneSecond):
|
||||
t.Fatal("expected cron will be stopped immediately")
|
||||
case <-stop(cron):
|
||||
}
|
||||
}
|
||||
|
||||
// Start, stop, then add an entry. Verify entry doesn't run.
|
||||
func TestStopCausesJobsToNotRun(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
cron := newWithSeconds()
|
||||
cron.Start()
|
||||
cron.Stop()
|
||||
cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||
|
||||
select {
|
||||
case <-time.After(OneSecond):
|
||||
// No job ran!
|
||||
case <-wait(wg):
|
||||
t.Fatal("expected stopped cron does not run any job")
|
||||
}
|
||||
}
|
||||
|
||||
// Add a job, start cron, expect it runs.
|
||||
func TestAddBeforeRunning(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
cron := newWithSeconds()
|
||||
cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
// Give cron 2 seconds to run our job (which is always activated).
|
||||
select {
|
||||
case <-time.After(OneSecond):
|
||||
t.Fatal("expected job runs")
|
||||
case <-wait(wg):
|
||||
}
|
||||
}
|
||||
|
||||
// Start cron, add a job, expect it runs.
|
||||
func TestAddWhileRunning(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
cron := newWithSeconds()
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||
|
||||
select {
|
||||
case <-time.After(OneSecond):
|
||||
t.Fatal("expected job runs")
|
||||
case <-wait(wg):
|
||||
}
|
||||
}
|
||||
|
||||
// Test for #34. Adding a job after calling start results in multiple job invocations
|
||||
func TestAddWhileRunningWithDelay(t *testing.T) {
|
||||
cron := newWithSeconds()
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
time.Sleep(5 * time.Second)
|
||||
var calls int64
|
||||
cron.AddFunc("* * * * * *", func() { atomic.AddInt64(&calls, 1) })
|
||||
|
||||
<-time.After(OneSecond)
|
||||
if atomic.LoadInt64(&calls) != 1 {
|
||||
t.Errorf("called %d times, expected 1\n", calls)
|
||||
}
|
||||
}
|
||||
|
||||
// Add a job, remove a job, start cron, expect nothing runs.
|
||||
func TestRemoveBeforeRunning(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
cron := newWithSeconds()
|
||||
id, _ := cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||
cron.Remove(id)
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
select {
|
||||
case <-time.After(OneSecond):
|
||||
// Success, shouldn't run
|
||||
case <-wait(wg):
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// Start cron, add a job, remove it, expect it doesn't run.
|
||||
func TestRemoveWhileRunning(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
cron := newWithSeconds()
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
id, _ := cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||
cron.Remove(id)
|
||||
|
||||
select {
|
||||
case <-time.After(OneSecond):
|
||||
case <-wait(wg):
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
// Test timing with Entries.
|
||||
func TestSnapshotEntries(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
cron := New()
|
||||
cron.AddFunc("@every 2s", func() { wg.Done() })
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
// Cron should fire in 2 seconds. After 1 second, call Entries.
|
||||
select {
|
||||
case <-time.After(OneSecond):
|
||||
cron.Entries()
|
||||
}
|
||||
|
||||
// Even though Entries was called, the cron should fire at the 2 second mark.
|
||||
select {
|
||||
case <-time.After(OneSecond):
|
||||
t.Error("expected job runs at 2 second mark")
|
||||
case <-wait(wg):
|
||||
}
|
||||
}
|
||||
|
||||
// Test that the entries are correctly sorted.
|
||||
// Add a bunch of long-in-the-future entries, and an immediate entry, and ensure
|
||||
// that the immediate entry runs immediately.
|
||||
// Also: Test that multiple jobs run in the same instant.
|
||||
func TestMultipleEntries(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
|
||||
cron := newWithSeconds()
|
||||
cron.AddFunc("0 0 0 1 1 ?", func() {})
|
||||
cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||
id1, _ := cron.AddFunc("* * * * * ?", func() { t.Fatal() })
|
||||
id2, _ := cron.AddFunc("* * * * * ?", func() { t.Fatal() })
|
||||
cron.AddFunc("0 0 0 31 12 ?", func() {})
|
||||
cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||
|
||||
cron.Remove(id1)
|
||||
cron.Start()
|
||||
cron.Remove(id2)
|
||||
defer cron.Stop()
|
||||
|
||||
select {
|
||||
case <-time.After(OneSecond):
|
||||
t.Error("expected job run in proper order")
|
||||
case <-wait(wg):
|
||||
}
|
||||
}
|
||||
|
||||
// Test running the same job twice.
|
||||
func TestRunningJobTwice(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
|
||||
cron := newWithSeconds()
|
||||
cron.AddFunc("0 0 0 1 1 ?", func() {})
|
||||
cron.AddFunc("0 0 0 31 12 ?", func() {})
|
||||
cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
select {
|
||||
case <-time.After(2 * OneSecond):
|
||||
t.Error("expected job fires 2 times")
|
||||
case <-wait(wg):
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunningMultipleSchedules(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
|
||||
cron := newWithSeconds()
|
||||
cron.AddFunc("0 0 0 1 1 ?", func() {})
|
||||
cron.AddFunc("0 0 0 31 12 ?", func() {})
|
||||
cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||
cron.Schedule(Every(time.Minute), FuncJob(func() {}))
|
||||
cron.Schedule(Every(time.Second), FuncJob(func() { wg.Done() }))
|
||||
cron.Schedule(Every(time.Hour), FuncJob(func() {}))
|
||||
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
select {
|
||||
case <-time.After(2 * OneSecond):
|
||||
t.Error("expected job fires 2 times")
|
||||
case <-wait(wg):
|
||||
}
|
||||
}
|
||||
|
||||
// Test that the cron is run in the local time zone (as opposed to UTC).
|
||||
func TestLocalTimezone(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
|
||||
now := time.Now()
|
||||
// FIX: Issue #205
|
||||
// This calculation doesn't work in seconds 58 or 59.
|
||||
// Take the easy way out and sleep.
|
||||
if now.Second() >= 58 {
|
||||
time.Sleep(2 * time.Second)
|
||||
now = time.Now()
|
||||
}
|
||||
spec := fmt.Sprintf("%d,%d %d %d %d %d ?",
|
||||
now.Second()+1, now.Second()+2, now.Minute(), now.Hour(), now.Day(), now.Month())
|
||||
|
||||
cron := newWithSeconds()
|
||||
cron.AddFunc(spec, func() { wg.Done() })
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
select {
|
||||
case <-time.After(OneSecond * 2):
|
||||
t.Error("expected job fires 2 times")
|
||||
case <-wait(wg):
|
||||
}
|
||||
}
|
||||
|
||||
// Test that the cron is run in the given time zone (as opposed to local).
|
||||
func TestNonLocalTimezone(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
|
||||
loc, err := time.LoadLocation("Atlantic/Cape_Verde")
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to load time zone Atlantic/Cape_Verde: %+v", err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
now := time.Now().In(loc)
|
||||
// FIX: Issue #205
|
||||
// This calculation doesn't work in seconds 58 or 59.
|
||||
// Take the easy way out and sleep.
|
||||
if now.Second() >= 58 {
|
||||
time.Sleep(2 * time.Second)
|
||||
now = time.Now().In(loc)
|
||||
}
|
||||
spec := fmt.Sprintf("%d,%d %d %d %d %d ?",
|
||||
now.Second()+1, now.Second()+2, now.Minute(), now.Hour(), now.Day(), now.Month())
|
||||
|
||||
cron := New(WithLocation(loc), WithParser(secondParser))
|
||||
cron.AddFunc(spec, func() { wg.Done() })
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
select {
|
||||
case <-time.After(OneSecond * 2):
|
||||
t.Error("expected job fires 2 times")
|
||||
case <-wait(wg):
|
||||
}
|
||||
}
|
||||
|
||||
// Test that calling stop before start silently returns without
|
||||
// blocking the stop channel.
|
||||
func TestStopWithoutStart(t *testing.T) {
|
||||
cron := New()
|
||||
cron.Stop()
|
||||
}
|
||||
|
||||
type testJob struct {
|
||||
wg *sync.WaitGroup
|
||||
name string
|
||||
}
|
||||
|
||||
func (t testJob) Run() {
|
||||
t.wg.Done()
|
||||
}
|
||||
|
||||
// Test that adding an invalid job spec returns an error
|
||||
func TestInvalidJobSpec(t *testing.T) {
|
||||
cron := New()
|
||||
_, err := cron.AddJob("this will not parse", nil)
|
||||
if err == nil {
|
||||
t.Errorf("expected an error with invalid spec, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
// Test blocking run method behaves as Start()
|
||||
func TestBlockingRun(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
cron := newWithSeconds()
|
||||
cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||
|
||||
var unblockChan = make(chan struct{})
|
||||
|
||||
go func() {
|
||||
cron.Run()
|
||||
close(unblockChan)
|
||||
}()
|
||||
defer cron.Stop()
|
||||
|
||||
select {
|
||||
case <-time.After(OneSecond):
|
||||
t.Error("expected job fires")
|
||||
case <-unblockChan:
|
||||
t.Error("expected that Run() blocks")
|
||||
case <-wait(wg):
|
||||
}
|
||||
}
|
||||
|
||||
// Test that double-running is a no-op
|
||||
func TestStartNoop(t *testing.T) {
|
||||
var tickChan = make(chan struct{}, 2)
|
||||
|
||||
cron := newWithSeconds()
|
||||
cron.AddFunc("* * * * * ?", func() {
|
||||
tickChan <- struct{}{}
|
||||
})
|
||||
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
// Wait for the first firing to ensure the runner is going
|
||||
<-tickChan
|
||||
|
||||
cron.Start()
|
||||
|
||||
<-tickChan
|
||||
|
||||
// Fail if this job fires again in a short period, indicating a double-run
|
||||
select {
|
||||
case <-time.After(time.Millisecond):
|
||||
case <-tickChan:
|
||||
t.Error("expected job fires exactly twice")
|
||||
}
|
||||
}
|
||||
|
||||
// Simple test using Runnables.
|
||||
func TestJob(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
cron := newWithSeconds()
|
||||
cron.AddJob("0 0 0 30 Feb ?", testJob{wg, "job0"})
|
||||
cron.AddJob("0 0 0 1 1 ?", testJob{wg, "job1"})
|
||||
job2, _ := cron.AddJob("* * * * * ?", testJob{wg, "job2"})
|
||||
cron.AddJob("1 0 0 1 1 ?", testJob{wg, "job3"})
|
||||
cron.Schedule(Every(5*time.Second+5*time.Nanosecond), testJob{wg, "job4"})
|
||||
job5 := cron.Schedule(Every(5*time.Minute), testJob{wg, "job5"})
|
||||
|
||||
// Test getting an Entry pre-Start.
|
||||
if actualName := cron.Entry(job2).Job.(testJob).name; actualName != "job2" {
|
||||
t.Error("wrong job retrieved:", actualName)
|
||||
}
|
||||
if actualName := cron.Entry(job5).Job.(testJob).name; actualName != "job5" {
|
||||
t.Error("wrong job retrieved:", actualName)
|
||||
}
|
||||
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
select {
|
||||
case <-time.After(OneSecond):
|
||||
t.FailNow()
|
||||
case <-wait(wg):
|
||||
}
|
||||
|
||||
// Ensure the entries are in the right order.
|
||||
expecteds := []string{"job2", "job4", "job5", "job1", "job3", "job0"}
|
||||
|
||||
var actuals []string
|
||||
for _, entry := range cron.Entries() {
|
||||
actuals = append(actuals, entry.Job.(testJob).name)
|
||||
}
|
||||
|
||||
for i, expected := range expecteds {
|
||||
if actuals[i] != expected {
|
||||
t.Fatalf("Jobs not in the right order. (expected) %s != %s (actual)", expecteds, actuals)
|
||||
}
|
||||
}
|
||||
|
||||
// Test getting Entries.
|
||||
if actualName := cron.Entry(job2).Job.(testJob).name; actualName != "job2" {
|
||||
t.Error("wrong job retrieved:", actualName)
|
||||
}
|
||||
if actualName := cron.Entry(job5).Job.(testJob).name; actualName != "job5" {
|
||||
t.Error("wrong job retrieved:", actualName)
|
||||
}
|
||||
}
|
||||
|
||||
// Issue #206
|
||||
// Ensure that the next run of a job after removing an entry is accurate.
|
||||
func TestScheduleAfterRemoval(t *testing.T) {
|
||||
var wg1 sync.WaitGroup
|
||||
var wg2 sync.WaitGroup
|
||||
wg1.Add(1)
|
||||
wg2.Add(1)
|
||||
|
||||
// The first time this job is run, set a timer and remove the other job
|
||||
// 750ms later. Correct behavior would be to still run the job again in
|
||||
// 250ms, but the bug would cause it to run instead 1s later.
|
||||
|
||||
var calls int
|
||||
var mu sync.Mutex
|
||||
|
||||
cron := newWithSeconds()
|
||||
hourJob := cron.Schedule(Every(time.Hour), FuncJob(func() {}))
|
||||
cron.Schedule(Every(time.Second), FuncJob(func() {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
switch calls {
|
||||
case 0:
|
||||
wg1.Done()
|
||||
calls++
|
||||
case 1:
|
||||
time.Sleep(750 * time.Millisecond)
|
||||
cron.Remove(hourJob)
|
||||
calls++
|
||||
case 2:
|
||||
calls++
|
||||
wg2.Done()
|
||||
case 3:
|
||||
panic("unexpected 3rd call")
|
||||
}
|
||||
}))
|
||||
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
|
||||
// the first run might be any length of time 0 - 1s, since the schedule
|
||||
// rounds to the second. wait for the first run to true up.
|
||||
wg1.Wait()
|
||||
|
||||
select {
|
||||
case <-time.After(2 * OneSecond):
|
||||
t.Error("expected job fires 2 times")
|
||||
case <-wait(&wg2):
|
||||
}
|
||||
}
|
||||
|
||||
type ZeroSchedule struct{}
|
||||
|
||||
func (*ZeroSchedule) Next(time.Time) time.Time {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
// Tests that job without time does not run
|
||||
func TestJobWithZeroTimeDoesNotRun(t *testing.T) {
|
||||
cron := newWithSeconds()
|
||||
var calls int64
|
||||
cron.AddFunc("* * * * * *", func() { atomic.AddInt64(&calls, 1) })
|
||||
cron.Schedule(new(ZeroSchedule), FuncJob(func() { t.Error("expected zero task will not run") }))
|
||||
cron.Start()
|
||||
defer cron.Stop()
|
||||
<-time.After(OneSecond)
|
||||
if atomic.LoadInt64(&calls) != 1 {
|
||||
t.Errorf("called %d times, expected 1\n", calls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStopAndWait(t *testing.T) {
|
||||
t.Run("nothing running, returns immediately", func(t *testing.T) {
|
||||
cron := newWithSeconds()
|
||||
cron.Start()
|
||||
ctx := cron.Stop()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-time.After(time.Millisecond):
|
||||
t.Error("context was not done immediately")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("repeated calls to Stop", func(t *testing.T) {
|
||||
cron := newWithSeconds()
|
||||
cron.Start()
|
||||
_ = cron.Stop()
|
||||
time.Sleep(time.Millisecond)
|
||||
ctx := cron.Stop()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-time.After(time.Millisecond):
|
||||
t.Error("context was not done immediately")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("a couple fast jobs added, still returns immediately", func(t *testing.T) {
|
||||
cron := newWithSeconds()
|
||||
cron.AddFunc("* * * * * *", func() {})
|
||||
cron.Start()
|
||||
cron.AddFunc("* * * * * *", func() {})
|
||||
cron.AddFunc("* * * * * *", func() {})
|
||||
cron.AddFunc("* * * * * *", func() {})
|
||||
time.Sleep(time.Second)
|
||||
ctx := cron.Stop()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-time.After(time.Millisecond):
|
||||
t.Error("context was not done immediately")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("a couple fast jobs and a slow job added, waits for slow job", func(t *testing.T) {
|
||||
cron := newWithSeconds()
|
||||
cron.AddFunc("* * * * * *", func() {})
|
||||
cron.Start()
|
||||
cron.AddFunc("* * * * * *", func() { time.Sleep(2 * time.Second) })
|
||||
cron.AddFunc("* * * * * *", func() {})
|
||||
time.Sleep(time.Second)
|
||||
|
||||
ctx := cron.Stop()
|
||||
|
||||
// Verify that it is not done for at least 750ms
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
t.Error("context was done too quickly immediately")
|
||||
case <-time.After(750 * time.Millisecond):
|
||||
// expected, because the job sleeping for 1 second is still running
|
||||
}
|
||||
|
||||
// Verify that it IS done in the next 500ms (giving 250ms buffer)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// expected
|
||||
case <-time.After(1500 * time.Millisecond):
|
||||
t.Error("context not done after job should have completed")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("repeated calls to stop, waiting for completion and after", func(t *testing.T) {
|
||||
cron := newWithSeconds()
|
||||
cron.AddFunc("* * * * * *", func() {})
|
||||
cron.AddFunc("* * * * * *", func() { time.Sleep(2 * time.Second) })
|
||||
cron.Start()
|
||||
cron.AddFunc("* * * * * *", func() {})
|
||||
time.Sleep(time.Second)
|
||||
ctx := cron.Stop()
|
||||
ctx2 := cron.Stop()
|
||||
|
||||
// Verify that it is not done for at least 1500ms
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
t.Error("context was done too quickly immediately")
|
||||
case <-ctx2.Done():
|
||||
t.Error("context2 was done too quickly immediately")
|
||||
case <-time.After(1500 * time.Millisecond):
|
||||
// expected, because the job sleeping for 2 seconds is still running
|
||||
}
|
||||
|
||||
// Verify that it IS done in the next 1s (giving 500ms buffer)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// expected
|
||||
case <-time.After(time.Second):
|
||||
t.Error("context not done after job should have completed")
|
||||
}
|
||||
|
||||
// Verify that ctx2 is also done.
|
||||
select {
|
||||
case <-ctx2.Done():
|
||||
// expected
|
||||
case <-time.After(time.Millisecond):
|
||||
t.Error("context2 not done even though context1 is")
|
||||
}
|
||||
|
||||
// Verify that a new context retrieved from stop is immediately done.
|
||||
ctx3 := cron.Stop()
|
||||
select {
|
||||
case <-ctx3.Done():
|
||||
// expected
|
||||
case <-time.After(time.Millisecond):
|
||||
t.Error("context not done even when cron Stop is completed")
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestMultiThreadedStartAndStop(t *testing.T) {
|
||||
cron := New()
|
||||
go cron.Run()
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
cron.Stop()
|
||||
}
|
||||
|
||||
func wait(wg *sync.WaitGroup) chan bool {
|
||||
ch := make(chan bool)
|
||||
go func() {
|
||||
wg.Wait()
|
||||
ch <- true
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
func stop(cron *Cron) chan bool {
|
||||
ch := make(chan bool)
|
||||
go func() {
|
||||
cron.Stop()
|
||||
ch <- true
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
// newWithSeconds returns a Cron with the seconds field enabled.
|
||||
func newWithSeconds() *Cron {
|
||||
return New(WithParser(secondParser), WithChain())
|
||||
}
|
||||
212
src/server/cron/doc.go
Normal file
212
src/server/cron/doc.go
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
Package cron implements a cron spec parser and job runner.
|
||||
|
||||
Usage
|
||||
|
||||
Callers may register Funcs to be invoked on a given schedule. Cron will run
|
||||
them in their own goroutines.
|
||||
|
||||
c := cron.New()
|
||||
c.AddFunc("30 * * * *", func() { fmt.Println("Every hour on the half hour") })
|
||||
c.AddFunc("30 3-6,20-23 * * *", func() { fmt.Println(".. in the range 3-6am, 8-11pm") })
|
||||
c.AddFunc("CRON_TZ=Asia/Tokyo 30 04 * * * *", func() { fmt.Println("Runs at 04:30 Tokyo time every day") })
|
||||
c.AddFunc("@hourly", func() { fmt.Println("Every hour, starting an hour from now") })
|
||||
c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty, starting an hour thirty from now") })
|
||||
c.Start()
|
||||
..
|
||||
// Funcs are invoked in their own goroutine, asynchronously.
|
||||
...
|
||||
// Funcs may also be added to a running Cron
|
||||
c.AddFunc("@daily", func() { fmt.Println("Every day") })
|
||||
..
|
||||
// Inspect the cron job entries' next and previous run times.
|
||||
inspect(c.Entries())
|
||||
..
|
||||
c.Stop() // Stop the scheduler (does not stop any jobs already running).
|
||||
|
||||
CRON Expression Format
|
||||
|
||||
A cron expression represents a set of times, using 5 space-separated fields.
|
||||
|
||||
Field name | Mandatory? | Allowed values | Allowed special characters
|
||||
---------- | ---------- | -------------- | --------------------------
|
||||
Minutes | Yes | 0-59 | * / , -
|
||||
Hours | Yes | 0-23 | * / , -
|
||||
Day of month | Yes | 1-31 | * / , - ?
|
||||
Month | Yes | 1-12 or JAN-DEC | * / , -
|
||||
Day of week | Yes | 0-6 or SUN-SAT | * / , - ?
|
||||
|
||||
Month and Day-of-week field values are case insensitive. "SUN", "Sun", and
|
||||
"sun" are equally accepted.
|
||||
|
||||
The specific interpretation of the format is based on the Cron Wikipedia page:
|
||||
https://en.wikipedia.org/wiki/Cron
|
||||
|
||||
Alternative Formats
|
||||
|
||||
Alternative Cron expression formats support other fields like seconds. You can
|
||||
implement that by creating a custom Parser as follows.
|
||||
|
||||
cron.New(
|
||||
cron.WithParser(
|
||||
cron.SecondOptional | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor))
|
||||
|
||||
The most popular alternative Cron expression format is Quartz:
|
||||
http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/crontrigger.html
|
||||
|
||||
Special Characters
|
||||
|
||||
Asterisk ( * )
|
||||
|
||||
The asterisk indicates that the cron expression will match for all values of the
|
||||
field; e.g., using an asterisk in the 5th field (month) would indicate every
|
||||
month.
|
||||
|
||||
Slash ( / )
|
||||
|
||||
Slashes are used to describe increments of ranges. For example 3-59/15 in the
|
||||
1st field (minutes) would indicate the 3rd minute of the hour and every 15
|
||||
minutes thereafter. The form "*\/..." is equivalent to the form "first-last/...",
|
||||
that is, an increment over the largest possible range of the field. The form
|
||||
"N/..." is accepted as meaning "N-MAX/...", that is, starting at N, use the
|
||||
increment until the end of that specific range. It does not wrap around.
|
||||
|
||||
Comma ( , )
|
||||
|
||||
Commas are used to separate items of a list. For example, using "MON,WED,FRI" in
|
||||
the 5th field (day of week) would mean Mondays, Wednesdays and Fridays.
|
||||
|
||||
Hyphen ( - )
|
||||
|
||||
Hyphens are used to define ranges. For example, 9-17 would indicate every
|
||||
hour between 9am and 5pm inclusive.
|
||||
|
||||
Question mark ( ? )
|
||||
|
||||
Question mark may be used instead of '*' for leaving either day-of-month or
|
||||
day-of-week blank.
|
||||
|
||||
Predefined schedules
|
||||
|
||||
You may use one of several pre-defined schedules in place of a cron expression.
|
||||
|
||||
Entry | Description | Equivalent To
|
||||
----- | ----------- | -------------
|
||||
@yearly (or @annually) | Run once a year, midnight, Jan. 1st | 0 0 1 1 *
|
||||
@monthly | Run once a month, midnight, first of month | 0 0 1 * *
|
||||
@weekly | Run once a week, midnight between Sat/Sun | 0 0 * * 0
|
||||
@daily (or @midnight) | Run once a day, midnight | 0 0 * * *
|
||||
@hourly | Run once an hour, beginning of hour | 0 * * * *
|
||||
|
||||
Intervals
|
||||
|
||||
You may also schedule a job to execute at fixed intervals, starting at the time it's added
|
||||
or cron is run. This is supported by formatting the cron spec like this:
|
||||
|
||||
@every <duration>
|
||||
|
||||
where "duration" is a string accepted by time.ParseDuration
|
||||
(http://golang.org/pkg/time/#ParseDuration).
|
||||
|
||||
For example, "@every 1h30m10s" would indicate a schedule that activates after
|
||||
1 hour, 30 minutes, 10 seconds, and then every interval after that.
|
||||
|
||||
Note: The interval does not take the job runtime into account. For example,
|
||||
if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes,
|
||||
it will have only 2 minutes of idle time between each run.
|
||||
|
||||
Time zones
|
||||
|
||||
By default, all interpretation and scheduling is done in the machine's local
|
||||
time zone (time.Local). You can specify a different time zone on construction:
|
||||
|
||||
cron.New(
|
||||
cron.WithLocation(time.UTC))
|
||||
|
||||
Individual cron schedules may also override the time zone they are to be
|
||||
interpreted in by providing an additional space-separated field at the beginning
|
||||
of the cron spec, of the form "CRON_TZ=Asia/Tokyo".
|
||||
|
||||
For example:
|
||||
|
||||
# Runs at 6am in time.Local
|
||||
cron.New().AddFunc("0 6 * * ?", ...)
|
||||
|
||||
# Runs at 6am in America/New_York
|
||||
nyc, _ := time.LoadLocation("America/New_York")
|
||||
c := cron.New(cron.WithLocation(nyc))
|
||||
c.AddFunc("0 6 * * ?", ...)
|
||||
|
||||
# Runs at 6am in Asia/Tokyo
|
||||
cron.New().AddFunc("CRON_TZ=Asia/Tokyo 0 6 * * ?", ...)
|
||||
|
||||
# Runs at 6am in Asia/Tokyo
|
||||
c := cron.New(cron.WithLocation(nyc))
|
||||
c.SetLocation("America/New_York")
|
||||
c.AddFunc("CRON_TZ=Asia/Tokyo 0 6 * * ?", ...)
|
||||
|
||||
The prefix "TZ=(TIME ZONE)" is also supported for legacy compatibility.
|
||||
|
||||
Be aware that jobs scheduled during daylight-savings leap-ahead transitions will
|
||||
not be run!
|
||||
|
||||
Job Wrappers / Chain
|
||||
|
||||
A Cron runner may be configured with a chain of job wrappers to add
|
||||
cross-cutting functionality to all submitted jobs. For example, they may be used
|
||||
to achieve the following effects:
|
||||
|
||||
- Recover any panics from jobs (activated by default)
|
||||
- Delay a job's execution if the previous run hasn't completed yet
|
||||
- Skip a job's execution if the previous run hasn't completed yet
|
||||
- Log each job's invocations
|
||||
|
||||
Install wrappers for all jobs added to a cron using the `cron.WithChain` option:
|
||||
|
||||
cron.New(cron.WithChain(
|
||||
cron.SkipIfStillRunning(logger),
|
||||
))
|
||||
|
||||
Install wrappers for individual jobs by explicitly wrapping them:
|
||||
|
||||
job = cron.NewChain(
|
||||
cron.SkipIfStillRunning(logger),
|
||||
).Then(job)
|
||||
|
||||
Thread safety
|
||||
|
||||
Since the Cron service runs concurrently with the calling code, some amount of
|
||||
care must be taken to ensure proper synchronization.
|
||||
|
||||
All cron methods are designed to be correctly synchronized as long as the caller
|
||||
ensures that invocations have a clear happens-before ordering between them.
|
||||
|
||||
Logging
|
||||
|
||||
Cron defines a Logger interface that is a subset of the one defined in
|
||||
github.com/go-logr/logr. It has two logging levels (Info and Error), and
|
||||
parameters are key/value pairs. This makes it possible for cron logging to plug
|
||||
into structured logging systems. An adapter, [Verbose]PrintfLogger, is provided
|
||||
to wrap the standard library *log.Logger.
|
||||
|
||||
For additional insight into Cron operations, verbose logging may be activated
|
||||
which will record job runs, scheduling decisions, and added or removed jobs.
|
||||
Activate it with a one-off logger as follows:
|
||||
|
||||
cron.New(
|
||||
cron.WithLogger(
|
||||
cron.VerbosePrintfLogger(log.New(os.Stdout, "cron: ", log.LstdFlags))))
|
||||
|
||||
|
||||
Implementation
|
||||
|
||||
Cron entries are stored in an array, sorted by their next activation time. Cron
|
||||
sleeps until the next job is due to be run.
|
||||
|
||||
Upon waking:
|
||||
- it runs each entry that is active on that second
|
||||
- it calculates the next run times for the jobs that were run
|
||||
- it re-sorts the array of entries by next activation time.
|
||||
- it goes to sleep until the soonest job.
|
||||
*/
|
||||
package cron
|
||||
86
src/server/cron/logger.go
Normal file
86
src/server/cron/logger.go
Normal file
@ -0,0 +1,86 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DefaultLogger is used by Cron if none is specified.
|
||||
var DefaultLogger Logger = PrintfLogger(log.New(os.Stdout, "cron: ", log.LstdFlags))
|
||||
|
||||
// DiscardLogger can be used by callers to discard all log messages.
|
||||
var DiscardLogger Logger = PrintfLogger(log.New(ioutil.Discard, "", 0))
|
||||
|
||||
// Logger is the interface used in this package for logging, so that any backend
|
||||
// can be plugged in. It is a subset of the github.com/go-logr/logr interface.
|
||||
type Logger interface {
|
||||
// Info logs routine messages about cron's operation.
|
||||
Info(msg string, keysAndValues ...interface{})
|
||||
// Error logs an error condition.
|
||||
Error(err error, msg string, keysAndValues ...interface{})
|
||||
}
|
||||
|
||||
// PrintfLogger wraps a Printf-based logger (such as the standard library "log")
|
||||
// into an implementation of the Logger interface which logs errors only.
|
||||
func PrintfLogger(l interface{ Printf(string, ...interface{}) }) Logger {
|
||||
return printfLogger{l, false}
|
||||
}
|
||||
|
||||
// VerbosePrintfLogger wraps a Printf-based logger (such as the standard library
|
||||
// "log") into an implementation of the Logger interface which logs everything.
|
||||
func VerbosePrintfLogger(l interface{ Printf(string, ...interface{}) }) Logger {
|
||||
return printfLogger{l, true}
|
||||
}
|
||||
|
||||
type printfLogger struct {
|
||||
logger interface{ Printf(string, ...interface{}) }
|
||||
logInfo bool
|
||||
}
|
||||
|
||||
func (pl printfLogger) Info(msg string, keysAndValues ...interface{}) {
|
||||
if pl.logInfo {
|
||||
keysAndValues = formatTimes(keysAndValues)
|
||||
pl.logger.Printf(
|
||||
formatString(len(keysAndValues)),
|
||||
append([]interface{}{msg}, keysAndValues...)...)
|
||||
}
|
||||
}
|
||||
|
||||
func (pl printfLogger) Error(err error, msg string, keysAndValues ...interface{}) {
|
||||
keysAndValues = formatTimes(keysAndValues)
|
||||
pl.logger.Printf(
|
||||
formatString(len(keysAndValues)+2),
|
||||
append([]interface{}{msg, "error", err}, keysAndValues...)...)
|
||||
}
|
||||
|
||||
// formatString returns a logfmt-like format string for the number of
|
||||
// key/values.
|
||||
func formatString(numKeysAndValues int) string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString("%s")
|
||||
if numKeysAndValues > 0 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
for i := 0; i < numKeysAndValues/2; i++ {
|
||||
if i > 0 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
sb.WriteString("%v=%v")
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// formatTimes formats any time.Time values as RFC3339.
|
||||
func formatTimes(keysAndValues []interface{}) []interface{} {
|
||||
var formattedArgs []interface{}
|
||||
for _, arg := range keysAndValues {
|
||||
if t, ok := arg.(time.Time); ok {
|
||||
arg = t.Format(time.RFC3339)
|
||||
}
|
||||
formattedArgs = append(formattedArgs, arg)
|
||||
}
|
||||
return formattedArgs
|
||||
}
|
||||
45
src/server/cron/option.go
Normal file
45
src/server/cron/option.go
Normal file
@ -0,0 +1,45 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Option represents a modification to the default behavior of a Cron.
|
||||
type Option func(*Cron)
|
||||
|
||||
// WithLocation overrides the timezone of the cron instance.
|
||||
func WithLocation(loc *time.Location) Option {
|
||||
return func(c *Cron) {
|
||||
c.location = loc
|
||||
}
|
||||
}
|
||||
|
||||
// WithSeconds overrides the parser used for interpreting job schedules to
|
||||
// include a seconds field as the first one.
|
||||
func WithSeconds() Option {
|
||||
return WithParser(NewParser(
|
||||
Second | Minute | Hour | Dom | Month | Dow | Descriptor,
|
||||
))
|
||||
}
|
||||
|
||||
// WithParser overrides the parser used for interpreting job schedules.
|
||||
func WithParser(p Parser) Option {
|
||||
return func(c *Cron) {
|
||||
c.parser = p
|
||||
}
|
||||
}
|
||||
|
||||
// WithChain specifies Job wrappers to apply to all jobs added to this cron.
|
||||
// Refer to the Chain* functions in this package for provided wrappers.
|
||||
func WithChain(wrappers ...JobWrapper) Option {
|
||||
return func(c *Cron) {
|
||||
c.chain = NewChain(wrappers...)
|
||||
}
|
||||
}
|
||||
|
||||
// WithLogger uses the provided logger.
|
||||
func WithLogger(logger Logger) Option {
|
||||
return func(c *Cron) {
|
||||
c.logger = logger
|
||||
}
|
||||
}
|
||||
42
src/server/cron/option_test.go
Normal file
42
src/server/cron/option_test.go
Normal file
@ -0,0 +1,42 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestWithLocation(t *testing.T) {
|
||||
c := New(WithLocation(time.UTC))
|
||||
if c.location != time.UTC {
|
||||
t.Errorf("expected UTC, got %v", c.location)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithParser(t *testing.T) {
|
||||
var parser = NewParser(Dow)
|
||||
c := New(WithParser(parser))
|
||||
if c.parser != parser {
|
||||
t.Error("expected provided parser")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithVerboseLogger(t *testing.T) {
|
||||
var buf syncWriter
|
||||
var logger = log.New(&buf, "", log.LstdFlags)
|
||||
c := New(WithLogger(VerbosePrintfLogger(logger)))
|
||||
if c.logger.(printfLogger).logger != logger {
|
||||
t.Error("expected provided logger")
|
||||
}
|
||||
|
||||
c.AddFunc("@every 1s", func() {})
|
||||
c.Start()
|
||||
time.Sleep(OneSecond)
|
||||
c.Stop()
|
||||
out := buf.String()
|
||||
if !strings.Contains(out, "schedule,") ||
|
||||
!strings.Contains(out, "run,") {
|
||||
t.Error("expected to see some actions, got:", out)
|
||||
}
|
||||
}
|
||||
434
src/server/cron/parser.go
Normal file
434
src/server/cron/parser.go
Normal file
@ -0,0 +1,434 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Configuration options for creating a parser. Most options specify which
|
||||
// fields should be included, while others enable features. If a field is not
|
||||
// included the parser will assume a default value. These options do not change
|
||||
// the order fields are parse in.
|
||||
type ParseOption int
|
||||
|
||||
const (
|
||||
Second ParseOption = 1 << iota // Seconds field, default 0
|
||||
SecondOptional // Optional seconds field, default 0
|
||||
Minute // Minutes field, default 0
|
||||
Hour // Hours field, default 0
|
||||
Dom // Day of month field, default *
|
||||
Month // Month field, default *
|
||||
Dow // Day of week field, default *
|
||||
DowOptional // Optional day of week field, default *
|
||||
Descriptor // Allow descriptors such as @monthly, @weekly, etc.
|
||||
)
|
||||
|
||||
var places = []ParseOption{
|
||||
Second,
|
||||
Minute,
|
||||
Hour,
|
||||
Dom,
|
||||
Month,
|
||||
Dow,
|
||||
}
|
||||
|
||||
var defaults = []string{
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"*",
|
||||
"*",
|
||||
"*",
|
||||
}
|
||||
|
||||
// A custom Parser that can be configured.
|
||||
type Parser struct {
|
||||
options ParseOption
|
||||
}
|
||||
|
||||
// NewParser creates a Parser with custom options.
|
||||
//
|
||||
// It panics if more than one Optional is given, since it would be impossible to
|
||||
// correctly infer which optional is provided or missing in general.
|
||||
//
|
||||
// Examples
|
||||
//
|
||||
// // Standard parser without descriptors
|
||||
// specParser := NewParser(Minute | Hour | Dom | Month | Dow)
|
||||
// sched, err := specParser.Parse("0 0 15 */3 *")
|
||||
//
|
||||
// // Same as above, just excludes time fields
|
||||
// subsParser := NewParser(Dom | Month | Dow)
|
||||
// sched, err := specParser.Parse("15 */3 *")
|
||||
//
|
||||
// // Same as above, just makes Dow optional
|
||||
// subsParser := NewParser(Dom | Month | DowOptional)
|
||||
// sched, err := specParser.Parse("15 */3")
|
||||
//
|
||||
func NewParser(options ParseOption) Parser {
|
||||
optionals := 0
|
||||
if options&DowOptional > 0 {
|
||||
optionals++
|
||||
}
|
||||
if options&SecondOptional > 0 {
|
||||
optionals++
|
||||
}
|
||||
if optionals > 1 {
|
||||
panic("multiple optionals may not be configured")
|
||||
}
|
||||
return Parser{options}
|
||||
}
|
||||
|
||||
// Parse returns a new crontab schedule representing the given spec.
|
||||
// It returns a descriptive error if the spec is not valid.
|
||||
// It accepts crontab specs and features configured by NewParser.
|
||||
func (p Parser) Parse(spec string) (Schedule, error) {
|
||||
if len(spec) == 0 {
|
||||
return nil, fmt.Errorf("empty spec string")
|
||||
}
|
||||
|
||||
// Extract timezone if present
|
||||
var loc = time.Local
|
||||
if strings.HasPrefix(spec, "TZ=") || strings.HasPrefix(spec, "CRON_TZ=") {
|
||||
var err error
|
||||
i := strings.Index(spec, " ")
|
||||
eq := strings.Index(spec, "=")
|
||||
if loc, err = time.LoadLocation(spec[eq+1 : i]); err != nil {
|
||||
return nil, fmt.Errorf("provided bad location %s: %v", spec[eq+1:i], err)
|
||||
}
|
||||
spec = strings.TrimSpace(spec[i:])
|
||||
}
|
||||
|
||||
// Handle named schedules (descriptors), if configured
|
||||
if strings.HasPrefix(spec, "@") {
|
||||
if p.options&Descriptor == 0 {
|
||||
return nil, fmt.Errorf("parser does not accept descriptors: %v", spec)
|
||||
}
|
||||
return parseDescriptor(spec, loc)
|
||||
}
|
||||
|
||||
// Split on whitespace.
|
||||
fields := strings.Fields(spec)
|
||||
|
||||
// Validate & fill in any omitted or optional fields
|
||||
var err error
|
||||
fields, err = normalizeFields(fields, p.options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
field := func(field string, r bounds) uint64 {
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
var bits uint64
|
||||
bits, err = getField(field, r)
|
||||
return bits
|
||||
}
|
||||
|
||||
var (
|
||||
second = field(fields[0], seconds)
|
||||
minute = field(fields[1], minutes)
|
||||
hour = field(fields[2], hours)
|
||||
dayofmonth = field(fields[3], dom)
|
||||
month = field(fields[4], months)
|
||||
dayofweek = field(fields[5], dow)
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SpecSchedule{
|
||||
Second: second,
|
||||
Minute: minute,
|
||||
Hour: hour,
|
||||
Dom: dayofmonth,
|
||||
Month: month,
|
||||
Dow: dayofweek,
|
||||
Location: loc,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// normalizeFields takes a subset set of the time fields and returns the full set
|
||||
// with defaults (zeroes) populated for unset fields.
|
||||
//
|
||||
// As part of performing this function, it also validates that the provided
|
||||
// fields are compatible with the configured options.
|
||||
func normalizeFields(fields []string, options ParseOption) ([]string, error) {
|
||||
// Validate optionals & add their field to options
|
||||
optionals := 0
|
||||
if options&SecondOptional > 0 {
|
||||
options |= Second
|
||||
optionals++
|
||||
}
|
||||
if options&DowOptional > 0 {
|
||||
options |= Dow
|
||||
optionals++
|
||||
}
|
||||
if optionals > 1 {
|
||||
return nil, fmt.Errorf("multiple optionals may not be configured")
|
||||
}
|
||||
|
||||
// Figure out how many fields we need
|
||||
max := 0
|
||||
for _, place := range places {
|
||||
if options&place > 0 {
|
||||
max++
|
||||
}
|
||||
}
|
||||
min := max - optionals
|
||||
|
||||
// Validate number of fields
|
||||
if count := len(fields); count < min || count > max {
|
||||
if min == max {
|
||||
return nil, fmt.Errorf("expected exactly %d fields, found %d: %s", min, count, fields)
|
||||
}
|
||||
return nil, fmt.Errorf("expected %d to %d fields, found %d: %s", min, max, count, fields)
|
||||
}
|
||||
|
||||
// Populate the optional field if not provided
|
||||
if min < max && len(fields) == min {
|
||||
switch {
|
||||
case options&DowOptional > 0:
|
||||
fields = append(fields, defaults[5]) // TODO: improve access to default
|
||||
case options&SecondOptional > 0:
|
||||
fields = append([]string{defaults[0]}, fields...)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown optional field")
|
||||
}
|
||||
}
|
||||
|
||||
// Populate all fields not part of options with their defaults
|
||||
n := 0
|
||||
expandedFields := make([]string, len(places))
|
||||
copy(expandedFields, defaults)
|
||||
for i, place := range places {
|
||||
if options&place > 0 {
|
||||
expandedFields[i] = fields[n]
|
||||
n++
|
||||
}
|
||||
}
|
||||
return expandedFields, nil
|
||||
}
|
||||
|
||||
var standardParser = NewParser(
|
||||
Minute | Hour | Dom | Month | Dow | Descriptor,
|
||||
)
|
||||
|
||||
// ParseStandard returns a new crontab schedule representing the given
|
||||
// standardSpec (https://en.wikipedia.org/wiki/Cron). It requires 5 entries
|
||||
// representing: minute, hour, day of month, month and day of week, in that
|
||||
// order. It returns a descriptive error if the spec is not valid.
|
||||
//
|
||||
// It accepts
|
||||
// - Standard crontab specs, e.g. "* * * * ?"
|
||||
// - Descriptors, e.g. "@midnight", "@every 1h30m"
|
||||
func ParseStandard(standardSpec string) (Schedule, error) {
|
||||
return standardParser.Parse(standardSpec)
|
||||
}
|
||||
|
||||
// getField returns an Int with the bits set representing all of the times that
|
||||
// the field represents or error parsing field value. A "field" is a comma-separated
|
||||
// list of "ranges".
|
||||
func getField(field string, r bounds) (uint64, error) {
|
||||
var bits uint64
|
||||
ranges := strings.FieldsFunc(field, func(r rune) bool { return r == ',' })
|
||||
for _, expr := range ranges {
|
||||
bit, err := getRange(expr, r)
|
||||
if err != nil {
|
||||
return bits, err
|
||||
}
|
||||
bits |= bit
|
||||
}
|
||||
return bits, nil
|
||||
}
|
||||
|
||||
// getRange returns the bits indicated by the given expression:
|
||||
// number | number "-" number [ "/" number ]
|
||||
// or error parsing range.
|
||||
func getRange(expr string, r bounds) (uint64, error) {
|
||||
var (
|
||||
start, end, step uint
|
||||
rangeAndStep = strings.Split(expr, "/")
|
||||
lowAndHigh = strings.Split(rangeAndStep[0], "-")
|
||||
singleDigit = len(lowAndHigh) == 1
|
||||
err error
|
||||
)
|
||||
|
||||
var extra uint64
|
||||
if lowAndHigh[0] == "*" || lowAndHigh[0] == "?" {
|
||||
start = r.min
|
||||
end = r.max
|
||||
extra = starBit
|
||||
} else {
|
||||
start, err = parseIntOrName(lowAndHigh[0], r.names)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
switch len(lowAndHigh) {
|
||||
case 1:
|
||||
end = start
|
||||
case 2:
|
||||
end, err = parseIntOrName(lowAndHigh[1], r.names)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
default:
|
||||
return 0, fmt.Errorf("too many hyphens: %s", expr)
|
||||
}
|
||||
}
|
||||
|
||||
switch len(rangeAndStep) {
|
||||
case 1:
|
||||
step = 1
|
||||
case 2:
|
||||
step, err = mustParseInt(rangeAndStep[1])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Special handling: "N/step" means "N-max/step".
|
||||
if singleDigit {
|
||||
end = r.max
|
||||
}
|
||||
if step > 1 {
|
||||
extra = 0
|
||||
}
|
||||
default:
|
||||
return 0, fmt.Errorf("too many slashes: %s", expr)
|
||||
}
|
||||
|
||||
if start < r.min {
|
||||
return 0, fmt.Errorf("beginning of range (%d) below minimum (%d): %s", start, r.min, expr)
|
||||
}
|
||||
if end > r.max {
|
||||
return 0, fmt.Errorf("end of range (%d) above maximum (%d): %s", end, r.max, expr)
|
||||
}
|
||||
if start > end {
|
||||
return 0, fmt.Errorf("beginning of range (%d) beyond end of range (%d): %s", start, end, expr)
|
||||
}
|
||||
if step == 0 {
|
||||
return 0, fmt.Errorf("step of range should be a positive number: %s", expr)
|
||||
}
|
||||
|
||||
return getBits(start, end, step) | extra, nil
|
||||
}
|
||||
|
||||
// parseIntOrName returns the (possibly-named) integer contained in expr.
|
||||
func parseIntOrName(expr string, names map[string]uint) (uint, error) {
|
||||
if names != nil {
|
||||
if namedInt, ok := names[strings.ToLower(expr)]; ok {
|
||||
return namedInt, nil
|
||||
}
|
||||
}
|
||||
return mustParseInt(expr)
|
||||
}
|
||||
|
||||
// mustParseInt parses the given expression as an int or returns an error.
|
||||
func mustParseInt(expr string) (uint, error) {
|
||||
num, err := strconv.Atoi(expr)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to parse int from %s: %s", expr, err)
|
||||
}
|
||||
if num < 0 {
|
||||
return 0, fmt.Errorf("negative number (%d) not allowed: %s", num, expr)
|
||||
}
|
||||
|
||||
return uint(num), nil
|
||||
}
|
||||
|
||||
// getBits sets all bits in the range [min, max], modulo the given step size.
|
||||
func getBits(min, max, step uint) uint64 {
|
||||
var bits uint64
|
||||
|
||||
// If step is 1, use shifts.
|
||||
if step == 1 {
|
||||
return ^(math.MaxUint64 << (max + 1)) & (math.MaxUint64 << min)
|
||||
}
|
||||
|
||||
// Else, use a simple loop.
|
||||
for i := min; i <= max; i += step {
|
||||
bits |= 1 << i
|
||||
}
|
||||
return bits
|
||||
}
|
||||
|
||||
// all returns all bits within the given bounds. (plus the star bit)
|
||||
func all(r bounds) uint64 {
|
||||
return getBits(r.min, r.max, 1) | starBit
|
||||
}
|
||||
|
||||
// parseDescriptor returns a predefined schedule for the expression, or error if none matches.
|
||||
func parseDescriptor(descriptor string, loc *time.Location) (Schedule, error) {
|
||||
switch descriptor {
|
||||
case "@yearly", "@annually":
|
||||
return &SpecSchedule{
|
||||
Second: 1 << seconds.min,
|
||||
Minute: 1 << minutes.min,
|
||||
Hour: 1 << hours.min,
|
||||
Dom: 1 << dom.min,
|
||||
Month: 1 << months.min,
|
||||
Dow: all(dow),
|
||||
Location: loc,
|
||||
}, nil
|
||||
|
||||
case "@monthly":
|
||||
return &SpecSchedule{
|
||||
Second: 1 << seconds.min,
|
||||
Minute: 1 << minutes.min,
|
||||
Hour: 1 << hours.min,
|
||||
Dom: 1 << dom.min,
|
||||
Month: all(months),
|
||||
Dow: all(dow),
|
||||
Location: loc,
|
||||
}, nil
|
||||
|
||||
case "@weekly":
|
||||
return &SpecSchedule{
|
||||
Second: 1 << seconds.min,
|
||||
Minute: 1 << minutes.min,
|
||||
Hour: 1 << hours.min,
|
||||
Dom: all(dom),
|
||||
Month: all(months),
|
||||
Dow: 1 << dow.min,
|
||||
Location: loc,
|
||||
}, nil
|
||||
|
||||
case "@daily", "@midnight":
|
||||
return &SpecSchedule{
|
||||
Second: 1 << seconds.min,
|
||||
Minute: 1 << minutes.min,
|
||||
Hour: 1 << hours.min,
|
||||
Dom: all(dom),
|
||||
Month: all(months),
|
||||
Dow: all(dow),
|
||||
Location: loc,
|
||||
}, nil
|
||||
|
||||
case "@hourly":
|
||||
return &SpecSchedule{
|
||||
Second: 1 << seconds.min,
|
||||
Minute: 1 << minutes.min,
|
||||
Hour: all(hours),
|
||||
Dom: all(dom),
|
||||
Month: all(months),
|
||||
Dow: all(dow),
|
||||
Location: loc,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
const every = "@every "
|
||||
if strings.HasPrefix(descriptor, every) {
|
||||
duration, err := time.ParseDuration(descriptor[len(every):])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse duration %s: %s", descriptor, err)
|
||||
}
|
||||
return Every(duration), nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unrecognized descriptor: %s", descriptor)
|
||||
}
|
||||
383
src/server/cron/parser_test.go
Normal file
383
src/server/cron/parser_test.go
Normal file
@ -0,0 +1,383 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var secondParser = NewParser(Second | Minute | Hour | Dom | Month | DowOptional | Descriptor)
|
||||
|
||||
func TestRange(t *testing.T) {
|
||||
zero := uint64(0)
|
||||
ranges := []struct {
|
||||
expr string
|
||||
min, max uint
|
||||
expected uint64
|
||||
err string
|
||||
}{
|
||||
{"5", 0, 7, 1 << 5, ""},
|
||||
{"0", 0, 7, 1 << 0, ""},
|
||||
{"7", 0, 7, 1 << 7, ""},
|
||||
|
||||
{"5-5", 0, 7, 1 << 5, ""},
|
||||
{"5-6", 0, 7, 1<<5 | 1<<6, ""},
|
||||
{"5-7", 0, 7, 1<<5 | 1<<6 | 1<<7, ""},
|
||||
|
||||
{"5-6/2", 0, 7, 1 << 5, ""},
|
||||
{"5-7/2", 0, 7, 1<<5 | 1<<7, ""},
|
||||
{"5-7/1", 0, 7, 1<<5 | 1<<6 | 1<<7, ""},
|
||||
|
||||
{"*", 1, 3, 1<<1 | 1<<2 | 1<<3 | starBit, ""},
|
||||
{"*/2", 1, 3, 1<<1 | 1<<3, ""},
|
||||
|
||||
{"5--5", 0, 0, zero, "too many hyphens"},
|
||||
{"jan-x", 0, 0, zero, "failed to parse int from"},
|
||||
{"2-x", 1, 5, zero, "failed to parse int from"},
|
||||
{"*/-12", 0, 0, zero, "negative number"},
|
||||
{"*//2", 0, 0, zero, "too many slashes"},
|
||||
{"1", 3, 5, zero, "below minimum"},
|
||||
{"6", 3, 5, zero, "above maximum"},
|
||||
{"5-3", 3, 5, zero, "beyond end of range"},
|
||||
{"*/0", 0, 0, zero, "should be a positive number"},
|
||||
}
|
||||
|
||||
for _, c := range ranges {
|
||||
actual, err := getRange(c.expr, bounds{c.min, c.max, nil})
|
||||
if len(c.err) != 0 && (err == nil || !strings.Contains(err.Error(), c.err)) {
|
||||
t.Errorf("%s => expected %v, got %v", c.expr, c.err, err)
|
||||
}
|
||||
if len(c.err) == 0 && err != nil {
|
||||
t.Errorf("%s => unexpected error %v", c.expr, err)
|
||||
}
|
||||
if actual != c.expected {
|
||||
t.Errorf("%s => expected %d, got %d", c.expr, c.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestField(t *testing.T) {
|
||||
fields := []struct {
|
||||
expr string
|
||||
min, max uint
|
||||
expected uint64
|
||||
}{
|
||||
{"5", 1, 7, 1 << 5},
|
||||
{"5,6", 1, 7, 1<<5 | 1<<6},
|
||||
{"5,6,7", 1, 7, 1<<5 | 1<<6 | 1<<7},
|
||||
{"1,5-7/2,3", 1, 7, 1<<1 | 1<<5 | 1<<7 | 1<<3},
|
||||
}
|
||||
|
||||
for _, c := range fields {
|
||||
actual, _ := getField(c.expr, bounds{c.min, c.max, nil})
|
||||
if actual != c.expected {
|
||||
t.Errorf("%s => expected %d, got %d", c.expr, c.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAll(t *testing.T) {
|
||||
allBits := []struct {
|
||||
r bounds
|
||||
expected uint64
|
||||
}{
|
||||
{minutes, 0xfffffffffffffff}, // 0-59: 60 ones
|
||||
{hours, 0xffffff}, // 0-23: 24 ones
|
||||
{dom, 0xfffffffe}, // 1-31: 31 ones, 1 zero
|
||||
{months, 0x1ffe}, // 1-12: 12 ones, 1 zero
|
||||
{dow, 0x7f}, // 0-6: 7 ones
|
||||
}
|
||||
|
||||
for _, c := range allBits {
|
||||
actual := all(c.r) // all() adds the starBit, so compensate for that..
|
||||
if c.expected|starBit != actual {
|
||||
t.Errorf("%d-%d/%d => expected %b, got %b",
|
||||
c.r.min, c.r.max, 1, c.expected|starBit, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBits(t *testing.T) {
|
||||
bits := []struct {
|
||||
min, max, step uint
|
||||
expected uint64
|
||||
}{
|
||||
{0, 0, 1, 0x1},
|
||||
{1, 1, 1, 0x2},
|
||||
{1, 5, 2, 0x2a}, // 101010
|
||||
{1, 4, 2, 0xa}, // 1010
|
||||
}
|
||||
|
||||
for _, c := range bits {
|
||||
actual := getBits(c.min, c.max, c.step)
|
||||
if c.expected != actual {
|
||||
t.Errorf("%d-%d/%d => expected %b, got %b",
|
||||
c.min, c.max, c.step, c.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseScheduleErrors(t *testing.T) {
|
||||
var tests = []struct{ expr, err string }{
|
||||
{"* 5 j * * *", "failed to parse int from"},
|
||||
{"@every Xm", "failed to parse duration"},
|
||||
{"@unrecognized", "unrecognized descriptor"},
|
||||
{"* * * *", "expected 5 to 6 fields"},
|
||||
{"", "empty spec string"},
|
||||
}
|
||||
for _, c := range tests {
|
||||
actual, err := secondParser.Parse(c.expr)
|
||||
if err == nil || !strings.Contains(err.Error(), c.err) {
|
||||
t.Errorf("%s => expected %v, got %v", c.expr, c.err, err)
|
||||
}
|
||||
if actual != nil {
|
||||
t.Errorf("expected nil schedule on error, got %v", actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseSchedule(t *testing.T) {
|
||||
tokyo, _ := time.LoadLocation("Asia/Tokyo")
|
||||
entries := []struct {
|
||||
parser Parser
|
||||
expr string
|
||||
expected Schedule
|
||||
}{
|
||||
{secondParser, "0 5 * * * *", every5min(time.Local)},
|
||||
{standardParser, "5 * * * *", every5min(time.Local)},
|
||||
{secondParser, "CRON_TZ=UTC 0 5 * * * *", every5min(time.UTC)},
|
||||
{standardParser, "CRON_TZ=UTC 5 * * * *", every5min(time.UTC)},
|
||||
{secondParser, "CRON_TZ=Asia/Tokyo 0 5 * * * *", every5min(tokyo)},
|
||||
{secondParser, "@every 5m", ConstantDelaySchedule{5 * time.Minute}},
|
||||
{secondParser, "@midnight", midnight(time.Local)},
|
||||
{secondParser, "TZ=UTC @midnight", midnight(time.UTC)},
|
||||
{secondParser, "TZ=Asia/Tokyo @midnight", midnight(tokyo)},
|
||||
{secondParser, "@yearly", annual(time.Local)},
|
||||
{secondParser, "@annually", annual(time.Local)},
|
||||
{
|
||||
parser: secondParser,
|
||||
expr: "* 5 * * * *",
|
||||
expected: &SpecSchedule{
|
||||
Second: all(seconds),
|
||||
Minute: 1 << 5,
|
||||
Hour: all(hours),
|
||||
Dom: all(dom),
|
||||
Month: all(months),
|
||||
Dow: all(dow),
|
||||
Location: time.Local,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range entries {
|
||||
actual, err := c.parser.Parse(c.expr)
|
||||
if err != nil {
|
||||
t.Errorf("%s => unexpected error %v", c.expr, err)
|
||||
}
|
||||
if !reflect.DeepEqual(actual, c.expected) {
|
||||
t.Errorf("%s => expected %b, got %b", c.expr, c.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptionalSecondSchedule(t *testing.T) {
|
||||
parser := NewParser(SecondOptional | Minute | Hour | Dom | Month | Dow | Descriptor)
|
||||
entries := []struct {
|
||||
expr string
|
||||
expected Schedule
|
||||
}{
|
||||
{"0 5 * * * *", every5min(time.Local)},
|
||||
{"5 5 * * * *", every5min5s(time.Local)},
|
||||
{"5 * * * *", every5min(time.Local)},
|
||||
}
|
||||
|
||||
for _, c := range entries {
|
||||
actual, err := parser.Parse(c.expr)
|
||||
if err != nil {
|
||||
t.Errorf("%s => unexpected error %v", c.expr, err)
|
||||
}
|
||||
if !reflect.DeepEqual(actual, c.expected) {
|
||||
t.Errorf("%s => expected %b, got %b", c.expr, c.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeFields(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []string
|
||||
options ParseOption
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
"AllFields_NoOptional",
|
||||
[]string{"0", "5", "*", "*", "*", "*"},
|
||||
Second | Minute | Hour | Dom | Month | Dow | Descriptor,
|
||||
[]string{"0", "5", "*", "*", "*", "*"},
|
||||
},
|
||||
{
|
||||
"AllFields_SecondOptional_Provided",
|
||||
[]string{"0", "5", "*", "*", "*", "*"},
|
||||
SecondOptional | Minute | Hour | Dom | Month | Dow | Descriptor,
|
||||
[]string{"0", "5", "*", "*", "*", "*"},
|
||||
},
|
||||
{
|
||||
"AllFields_SecondOptional_NotProvided",
|
||||
[]string{"5", "*", "*", "*", "*"},
|
||||
SecondOptional | Minute | Hour | Dom | Month | Dow | Descriptor,
|
||||
[]string{"0", "5", "*", "*", "*", "*"},
|
||||
},
|
||||
{
|
||||
"SubsetFields_NoOptional",
|
||||
[]string{"5", "15", "*"},
|
||||
Hour | Dom | Month,
|
||||
[]string{"0", "0", "5", "15", "*", "*"},
|
||||
},
|
||||
{
|
||||
"SubsetFields_DowOptional_Provided",
|
||||
[]string{"5", "15", "*", "4"},
|
||||
Hour | Dom | Month | DowOptional,
|
||||
[]string{"0", "0", "5", "15", "*", "4"},
|
||||
},
|
||||
{
|
||||
"SubsetFields_DowOptional_NotProvided",
|
||||
[]string{"5", "15", "*"},
|
||||
Hour | Dom | Month | DowOptional,
|
||||
[]string{"0", "0", "5", "15", "*", "*"},
|
||||
},
|
||||
{
|
||||
"SubsetFields_SecondOptional_NotProvided",
|
||||
[]string{"5", "15", "*"},
|
||||
SecondOptional | Hour | Dom | Month,
|
||||
[]string{"0", "0", "5", "15", "*", "*"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual, err := normalizeFields(test.input, test.options)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(actual, test.expected) {
|
||||
t.Errorf("expected %v, got %v", test.expected, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeFields_Errors(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []string
|
||||
options ParseOption
|
||||
err string
|
||||
}{
|
||||
{
|
||||
"TwoOptionals",
|
||||
[]string{"0", "5", "*", "*", "*", "*"},
|
||||
SecondOptional | Minute | Hour | Dom | Month | DowOptional,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"TooManyFields",
|
||||
[]string{"0", "5", "*", "*"},
|
||||
SecondOptional | Minute | Hour,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"NoFields",
|
||||
[]string{},
|
||||
SecondOptional | Minute | Hour,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"TooFewFields",
|
||||
[]string{"*"},
|
||||
SecondOptional | Minute | Hour,
|
||||
"",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual, err := normalizeFields(test.input, test.options)
|
||||
if err == nil {
|
||||
t.Errorf("expected an error, got none. results: %v", actual)
|
||||
}
|
||||
if !strings.Contains(err.Error(), test.err) {
|
||||
t.Errorf("expected error %q, got %q", test.err, err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStandardSpecSchedule(t *testing.T) {
|
||||
entries := []struct {
|
||||
expr string
|
||||
expected Schedule
|
||||
err string
|
||||
}{
|
||||
{
|
||||
expr: "5 * * * *",
|
||||
expected: &SpecSchedule{1 << seconds.min, 1 << 5, all(hours), all(dom), all(months), all(dow), time.Local},
|
||||
},
|
||||
{
|
||||
expr: "@every 5m",
|
||||
expected: ConstantDelaySchedule{time.Duration(5) * time.Minute},
|
||||
},
|
||||
{
|
||||
expr: "5 j * * *",
|
||||
err: "failed to parse int from",
|
||||
},
|
||||
{
|
||||
expr: "* * * *",
|
||||
err: "expected exactly 5 fields",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range entries {
|
||||
actual, err := ParseStandard(c.expr)
|
||||
if len(c.err) != 0 && (err == nil || !strings.Contains(err.Error(), c.err)) {
|
||||
t.Errorf("%s => expected %v, got %v", c.expr, c.err, err)
|
||||
}
|
||||
if len(c.err) == 0 && err != nil {
|
||||
t.Errorf("%s => unexpected error %v", c.expr, err)
|
||||
}
|
||||
if !reflect.DeepEqual(actual, c.expected) {
|
||||
t.Errorf("%s => expected %b, got %b", c.expr, c.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoDescriptorParser(t *testing.T) {
|
||||
parser := NewParser(Minute | Hour)
|
||||
_, err := parser.Parse("@every 1m")
|
||||
if err == nil {
|
||||
t.Error("expected an error, got none")
|
||||
}
|
||||
}
|
||||
|
||||
func every5min(loc *time.Location) *SpecSchedule {
|
||||
return &SpecSchedule{1 << 0, 1 << 5, all(hours), all(dom), all(months), all(dow), loc}
|
||||
}
|
||||
|
||||
func every5min5s(loc *time.Location) *SpecSchedule {
|
||||
return &SpecSchedule{1 << 5, 1 << 5, all(hours), all(dom), all(months), all(dow), loc}
|
||||
}
|
||||
|
||||
func midnight(loc *time.Location) *SpecSchedule {
|
||||
return &SpecSchedule{1, 1, 1, all(dom), all(months), all(dow), loc}
|
||||
}
|
||||
|
||||
func annual(loc *time.Location) *SpecSchedule {
|
||||
return &SpecSchedule{
|
||||
Second: 1 << seconds.min,
|
||||
Minute: 1 << minutes.min,
|
||||
Hour: 1 << hours.min,
|
||||
Dom: 1 << dom.min,
|
||||
Month: 1 << months.min,
|
||||
Dow: all(dow),
|
||||
Location: loc,
|
||||
}
|
||||
}
|
||||
188
src/server/cron/spec.go
Normal file
188
src/server/cron/spec.go
Normal file
@ -0,0 +1,188 @@
|
||||
package cron
|
||||
|
||||
import "time"
|
||||
|
||||
// SpecSchedule specifies a duty cycle (to the second granularity), based on a
|
||||
// traditional crontab specification. It is computed initially and stored as bit sets.
|
||||
type SpecSchedule struct {
|
||||
Second, Minute, Hour, Dom, Month, Dow uint64
|
||||
|
||||
// Override location for this schedule.
|
||||
Location *time.Location
|
||||
}
|
||||
|
||||
// bounds provides a range of acceptable values (plus a map of name to value).
|
||||
type bounds struct {
|
||||
min, max uint
|
||||
names map[string]uint
|
||||
}
|
||||
|
||||
// The bounds for each field.
|
||||
var (
|
||||
seconds = bounds{0, 59, nil}
|
||||
minutes = bounds{0, 59, nil}
|
||||
hours = bounds{0, 23, nil}
|
||||
dom = bounds{1, 31, nil}
|
||||
months = bounds{1, 12, map[string]uint{
|
||||
"jan": 1,
|
||||
"feb": 2,
|
||||
"mar": 3,
|
||||
"apr": 4,
|
||||
"may": 5,
|
||||
"jun": 6,
|
||||
"jul": 7,
|
||||
"aug": 8,
|
||||
"sep": 9,
|
||||
"oct": 10,
|
||||
"nov": 11,
|
||||
"dec": 12,
|
||||
}}
|
||||
dow = bounds{0, 6, map[string]uint{
|
||||
"sun": 0,
|
||||
"mon": 1,
|
||||
"tue": 2,
|
||||
"wed": 3,
|
||||
"thu": 4,
|
||||
"fri": 5,
|
||||
"sat": 6,
|
||||
}}
|
||||
)
|
||||
|
||||
const (
|
||||
// Set the top bit if a star was included in the expression.
|
||||
starBit = 1 << 63
|
||||
)
|
||||
|
||||
// Next returns the next time this schedule is activated, greater than the given
|
||||
// time. If no time can be found to satisfy the schedule, return the zero time.
|
||||
func (s *SpecSchedule) Next(t time.Time) time.Time {
|
||||
// General approach
|
||||
//
|
||||
// For Month, Day, Hour, Minute, Second:
|
||||
// Check if the time value matches. If yes, continue to the next field.
|
||||
// If the field doesn't match the schedule, then increment the field until it matches.
|
||||
// While incrementing the field, a wrap-around brings it back to the beginning
|
||||
// of the field list (since it is necessary to re-verify previous field
|
||||
// values)
|
||||
|
||||
// Convert the given time into the schedule's timezone, if one is specified.
|
||||
// Save the original timezone so we can convert back after we find a time.
|
||||
// Note that schedules without a time zone specified (time.Local) are treated
|
||||
// as local to the time provided.
|
||||
origLocation := t.Location()
|
||||
loc := s.Location
|
||||
if loc == time.Local {
|
||||
loc = t.Location()
|
||||
}
|
||||
if s.Location != time.Local {
|
||||
t = t.In(s.Location)
|
||||
}
|
||||
|
||||
// Start at the earliest possible time (the upcoming second).
|
||||
t = t.Add(1*time.Second - time.Duration(t.Nanosecond())*time.Nanosecond)
|
||||
|
||||
// This flag indicates whether a field has been incremented.
|
||||
added := false
|
||||
|
||||
// If no time is found within five years, return zero.
|
||||
yearLimit := t.Year() + 5
|
||||
|
||||
WRAP:
|
||||
if t.Year() > yearLimit {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
// Find the first applicable month.
|
||||
// If it's this month, then do nothing.
|
||||
for 1<<uint(t.Month())&s.Month == 0 {
|
||||
// If we have to add a month, reset the other parts to 0.
|
||||
if !added {
|
||||
added = true
|
||||
// Otherwise, set the date at the beginning (since the current time is irrelevant).
|
||||
t = time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, loc)
|
||||
}
|
||||
t = t.AddDate(0, 1, 0)
|
||||
|
||||
// Wrapped around.
|
||||
if t.Month() == time.January {
|
||||
goto WRAP
|
||||
}
|
||||
}
|
||||
|
||||
// Now get a day in that month.
|
||||
//
|
||||
// NOTE: This causes issues for daylight savings regimes where midnight does
|
||||
// not exist. For example: Sao Paulo has DST that transforms midnight on
|
||||
// 11/3 into 1am. Handle that by noticing when the Hour ends up != 0.
|
||||
for !dayMatches(s, t) {
|
||||
if !added {
|
||||
added = true
|
||||
t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, loc)
|
||||
}
|
||||
t = t.AddDate(0, 0, 1)
|
||||
// Notice if the hour is no longer midnight due to DST.
|
||||
// Add an hour if it's 23, subtract an hour if it's 1.
|
||||
if t.Hour() != 0 {
|
||||
if t.Hour() > 12 {
|
||||
t = t.Add(time.Duration(24-t.Hour()) * time.Hour)
|
||||
} else {
|
||||
t = t.Add(time.Duration(-t.Hour()) * time.Hour)
|
||||
}
|
||||
}
|
||||
|
||||
if t.Day() == 1 {
|
||||
goto WRAP
|
||||
}
|
||||
}
|
||||
|
||||
for 1<<uint(t.Hour())&s.Hour == 0 {
|
||||
if !added {
|
||||
added = true
|
||||
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), 0, 0, 0, loc)
|
||||
}
|
||||
t = t.Add(1 * time.Hour)
|
||||
|
||||
if t.Hour() == 0 {
|
||||
goto WRAP
|
||||
}
|
||||
}
|
||||
|
||||
for 1<<uint(t.Minute())&s.Minute == 0 {
|
||||
if !added {
|
||||
added = true
|
||||
t = t.Truncate(time.Minute)
|
||||
}
|
||||
t = t.Add(1 * time.Minute)
|
||||
|
||||
if t.Minute() == 0 {
|
||||
goto WRAP
|
||||
}
|
||||
}
|
||||
|
||||
for 1<<uint(t.Second())&s.Second == 0 {
|
||||
if !added {
|
||||
added = true
|
||||
t = t.Truncate(time.Second)
|
||||
}
|
||||
t = t.Add(1 * time.Second)
|
||||
|
||||
if t.Second() == 0 {
|
||||
goto WRAP
|
||||
}
|
||||
}
|
||||
|
||||
return t.In(origLocation)
|
||||
}
|
||||
|
||||
// dayMatches returns true if the schedule's day-of-week and day-of-month
|
||||
// restrictions are satisfied by the given time.
|
||||
func dayMatches(s *SpecSchedule, t time.Time) bool {
|
||||
var (
|
||||
domMatch bool = 1<<uint(t.Day())&s.Dom > 0
|
||||
dowMatch bool = 1<<uint(t.Weekday())&s.Dow > 0
|
||||
)
|
||||
if s.Dom&starBit > 0 || s.Dow&starBit > 0 {
|
||||
return domMatch && dowMatch
|
||||
}
|
||||
return domMatch || dowMatch
|
||||
}
|
||||
300
src/server/cron/spec_test.go
Normal file
300
src/server/cron/spec_test.go
Normal file
@ -0,0 +1,300 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestActivation(t *testing.T) {
|
||||
tests := []struct {
|
||||
time, spec string
|
||||
expected bool
|
||||
}{
|
||||
// Every fifteen minutes.
|
||||
{"Mon Jul 9 15:00 2012", "0/15 * * * *", true},
|
||||
{"Mon Jul 9 15:45 2012", "0/15 * * * *", true},
|
||||
{"Mon Jul 9 15:40 2012", "0/15 * * * *", false},
|
||||
|
||||
// Every fifteen minutes, starting at 5 minutes.
|
||||
{"Mon Jul 9 15:05 2012", "5/15 * * * *", true},
|
||||
{"Mon Jul 9 15:20 2012", "5/15 * * * *", true},
|
||||
{"Mon Jul 9 15:50 2012", "5/15 * * * *", true},
|
||||
|
||||
// Named months
|
||||
{"Sun Jul 15 15:00 2012", "0/15 * * Jul *", true},
|
||||
{"Sun Jul 15 15:00 2012", "0/15 * * Jun *", false},
|
||||
|
||||
// Everything set.
|
||||
{"Sun Jul 15 08:30 2012", "30 08 ? Jul Sun", true},
|
||||
{"Sun Jul 15 08:30 2012", "30 08 15 Jul ?", true},
|
||||
{"Mon Jul 16 08:30 2012", "30 08 ? Jul Sun", false},
|
||||
{"Mon Jul 16 08:30 2012", "30 08 15 Jul ?", false},
|
||||
|
||||
// Predefined schedules
|
||||
{"Mon Jul 9 15:00 2012", "@hourly", true},
|
||||
{"Mon Jul 9 15:04 2012", "@hourly", false},
|
||||
{"Mon Jul 9 15:00 2012", "@daily", false},
|
||||
{"Mon Jul 9 00:00 2012", "@daily", true},
|
||||
{"Mon Jul 9 00:00 2012", "@weekly", false},
|
||||
{"Sun Jul 8 00:00 2012", "@weekly", true},
|
||||
{"Sun Jul 8 01:00 2012", "@weekly", false},
|
||||
{"Sun Jul 8 00:00 2012", "@monthly", false},
|
||||
{"Sun Jul 1 00:00 2012", "@monthly", true},
|
||||
|
||||
// Test interaction of DOW and DOM.
|
||||
// If both are restricted, then only one needs to match.
|
||||
{"Sun Jul 15 00:00 2012", "* * 1,15 * Sun", true},
|
||||
{"Fri Jun 15 00:00 2012", "* * 1,15 * Sun", true},
|
||||
{"Wed Aug 1 00:00 2012", "* * 1,15 * Sun", true},
|
||||
{"Sun Jul 15 00:00 2012", "* * */10 * Sun", true}, // verifies #70
|
||||
|
||||
// However, if one has a star, then both need to match.
|
||||
{"Sun Jul 15 00:00 2012", "* * * * Mon", false},
|
||||
{"Mon Jul 9 00:00 2012", "* * 1,15 * *", false},
|
||||
{"Sun Jul 15 00:00 2012", "* * 1,15 * *", true},
|
||||
{"Sun Jul 15 00:00 2012", "* * */2 * Sun", true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
sched, err := ParseStandard(test.spec)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
actual := sched.Next(getTime(test.time).Add(-1 * time.Second))
|
||||
expected := getTime(test.time)
|
||||
if test.expected && expected != actual || !test.expected && expected == actual {
|
||||
t.Errorf("Fail evaluating %s on %s: (expected) %s != %s (actual)",
|
||||
test.spec, test.time, expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNext(t *testing.T) {
|
||||
runs := []struct {
|
||||
time, spec string
|
||||
expected string
|
||||
}{
|
||||
// Simple cases
|
||||
{"Mon Jul 9 14:45 2012", "0 0/15 * * * *", "Mon Jul 9 15:00 2012"},
|
||||
{"Mon Jul 9 14:59 2012", "0 0/15 * * * *", "Mon Jul 9 15:00 2012"},
|
||||
{"Mon Jul 9 14:59:59 2012", "0 0/15 * * * *", "Mon Jul 9 15:00 2012"},
|
||||
|
||||
// Wrap around hours
|
||||
{"Mon Jul 9 15:45 2012", "0 20-35/15 * * * *", "Mon Jul 9 16:20 2012"},
|
||||
|
||||
// Wrap around days
|
||||
{"Mon Jul 9 23:46 2012", "0 */15 * * * *", "Tue Jul 10 00:00 2012"},
|
||||
{"Mon Jul 9 23:45 2012", "0 20-35/15 * * * *", "Tue Jul 10 00:20 2012"},
|
||||
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 * * * *", "Tue Jul 10 00:20:15 2012"},
|
||||
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 1/2 * * *", "Tue Jul 10 01:20:15 2012"},
|
||||
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 10-12 * * *", "Tue Jul 10 10:20:15 2012"},
|
||||
|
||||
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 1/2 */2 * *", "Thu Jul 11 01:20:15 2012"},
|
||||
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 * 9-20 * *", "Wed Jul 10 00:20:15 2012"},
|
||||
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 * 9-20 Jul *", "Wed Jul 10 00:20:15 2012"},
|
||||
|
||||
// Wrap around months
|
||||
{"Mon Jul 9 23:35 2012", "0 0 0 9 Apr-Oct ?", "Thu Aug 9 00:00 2012"},
|
||||
{"Mon Jul 9 23:35 2012", "0 0 0 */5 Apr,Aug,Oct Mon", "Tue Aug 1 00:00 2012"},
|
||||
{"Mon Jul 9 23:35 2012", "0 0 0 */5 Oct Mon", "Mon Oct 1 00:00 2012"},
|
||||
|
||||
// Wrap around years
|
||||
{"Mon Jul 9 23:35 2012", "0 0 0 * Feb Mon", "Mon Feb 4 00:00 2013"},
|
||||
{"Mon Jul 9 23:35 2012", "0 0 0 * Feb Mon/2", "Fri Feb 1 00:00 2013"},
|
||||
|
||||
// Wrap around minute, hour, day, month, and year
|
||||
{"Mon Dec 31 23:59:45 2012", "0 * * * * *", "Tue Jan 1 00:00:00 2013"},
|
||||
|
||||
// Leap year
|
||||
{"Mon Jul 9 23:35 2012", "0 0 0 29 Feb ?", "Mon Feb 29 00:00 2016"},
|
||||
|
||||
// Daylight savings time 2am EST (-5) -> 3am EDT (-4)
|
||||
{"2012-03-11T00:00:00-0500", "TZ=America/New_York 0 30 2 11 Mar ?", "2013-03-11T02:30:00-0400"},
|
||||
|
||||
// hourly job
|
||||
{"2012-03-11T00:00:00-0500", "TZ=America/New_York 0 0 * * * ?", "2012-03-11T01:00:00-0500"},
|
||||
{"2012-03-11T01:00:00-0500", "TZ=America/New_York 0 0 * * * ?", "2012-03-11T03:00:00-0400"},
|
||||
{"2012-03-11T03:00:00-0400", "TZ=America/New_York 0 0 * * * ?", "2012-03-11T04:00:00-0400"},
|
||||
{"2012-03-11T04:00:00-0400", "TZ=America/New_York 0 0 * * * ?", "2012-03-11T05:00:00-0400"},
|
||||
|
||||
// hourly job using CRON_TZ
|
||||
{"2012-03-11T00:00:00-0500", "CRON_TZ=America/New_York 0 0 * * * ?", "2012-03-11T01:00:00-0500"},
|
||||
{"2012-03-11T01:00:00-0500", "CRON_TZ=America/New_York 0 0 * * * ?", "2012-03-11T03:00:00-0400"},
|
||||
{"2012-03-11T03:00:00-0400", "CRON_TZ=America/New_York 0 0 * * * ?", "2012-03-11T04:00:00-0400"},
|
||||
{"2012-03-11T04:00:00-0400", "CRON_TZ=America/New_York 0 0 * * * ?", "2012-03-11T05:00:00-0400"},
|
||||
|
||||
// 1am nightly job
|
||||
{"2012-03-11T00:00:00-0500", "TZ=America/New_York 0 0 1 * * ?", "2012-03-11T01:00:00-0500"},
|
||||
{"2012-03-11T01:00:00-0500", "TZ=America/New_York 0 0 1 * * ?", "2012-03-12T01:00:00-0400"},
|
||||
|
||||
// 2am nightly job (skipped)
|
||||
{"2012-03-11T00:00:00-0500", "TZ=America/New_York 0 0 2 * * ?", "2012-03-12T02:00:00-0400"},
|
||||
|
||||
// Daylight savings time 2am EDT (-4) => 1am EST (-5)
|
||||
{"2012-11-04T00:00:00-0400", "TZ=America/New_York 0 30 2 04 Nov ?", "2012-11-04T02:30:00-0500"},
|
||||
{"2012-11-04T01:45:00-0400", "TZ=America/New_York 0 30 1 04 Nov ?", "2012-11-04T01:30:00-0500"},
|
||||
|
||||
// hourly job
|
||||
{"2012-11-04T00:00:00-0400", "TZ=America/New_York 0 0 * * * ?", "2012-11-04T01:00:00-0400"},
|
||||
{"2012-11-04T01:00:00-0400", "TZ=America/New_York 0 0 * * * ?", "2012-11-04T01:00:00-0500"},
|
||||
{"2012-11-04T01:00:00-0500", "TZ=America/New_York 0 0 * * * ?", "2012-11-04T02:00:00-0500"},
|
||||
|
||||
// 1am nightly job (runs twice)
|
||||
{"2012-11-04T00:00:00-0400", "TZ=America/New_York 0 0 1 * * ?", "2012-11-04T01:00:00-0400"},
|
||||
{"2012-11-04T01:00:00-0400", "TZ=America/New_York 0 0 1 * * ?", "2012-11-04T01:00:00-0500"},
|
||||
{"2012-11-04T01:00:00-0500", "TZ=America/New_York 0 0 1 * * ?", "2012-11-05T01:00:00-0500"},
|
||||
|
||||
// 2am nightly job
|
||||
{"2012-11-04T00:00:00-0400", "TZ=America/New_York 0 0 2 * * ?", "2012-11-04T02:00:00-0500"},
|
||||
{"2012-11-04T02:00:00-0500", "TZ=America/New_York 0 0 2 * * ?", "2012-11-05T02:00:00-0500"},
|
||||
|
||||
// 3am nightly job
|
||||
{"2012-11-04T00:00:00-0400", "TZ=America/New_York 0 0 3 * * ?", "2012-11-04T03:00:00-0500"},
|
||||
{"2012-11-04T03:00:00-0500", "TZ=America/New_York 0 0 3 * * ?", "2012-11-05T03:00:00-0500"},
|
||||
|
||||
// hourly job
|
||||
{"TZ=America/New_York 2012-11-04T00:00:00-0400", "0 0 * * * ?", "2012-11-04T01:00:00-0400"},
|
||||
{"TZ=America/New_York 2012-11-04T01:00:00-0400", "0 0 * * * ?", "2012-11-04T01:00:00-0500"},
|
||||
{"TZ=America/New_York 2012-11-04T01:00:00-0500", "0 0 * * * ?", "2012-11-04T02:00:00-0500"},
|
||||
|
||||
// 1am nightly job (runs twice)
|
||||
{"TZ=America/New_York 2012-11-04T00:00:00-0400", "0 0 1 * * ?", "2012-11-04T01:00:00-0400"},
|
||||
{"TZ=America/New_York 2012-11-04T01:00:00-0400", "0 0 1 * * ?", "2012-11-04T01:00:00-0500"},
|
||||
{"TZ=America/New_York 2012-11-04T01:00:00-0500", "0 0 1 * * ?", "2012-11-05T01:00:00-0500"},
|
||||
|
||||
// 2am nightly job
|
||||
{"TZ=America/New_York 2012-11-04T00:00:00-0400", "0 0 2 * * ?", "2012-11-04T02:00:00-0500"},
|
||||
{"TZ=America/New_York 2012-11-04T02:00:00-0500", "0 0 2 * * ?", "2012-11-05T02:00:00-0500"},
|
||||
|
||||
// 3am nightly job
|
||||
{"TZ=America/New_York 2012-11-04T00:00:00-0400", "0 0 3 * * ?", "2012-11-04T03:00:00-0500"},
|
||||
{"TZ=America/New_York 2012-11-04T03:00:00-0500", "0 0 3 * * ?", "2012-11-05T03:00:00-0500"},
|
||||
|
||||
// Unsatisfiable
|
||||
{"Mon Jul 9 23:35 2012", "0 0 0 30 Feb ?", ""},
|
||||
{"Mon Jul 9 23:35 2012", "0 0 0 31 Apr ?", ""},
|
||||
|
||||
// Monthly job
|
||||
{"TZ=America/New_York 2012-11-04T00:00:00-0400", "0 0 3 3 * ?", "2012-12-03T03:00:00-0500"},
|
||||
|
||||
// Test the scenario of DST resulting in midnight not being a valid time.
|
||||
// https://github.com/robfig/cron/issues/157
|
||||
{"2018-10-17T05:00:00-0400", "TZ=America/Sao_Paulo 0 0 9 10 * ?", "2018-11-10T06:00:00-0500"},
|
||||
{"2018-02-14T05:00:00-0500", "TZ=America/Sao_Paulo 0 0 9 22 * ?", "2018-02-22T07:00:00-0500"},
|
||||
}
|
||||
|
||||
for _, c := range runs {
|
||||
sched, err := secondParser.Parse(c.spec)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
actual := sched.Next(getTime(c.time))
|
||||
expected := getTime(c.expected)
|
||||
if !actual.Equal(expected) {
|
||||
t.Errorf("%s, \"%s\": (expected) %v != %v (actual)", c.time, c.spec, expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrors(t *testing.T) {
|
||||
invalidSpecs := []string{
|
||||
"xyz",
|
||||
"60 0 * * *",
|
||||
"0 60 * * *",
|
||||
"0 0 * * XYZ",
|
||||
}
|
||||
for _, spec := range invalidSpecs {
|
||||
_, err := ParseStandard(spec)
|
||||
if err == nil {
|
||||
t.Error("expected an error parsing: ", spec)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getTime(value string) time.Time {
|
||||
if value == "" {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
var location = time.Local
|
||||
if strings.HasPrefix(value, "TZ=") {
|
||||
parts := strings.Fields(value)
|
||||
loc, err := time.LoadLocation(parts[0][len("TZ="):])
|
||||
if err != nil {
|
||||
panic("could not parse location:" + err.Error())
|
||||
}
|
||||
location = loc
|
||||
value = parts[1]
|
||||
}
|
||||
|
||||
var layouts = []string{
|
||||
"Mon Jan 2 15:04 2006",
|
||||
"Mon Jan 2 15:04:05 2006",
|
||||
}
|
||||
for _, layout := range layouts {
|
||||
if t, err := time.ParseInLocation(layout, value, location); err == nil {
|
||||
return t
|
||||
}
|
||||
}
|
||||
if t, err := time.ParseInLocation("2006-01-02T15:04:05-0700", value, location); err == nil {
|
||||
return t
|
||||
}
|
||||
panic("could not parse time value " + value)
|
||||
}
|
||||
|
||||
func TestNextWithTz(t *testing.T) {
|
||||
runs := []struct {
|
||||
time, spec string
|
||||
expected string
|
||||
}{
|
||||
// Failing tests
|
||||
{"2016-01-03T13:09:03+0530", "14 14 * * *", "2016-01-03T14:14:00+0530"},
|
||||
{"2016-01-03T04:09:03+0530", "14 14 * * ?", "2016-01-03T14:14:00+0530"},
|
||||
|
||||
// Passing tests
|
||||
{"2016-01-03T14:09:03+0530", "14 14 * * *", "2016-01-03T14:14:00+0530"},
|
||||
{"2016-01-03T14:00:00+0530", "14 14 * * ?", "2016-01-03T14:14:00+0530"},
|
||||
}
|
||||
for _, c := range runs {
|
||||
sched, err := ParseStandard(c.spec)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
actual := sched.Next(getTimeTZ(c.time))
|
||||
expected := getTimeTZ(c.expected)
|
||||
if !actual.Equal(expected) {
|
||||
t.Errorf("%s, \"%s\": (expected) %v != %v (actual)", c.time, c.spec, expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getTimeTZ(value string) time.Time {
|
||||
if value == "" {
|
||||
return time.Time{}
|
||||
}
|
||||
t, err := time.Parse("Mon Jan 2 15:04 2006", value)
|
||||
if err != nil {
|
||||
t, err = time.Parse("Mon Jan 2 15:04:05 2006", value)
|
||||
if err != nil {
|
||||
t, err = time.Parse("2006-01-02T15:04:05-0700", value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// https://github.com/robfig/cron/issues/144
|
||||
func TestSlash0NoHang(t *testing.T) {
|
||||
schedule := "TZ=America/New_York 15/0 * * * *"
|
||||
_, err := ParseStandard(schedule)
|
||||
if err == nil {
|
||||
t.Error("expected an error on 0 increment")
|
||||
}
|
||||
}
|
||||
451
src/server/db/Mysql.go
Normal file
451
src/server/db/Mysql.go
Normal file
@ -0,0 +1,451 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
//"database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"server/GoUtil"
|
||||
"server/conf"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"strings"
|
||||
|
||||
// "server/game"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
type user struct {
|
||||
Id int `db:"user_id"`
|
||||
Sex int `db:"sex"`
|
||||
UserName string `db:"username"`
|
||||
Email string `db:"email"`
|
||||
}
|
||||
|
||||
var SqlDb *sqlx.DB
|
||||
|
||||
func InitDB() {
|
||||
//"用户名:密码@[连接方式](主机名:端口号)/数据库名"
|
||||
connect := fmt.Sprintf("%s:%s@(%s:%s)/%s", conf.Server.MySqlUsr, conf.Server.MySqlPwd, conf.Server.MySqlAddr, conf.Server.MySqlPort, conf.Server.DbName)
|
||||
SqlDb = sqlx.MustConnect("mysql", connect) // 设置连接数据库的参数
|
||||
SqlDb.SetMaxOpenConns(20) // 设置最大打开的连接数
|
||||
log.Debug("connect mysql success")
|
||||
}
|
||||
|
||||
func SeriesTransaction(sqlstrs []string, params [][]any) (err error) {
|
||||
tx, err := SqlDb.Begin()
|
||||
if err != nil {
|
||||
log.Debug("Transaction failed, err:%v\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.Debug("Transaction failed, err:%v\n", err)
|
||||
_ = tx.Rollback()
|
||||
} else {
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
for i := 0; i < len(sqlstrs); i++ {
|
||||
_, err := tx.Exec(sqlstrs[i], params[i]...)
|
||||
if err != nil {
|
||||
log.Debug("Transaction failed, err:%v\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 更新数据
|
||||
func FormatUpdateOneAttrRow(u interface{}, tableName string, UpdateAttr string, Exclude string) (err error) {
|
||||
t := reflect.TypeOf(u)
|
||||
len1 := t.Elem().NumField()
|
||||
Fields := make([]string, len1)
|
||||
Values := make([]interface{}, len1)
|
||||
pp := reflect.ValueOf(u)
|
||||
origin := "UPDATE " + tableName + " SET "
|
||||
index := 0
|
||||
var keyValue interface{}
|
||||
for i := 0; i < len1; i++ {
|
||||
field := t.Elem().Field(i)
|
||||
if field.Tag.Get("db") != Exclude {
|
||||
if field.Tag.Get("db") == UpdateAttr {
|
||||
Fields[index] = field.Tag.Get("db") + " = ?"
|
||||
|
||||
ufield := pp.Elem().FieldByName(field.Name)
|
||||
k := ufield.Kind()
|
||||
if k == reflect.String {
|
||||
Values[index] = ufield.String()
|
||||
}
|
||||
if k == reflect.Int32 {
|
||||
Values[index] = ufield.Int()
|
||||
}
|
||||
index++
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
ufield := pp.Elem().FieldByName(field.Name)
|
||||
k := ufield.Kind()
|
||||
if k == reflect.String {
|
||||
keyValue = ufield.String()
|
||||
}
|
||||
if k == reflect.Int32 {
|
||||
keyValue = ufield.Int()
|
||||
}
|
||||
}
|
||||
}
|
||||
Values[index] = keyValue
|
||||
// Values = append(Values, keyValue)
|
||||
origin += strings.Join(Fields, ",")
|
||||
strLen := len(origin)
|
||||
origin = origin[:strLen-1]
|
||||
origin = origin + " WHERE " + Exclude + " = ?"
|
||||
sqlStr := origin
|
||||
_, err = SqlDb.Exec(sqlStr, Values...)
|
||||
if err != nil {
|
||||
log.Debug("table: %s, sql :%s, exec failed, err:%v\n", tableName, sqlStr, err)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// "UPDATE user SET age = ?, degree = ? WHERE id = ?"
|
||||
func FormatAllMemUpdateDb(u interface{}, tableName string, Exclude string) (err error) {
|
||||
t := reflect.TypeOf(u)
|
||||
len1 := t.Elem().NumField()
|
||||
Fields := make([]string, len1)
|
||||
Values := make([]interface{}, len1)
|
||||
pp := reflect.ValueOf(u)
|
||||
origin := "UPDATE " + tableName + " SET "
|
||||
index := 0
|
||||
var keyValue interface{}
|
||||
for i := 0; i < len1; i++ {
|
||||
field := t.Elem().Field(i)
|
||||
if field.Tag.Get("db") != Exclude {
|
||||
Fields[index] = "`" + field.Tag.Get("db") + "` = ?"
|
||||
|
||||
ufield := pp.Elem().FieldByName(field.Name)
|
||||
k := ufield.Kind()
|
||||
if k == reflect.String {
|
||||
Values[index] = ufield.String()
|
||||
}
|
||||
if k == reflect.Int32 || k == reflect.Int || k == reflect.Int64 {
|
||||
Values[index] = ufield.Int()
|
||||
}
|
||||
index++
|
||||
} else {
|
||||
ufield := pp.Elem().FieldByName(field.Name)
|
||||
k := ufield.Kind()
|
||||
if k == reflect.String {
|
||||
keyValue = ufield.String()
|
||||
}
|
||||
if k == reflect.Int32 || k == reflect.Int {
|
||||
keyValue = ufield.Int()
|
||||
}
|
||||
}
|
||||
}
|
||||
Values[index] = keyValue
|
||||
// Values = append(Values, keyValue)
|
||||
origin += strings.Join(Fields, ",")
|
||||
strLen := len(origin)
|
||||
origin = origin[:strLen-1]
|
||||
origin = origin + " WHERE `" + Exclude + "` = ?"
|
||||
sqlStr := origin
|
||||
|
||||
_, err = SqlDb.Exec(sqlStr, Values...)
|
||||
if err != nil {
|
||||
log.Debug("table: %s, sql :%s, exec failed, err:%v\n", tableName, sqlStr, err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
func FormatAllMemInsertDb(u interface{}, tableName string) (insertID int64, err error) {
|
||||
t := reflect.TypeOf(u)
|
||||
len := t.Elem().NumField()
|
||||
Fields := make([]string, len)
|
||||
Fields1 := make([]string, len)
|
||||
FieldNames := make([]string, len)
|
||||
Values := make([]interface{}, len)
|
||||
pp := reflect.ValueOf(u)
|
||||
origin := "INSERT INTO " + tableName + "("
|
||||
for i := 0; i < len; i++ {
|
||||
field := t.Elem().Field(i)
|
||||
Fields[i] = field.Tag.Get("db")
|
||||
Fields1[i] = "?"
|
||||
FieldNames[i] = field.Name
|
||||
ufield := pp.Elem().FieldByName(field.Name)
|
||||
k := ufield.Kind()
|
||||
if k == reflect.String {
|
||||
Values[i] = ufield.String()
|
||||
}
|
||||
if k == reflect.Int32 {
|
||||
Values[i] = ufield.Int()
|
||||
}
|
||||
}
|
||||
for i := range Fields {
|
||||
Fields[i] = "`" + Fields[i] + "`"
|
||||
}
|
||||
origin += strings.Join(Fields, ",")
|
||||
origin += ") VALUES("
|
||||
origin += strings.Join(Fields1, ",")
|
||||
origin += ")"
|
||||
sqlStr := origin
|
||||
result, err := SqlDb.Exec(sqlStr, Values...)
|
||||
if err != nil {
|
||||
log.Debug("table: %s, sql :%s, exec failed, err:%v\n", tableName, sqlStr, err)
|
||||
return
|
||||
}
|
||||
insertID, err = result.LastInsertId()
|
||||
if err != nil {
|
||||
log.Debug("table: %s, sql :%s, exec failed, err:%v\n", tableName, sqlStr, err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetPlayerBaseInfoFromDbByName(name string) *ResPlayerBaseInfo {
|
||||
sqlStr := "SELECT * FROM t_player_baseinfo WHERE user_name = ?"
|
||||
var res ResPlayerBaseInfo
|
||||
if err := SqlDb.Get(&res, sqlStr, name); err != nil {
|
||||
log.Debug("table: %s, sql :%s, exec failed, err:%v\n", "PlayerBaseInfo", sqlStr, err)
|
||||
return nil
|
||||
}
|
||||
return &res
|
||||
}
|
||||
|
||||
func GetPlayerBaseInfoFromDbById(id int32) *ResPlayerBaseInfo {
|
||||
sqlStr := "SELECT * FROM t_player_baseinfo WHERE dwUin = ?"
|
||||
var res ResPlayerBaseInfo
|
||||
if err := SqlDb.Get(&res, sqlStr, id); err != nil {
|
||||
log.Debug("table: %s, sql :%s, exec failed, err:%v\n", "PlayerBaseInfo", sqlStr, err)
|
||||
return nil
|
||||
}
|
||||
return &res
|
||||
}
|
||||
|
||||
func GetAccountInfoFromDb(name string) *Db_Account {
|
||||
sqlStr := "SELECT * FROM t_account WHERE user_name = ?"
|
||||
var res Db_Account
|
||||
if err := SqlDb.Get(&res, sqlStr, name); err != nil {
|
||||
log.Debug("table: %s, sql :%s, exec failed, err:%v\n", "account", sqlStr, err)
|
||||
return nil
|
||||
}
|
||||
return &res
|
||||
}
|
||||
|
||||
func FormatAllMemLoadDb(u interface{}, tableName string, Exclude string) (err error) {
|
||||
t := reflect.TypeOf(u)
|
||||
len := t.Elem().NumField()
|
||||
Fields := make([]string, len)
|
||||
Values := make([]interface{}, len)
|
||||
pp := reflect.ValueOf(u)
|
||||
origin := "SELECT * FROM " + tableName + " WHERE "
|
||||
index := 0
|
||||
var keyValue interface{}
|
||||
for i := 0; i < len; i++ {
|
||||
field := t.Elem().Field(i)
|
||||
if field.Tag.Get("db") != Exclude {
|
||||
Fields[index] = field.Tag.Get("db") + " = ?"
|
||||
|
||||
ufield := pp.Elem().FieldByName(field.Name)
|
||||
k := ufield.Kind()
|
||||
if k == reflect.String {
|
||||
Values[index] = ufield.String()
|
||||
}
|
||||
if k == reflect.Int32 || k == reflect.Int || k == reflect.Int64 {
|
||||
Values[index] = ufield.Int()
|
||||
}
|
||||
index++
|
||||
} else {
|
||||
|
||||
ufield := pp.Elem().FieldByName(field.Name)
|
||||
k := ufield.Kind()
|
||||
if k == reflect.String {
|
||||
keyValue = ufield.String()
|
||||
}
|
||||
if k == reflect.Int32 {
|
||||
keyValue = ufield.Int()
|
||||
}
|
||||
}
|
||||
}
|
||||
Values[index] = keyValue
|
||||
// Values = append(Values, keyValue)
|
||||
origin += strings.Join(Fields, " AND ")
|
||||
sqlStr := origin
|
||||
if err := SqlDb.Get(u, sqlStr, Values...); err != nil {
|
||||
log.Debug("table: %s, sql :%s, exec failed, err:%v\n", tableName, sqlStr, err)
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetServerData(d interface{}, Key string) (err error) {
|
||||
sql := "select * from t_server_mod where `key` = ?"
|
||||
err = SqlDb.Get(d, sql, Key)
|
||||
return
|
||||
}
|
||||
|
||||
func SaveServerData(data *SqlServerModStruct) error {
|
||||
sql := "update t_server_mod set `mData` = ? , `updateTime` = ? where `key` = ?"
|
||||
_, err := SqlDb.Exec(sql, data.ModData, data.UpdataTime, data.Key)
|
||||
return err
|
||||
}
|
||||
|
||||
func InsertServerData(data *SqlServerModStruct) error {
|
||||
sql := "insert into t_server_mod (`mData` , `updateTime` ,`key`) Values (?,?,?)"
|
||||
_, err := SqlDb.Exec(sql, data.ModData, data.UpdataTime, data.Key)
|
||||
return err
|
||||
}
|
||||
|
||||
func SavePlayerModData(data *SqlModStruct) error {
|
||||
sql := "INSERT INTO `t_player_mod` (`mData` , `updateTime` ,`dwUin`) Values (?,?,?) ON DUPLICATE KEY UPDATE `mData` = ? , `updateTime` = ? "
|
||||
_, err := SqlDb.Exec(sql, data.ModData, data.UpdataTime, data.DwUin, data.ModData, data.UpdataTime)
|
||||
return err
|
||||
}
|
||||
|
||||
func InsertPlayerModData(data *SqlModStruct) error {
|
||||
sql := "insert into t_player_mod (`mData` , `updateTime` ,`dwUin`) Values (?,?,?)"
|
||||
_, err := SqlDb.Exec(sql, data.ModData, data.UpdataTime, data.DwUin)
|
||||
return err
|
||||
}
|
||||
|
||||
func SavePlayerClientData(data *SqlModStruct) error {
|
||||
sql := "INSERT INTO `t_player_client_data` (`mData` , `updateTime` ,`dwUin`) Values (?,?,?) ON DUPLICATE KEY UPDATE `mData` = ? , `updateTime` = ? "
|
||||
_, err := SqlDb.Exec(sql, data.ModData, data.UpdataTime, data.DwUin, data.ModData, data.UpdataTime)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetPlayerClientData(d interface{}, Key string) (err error) {
|
||||
sql := "select * from t_server_mod where `dwUin` = ?"
|
||||
err = SqlDb.Get(d, sql, Key)
|
||||
return
|
||||
}
|
||||
|
||||
func InsertData(u interface{}, tableName string) (insertID int64, err error) {
|
||||
t := reflect.TypeOf(u)
|
||||
len := t.Elem().NumField()
|
||||
Fields := make([]string, 0)
|
||||
Fields1 := make([]string, 0)
|
||||
Values := make([]interface{}, 0)
|
||||
pp := reflect.ValueOf(u)
|
||||
origin := "INSERT INTO " + tableName + "("
|
||||
for i := 0; i < len; i++ {
|
||||
field := t.Elem().Field(i)
|
||||
if field.Tag.Get("db") == "id" {
|
||||
continue
|
||||
}
|
||||
|
||||
ufield := pp.Elem().FieldByName(field.Name)
|
||||
k := ufield.Kind()
|
||||
if k == reflect.String && ufield.String() == "" {
|
||||
continue
|
||||
}
|
||||
if (k == reflect.Int32 || k == reflect.Int || k == reflect.Int64) && ufield.Int() == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if k == reflect.String {
|
||||
Values = append(Values, ufield.String())
|
||||
}
|
||||
if k == reflect.Int32 || k == reflect.Int || k == reflect.Int64 {
|
||||
Values = append(Values, ufield.Int())
|
||||
}
|
||||
Fields = append(Fields, field.Tag.Get("db"))
|
||||
Fields1 = append(Fields1, "?")
|
||||
}
|
||||
for i := range Fields {
|
||||
Fields[i] = "`" + Fields[i] + "`"
|
||||
}
|
||||
origin += strings.Join(Fields, ",")
|
||||
origin += ") VALUES("
|
||||
origin += strings.Join(Fields1, ",")
|
||||
origin += ")"
|
||||
sqlStr := origin
|
||||
result, err := SqlDb.Exec(sqlStr, Values...)
|
||||
if err != nil {
|
||||
log.Debug("InsertData exec failed, sql : %s ;err:%v\n", sqlStr, err)
|
||||
return
|
||||
}
|
||||
insertID, err = result.LastInsertId()
|
||||
if err != nil {
|
||||
log.Debug("InsertData exec failed, err:%v\n", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func UpdateData(u interface{}, tableName string, Exclude string) (err error) {
|
||||
t := reflect.TypeOf(u)
|
||||
len1 := t.Elem().NumField()
|
||||
Fields := make([]string, 0)
|
||||
Values := make([]interface{}, 0)
|
||||
pp := reflect.ValueOf(u)
|
||||
origin := "UPDATE " + tableName + " SET "
|
||||
var ExcludeValue interface{}
|
||||
for i := 0; i < len1; i++ {
|
||||
field := t.Elem().Field(i)
|
||||
ufield := pp.Elem().FieldByName(field.Name)
|
||||
k := ufield.Kind()
|
||||
if field.Tag.Get("db") != Exclude && field.Tag.Get("db") != "id" {
|
||||
|
||||
if k == reflect.String {
|
||||
Values = append(Values, ufield.String())
|
||||
}
|
||||
if k == reflect.Int32 || k == reflect.Int || k == reflect.Int64 {
|
||||
Values = append(Values, ufield.Int())
|
||||
}
|
||||
Fields = append(Fields, "`"+field.Tag.Get("db")+"` = ?")
|
||||
}
|
||||
if field.Tag.Get("db") == Exclude {
|
||||
if k == reflect.String {
|
||||
ExcludeValue = ufield.String()
|
||||
}
|
||||
if k == reflect.Int32 || k == reflect.Int || k == reflect.Int64 {
|
||||
ExcludeValue = append(Values, ufield.Int())
|
||||
}
|
||||
}
|
||||
}
|
||||
Values = append(Values, ExcludeValue)
|
||||
origin += strings.Join(Fields, ",")
|
||||
origin = origin + " WHERE `" + Exclude + "` = ?"
|
||||
sqlStr := origin
|
||||
|
||||
_, err = SqlDb.Exec(sqlStr, Values...)
|
||||
if err != nil {
|
||||
log.Debug("update failed, sql %s err:%v\n", sqlStr, err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetServerMailData(data *[]*SqlServerMailStruct) error {
|
||||
sql := "select * from system_mail_info"
|
||||
err := SqlDb.Select(data, sql)
|
||||
return err
|
||||
}
|
||||
|
||||
func CreateOrderSn(Uid, ChargeId int, OrderSn, Platform, Channel string, Price float64, Currency string) error {
|
||||
sql := "insert into t_player_charge (`Uid`,`OrderId`, `ProductId`, `Price`,`Currency`, `CreateTime`, `PayPlatform`, `PayChannel`) Values (?,?,?,?,?,?,?,?)"
|
||||
Now := GoUtil.Now()
|
||||
_, err := SqlDb.Exec(sql, Uid, OrderSn, ChargeId, Price, Currency, Now, Platform, Channel)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetPlayerChargeData(OrderSn string) (*SqlChargeOrderStruct, error) {
|
||||
sql := "select * from t_player_charge where OrderId = ?"
|
||||
data := &SqlChargeOrderStruct{}
|
||||
err := SqlDb.Get(data, sql, OrderSn)
|
||||
return data, err
|
||||
}
|
||||
|
||||
func UpdatePlayerChargeData(data *SqlChargeOrderStruct) error {
|
||||
sql := "update t_player_charge set PayTime = ?, PayStatus = ?, PayChannelOrderId = ? where OrderId = ?"
|
||||
_, err := SqlDb.Exec(sql, data.PayTime, data.PayStatus, data.PayChannelOrderId, data.OrderId)
|
||||
return err
|
||||
}
|
||||
87
src/server/db/Redis.go
Normal file
87
src/server/db/Redis.go
Normal file
@ -0,0 +1,87 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"server/conf"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"time"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
var ctx = context.Background()
|
||||
|
||||
var Rdb *redis.Client
|
||||
|
||||
func InitRedis() {
|
||||
rdb := redis.NewClient(&redis.Options{
|
||||
Addr: conf.Server.RedisAddr + ":" + conf.Server.RedisPort,
|
||||
Password: conf.Server.RedisPwd, // no password set
|
||||
DB: 0,
|
||||
})
|
||||
|
||||
_, err := rdb.Ping(ctx).Result()
|
||||
if err != nil {
|
||||
log.Debug("连接redis出错,错误信息:%v", err)
|
||||
return
|
||||
}
|
||||
log.Debug("成功连接redis")
|
||||
Rdb = rdb
|
||||
}
|
||||
|
||||
func RedisSetKey(key string, value string, expiration time.Duration) {
|
||||
err := Rdb.Set(ctx, key, value, expiration).Err()
|
||||
if err != nil {
|
||||
log.Debug("redis set failed, err:%v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取锁
|
||||
func RedisLock(key string, value string, expiration time.Duration) bool {
|
||||
ok, err := Rdb.SetNX(ctx, key, value, expiration).Result()
|
||||
if err != nil {
|
||||
log.Debug("redis lock failed, err:%v\n", err)
|
||||
return false
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
// 释放锁
|
||||
func RedisUnlock(key string, value string) bool {
|
||||
script := `
|
||||
if redis.call("GET", KEYS[1]) == ARGV[1] then
|
||||
return redis.call("DEL", KEYS[1])
|
||||
else
|
||||
return 0
|
||||
end
|
||||
`
|
||||
result, err := Rdb.Eval(ctx, script, []string{key}, value).Result()
|
||||
if err != nil {
|
||||
log.Debug("redis unlock failed, err:%v\n", err)
|
||||
return false
|
||||
}
|
||||
return result.(int64) == 1
|
||||
}
|
||||
|
||||
func RedisGetKey(key string) (string, error) {
|
||||
val, err := Rdb.Get(ctx, key).Result()
|
||||
if err != nil {
|
||||
log.Debug("redis get failed, err:%v\n", err)
|
||||
return "", err
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func RedisDelKey(key string) {
|
||||
err := Rdb.Del(ctx, key).Err()
|
||||
if err != nil {
|
||||
log.Debug("redis del failed, err:%v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func RedisZAdd(key string, member string, score float64) {
|
||||
err := Rdb.ZAdd(ctx, key, redis.Z{Score: score, Member: member}).Err()
|
||||
if err != nil {
|
||||
log.Debug("redis zadd failed, err:%v\n", err)
|
||||
}
|
||||
}
|
||||
3
src/server/db/SqlQueryConst.go
Normal file
3
src/server/db/SqlQueryConst.go
Normal file
@ -0,0 +1,3 @@
|
||||
package db
|
||||
|
||||
const ()
|
||||
503
src/server/db/SqlStruct.go
Normal file
503
src/server/db/SqlStruct.go
Normal file
@ -0,0 +1,503 @@
|
||||
package db
|
||||
|
||||
type Db_GameServerInfo struct {
|
||||
Id string `db:"id"`
|
||||
GrowthfundBuynum string `db:"growthfund_buynum"`
|
||||
OpenServertime int `db:"open_servertime"`
|
||||
OpenActiveflag int `db:"open_activeflag"`
|
||||
DailyRenewTime int `db:"DailyRenewTime"`
|
||||
}
|
||||
|
||||
type Db_Account struct {
|
||||
UserName string `db:"user_name"`
|
||||
UserPassword string `db:"user_password"`
|
||||
LoginTime int `db:"login_time"`
|
||||
LogoutTime int `db:"logout_time"`
|
||||
Ip string `db:"ip_address"`
|
||||
GmLevel int `db:"gm_level"`
|
||||
Platform string `db:"platform"`
|
||||
IsOnline int `db:"is_online"`
|
||||
Channel string `db:"channel"`
|
||||
DeviceId string `db:"device_id"`
|
||||
AutoId int `db:"auto_id"`
|
||||
}
|
||||
|
||||
type ResPlayerBaseInfo struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
Energy int32 `db:"energy"`
|
||||
Star int32 `db:"star"`
|
||||
RecoverTime int32 `db:"recover_time"`
|
||||
Diamond int32 `db:"diamond"`
|
||||
Level int32 `db:"level"`
|
||||
Exp int32 `db:"exp"`
|
||||
StartOrderId string `db:"start_order_id"`
|
||||
MusicCode int32 `db:"music_code"`
|
||||
Guild int32 `db:"guild"`
|
||||
PackUnlockCount int32 `db:"pack_unlock_count"`
|
||||
LastPlayTime int32 `db:"last_play_time"`
|
||||
EnergyBuyCount int32 `db:"EnergyBuyCount"`
|
||||
UserName string `db:"user_name"`
|
||||
LoginTime int32 `db:"login_time"`
|
||||
LogoutTime int32 `db:"logout_time"`
|
||||
Todayolinetime int32 `db:"todayolinetime"`
|
||||
Rolecreatetime int32 `db:"rolecreatetime"`
|
||||
EmitOrderCnt int32 `db:"EmitOrderCnt"`
|
||||
DailyRenewTime int32 `db:"DailyRenewTime"`
|
||||
NoAd int32 `db:"NoAd"`
|
||||
ChampshipsGroupID int32 `db:"ChampshipsGroupID"`
|
||||
LastChampGroupID int32 `db:"LastChampGroupID"`
|
||||
FaceBookId string `db:"FaceBookId"`
|
||||
}
|
||||
|
||||
type SqlKeyValueStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
Keys string `db:"ReqKeys"`
|
||||
Vals string `db:"ReqVals"`
|
||||
}
|
||||
type SqlEmitUnlockStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
Value string `db:"EmitUnlockDat"`
|
||||
RenewTime int32 `db:"RenewTime"`
|
||||
}
|
||||
|
||||
type SqlPackStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
MPackData string `db:"mPackData"`
|
||||
}
|
||||
|
||||
type SqlChessStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
MChessData string `db:"mChessData"`
|
||||
MChessColorData string `db:"mChessColorData"`
|
||||
}
|
||||
|
||||
type SqlGiftStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
MGiftData string `db:"mGiftData"`
|
||||
}
|
||||
|
||||
type SqlOrderStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
FinishOrderCount int32 `db:"finishOrderCount"`
|
||||
FinishOrderTime int32 `db:"finishOrderTime"`
|
||||
MOrderData string `db:"mOrderData"`
|
||||
RenewTime int32 `db:"RenewTime"`
|
||||
}
|
||||
|
||||
type SqlVersionStruct struct {
|
||||
Id int32 `db:"id"`
|
||||
StartTime int32 `db:"start_time"`
|
||||
CloseTime int32 `db:"close_time"`
|
||||
IsClose int32 `db:"is_close"`
|
||||
}
|
||||
|
||||
type SqlChestStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
ChestID int32 `db:"ChestID"`
|
||||
UnlockStartTime int32 `db:"UnlockStartTime"`
|
||||
}
|
||||
|
||||
type SqlEmitStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
MEmitMergeData string `db:"mEmitMergeData"`
|
||||
MEmitCountData string `db:"mEmitCountData"`
|
||||
MEmitTimeData string `db:"mEmitTimeData"`
|
||||
}
|
||||
|
||||
type SqlDecorateStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
MDecorateData string `db:"mDecorateData"`
|
||||
MFinishList string `db:"mFinishList"`
|
||||
}
|
||||
|
||||
type SqlLevelUpPackStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
CurBuyedLv int32 `db:"CurBuyedLv"`
|
||||
}
|
||||
|
||||
type SqlGrowthFundStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
CurBuyLv string `db:"CurGetLv"`
|
||||
IsBuy int32 `db:"IsBuy"`
|
||||
}
|
||||
|
||||
type SqlSupermeGiftStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
|
||||
IsBuy int32 `db:"IsBuy"`
|
||||
NoAdStartTime int32 `db:"NoAdStartTime"`
|
||||
NoAdEndTime int32 `db:"NoAdEndTime"`
|
||||
StorgeStartTime int32 `db:"StorgeStartTime"`
|
||||
StorgeEndTime int32 `db:"StorgeEndTime"`
|
||||
}
|
||||
|
||||
type SqlDailyTaskStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
StartDailySvrTime int32 `db:"StartDailySvrTime"`
|
||||
StartWeekySvrTime int32 `db:"StartWeekySvrTime"`
|
||||
NowSortId int32 `db:"NowSortId"`
|
||||
WeekyActive int32 `db:"WeekyActive"`
|
||||
NowTaskProgress int32 `db:"NowTaskProgress"`
|
||||
TodayTaskList string `db:"TodayTaskList"`
|
||||
}
|
||||
|
||||
type SqlNotify7DayLoginData struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
StartSvrTime int32 `db:"StartSvrTime"`
|
||||
GetIndex int32 `db:"GetIndex"`
|
||||
LastGetTime int32 `db:"LastGetTime"`
|
||||
MonthScore int32 `db:"MonthScore"`
|
||||
MonthStartTime int32 `db:"MonthStartTime"`
|
||||
IsCallBack int32 `db:"IsCallBack"`
|
||||
}
|
||||
|
||||
type SqlNotify7DayCallbackData struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
StartSvrTime int32 `db:"StartSvrTime"`
|
||||
GetIndex int32 `db:"GetIndex"`
|
||||
LastGetTime int32 `db:"LastGetTime"`
|
||||
}
|
||||
|
||||
type SqlPetHomeData struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
InterActEndTime int32 `db:"InterActEndTime"`
|
||||
NestId int32 `db:"NestId"`
|
||||
OrnamentsId int32 `db:"OrnamentsId"`
|
||||
CurInterActUin int32 `db:"CurInterActUin"`
|
||||
MiniGameResult int32 `db:"MiniGameResult"`
|
||||
SelfWorkTime int32 `db:"SelfWorkTime"`
|
||||
OtherWorkTime int32 `db:"OtherWorkTime"`
|
||||
UnlockPetNest string `db:"UnlockPetNest"`
|
||||
UnlockPetOrnaments string `db:"UnlockPetOrnaments"`
|
||||
UnlockPetEmotion string `db:"UnlockPetEmotion"`
|
||||
AtHome int32 `db:"AtHome"`
|
||||
UnlockDecorateList string `db:"UnlockDecorateList"`
|
||||
SelectDecorateMap string `db:"SelectDecorateMap"`
|
||||
Mood int32 `db:"Mood"`
|
||||
}
|
||||
|
||||
type SqlPetHomeInterAct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
TargetUin int32 `db:"TargetUin"`
|
||||
InterActEndTime int32 `db:"InterActEndTime"`
|
||||
AutoId int32 `db:"auto_id"`
|
||||
}
|
||||
|
||||
type SqlPlayerChampionData struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
IsEnterRank int32 `db:"IsEnterRank"`
|
||||
CurScore int32 `db:"CurScore"`
|
||||
CurMaxScore int32 `db:"CurMaxScore"`
|
||||
CurRank int32 `db:"CurRank"`
|
||||
TodayOpenTime int32 `db:"TodayOpenTime"`
|
||||
ChampshipsGroupID int32 `db:"ChampshipsGroupID"`
|
||||
LastChampGroupID int32 `db:"LastChampGroupID"`
|
||||
MaxHistoryScore int32 `db:"MaxHistoryScore"`
|
||||
HistoryData string `db:"HistoryData"`
|
||||
}
|
||||
|
||||
type SqlPlayerPetData struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
ImageFrame int32 `db:"ImageFrame"`
|
||||
ImageIcon int32 `db:"ImageIcon"`
|
||||
PetNickName string `db:"PetNickName"`
|
||||
UnlockFrame string `db:"UnlockFrame"`
|
||||
UnlockIcon string `db:"UnlockIcon"`
|
||||
}
|
||||
type SqlMileStoneStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
MileStoneScore int32 `db:"MileStoneScore"`
|
||||
StartMileStoneTime int32 `db:"StartMileStoneTime"`
|
||||
MileStoneTaskList string `db:"MileStoneTaskList"`
|
||||
}
|
||||
|
||||
type SqlSvrGlobalStruct struct {
|
||||
Id int32 `db:"Id"`
|
||||
StartMileStoneSvrTime int32 `db:"StartMileStoneSvrTime"`
|
||||
StartChampshipsSvrTime int32 `db:"StartChampshipsSvrTime"`
|
||||
InsertChampshipsSvrTime int32 `db:"InsertChampshipsSvrTime"`
|
||||
WaitToRank string `db:"WaitToRank"`
|
||||
Limit4CardExclude string `db:"Limit4CardExclude"`
|
||||
Limit5CardExclude string `db:"Limit5CardExclude"`
|
||||
CurChampshipsId int32 `db:"CurChampshipsId"`
|
||||
LastChampshipsId int32 `db:"LastChampshipsId"`
|
||||
Limit4Card int32 `db:"Limit4Card"`
|
||||
Limit5Card int32 `db:"Limit5Card"`
|
||||
LimitCardSwapTime int32 `db:"LimitCardSwapTime"`
|
||||
OpenSvrTime int32 `db:"OpenSvrTime"`
|
||||
}
|
||||
|
||||
type SqlChampionshipsStruct struct {
|
||||
CurChampshipsId int32 `db:"CurChampshipsId"`
|
||||
GroupRankData string `db:"GroupRankData"`
|
||||
ChampshipsGroupID int32 `db:"ChampshipsGroupID"`
|
||||
GroupActive int32 `db:"GroupActive"`
|
||||
}
|
||||
|
||||
type SqlIllustrateStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
IllustrateType int32 `db:"IllustrateType"`
|
||||
Category string `db:"Category"`
|
||||
ItemInfoStr string `db:"ItemInfoStr"`
|
||||
IllustratedID int32 `db:"IllustratedID"`
|
||||
}
|
||||
|
||||
type SqlShopInfoStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
EnergyAdCount int32 `db:"EnergyAdCount"`
|
||||
EnergyRenewTime int32 `db:"EnergyRenewTime"`
|
||||
DailyRenewTime int32 `db:"DailyRenewTime"`
|
||||
BuyEnergyTime int32 `db:"BuyEnergyTime"`
|
||||
MShopTimeBuyData string `db:"mShopTimeBuyData"`
|
||||
MShopSaleBuyData string `db:"mShopSaleBuyData"`
|
||||
MPackBuyData string `db:"mPackBuyData"`
|
||||
MItemRenewTimes int32 `db:"ItemRenewTimes"`
|
||||
MPackRenewTimes string `db:"mPackRenewTimes"`
|
||||
MSpecialOfferBuyData string `db:"MSpecialOfferBuyData"`
|
||||
MUISpecialOfferBuyData string `db:"MUISpecialOfferBuyData"`
|
||||
MFreePackBuyData string `db:"MFreePackBuyData"`
|
||||
MDiamondFirstBuyData string `db:"MDiamondFirstBuyData"`
|
||||
}
|
||||
|
||||
type SqlEmailStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
EmailId int32 `db:"mail_id"`
|
||||
Sender string `db:"sender"`
|
||||
Title string `db:"title"`
|
||||
Content string `db:"content"`
|
||||
CurrencyCount int32 `db:"currency_count"`
|
||||
CurrencyInfo string `db:"currency_info"`
|
||||
ItemCount int32 `db:"item_count"`
|
||||
ItemInfo string `db:"item_info"`
|
||||
SendTime int32 `db:"send_time"`
|
||||
RecvTime int32 `db:"recv_time"`
|
||||
Status int32 `db:"state"`
|
||||
Type int32 `db:"type"`
|
||||
RewardType string `db:"reward_type"`
|
||||
RewardId string `db:"reward_id"`
|
||||
RewardCount string `db:"reward_count"`
|
||||
LinkUrl string `db:"LinkUrl"`
|
||||
}
|
||||
|
||||
type SqlCompensateStruct struct {
|
||||
DeviceId string `db:"DeviceId"`
|
||||
IsSendEmail int32 `db:"IsSendEmail"`
|
||||
DecorationCnt int32 `db:"DecorationCnt"`
|
||||
ChargeCnt string `db:"ChargeCnt"`
|
||||
AutoId string `db:"auto_id"`
|
||||
}
|
||||
|
||||
type SqlLimitPassportStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
ActiveID int32 `db:"ActiveID"`
|
||||
StartSvrTime int32 `db:"StartSvrTime"`
|
||||
EndSvrTime int32 `db:"EndSvrTime"`
|
||||
Status int32 `db:"Status"`
|
||||
Star int32 `db:"Star"`
|
||||
IsPay int32 `db:"IsPay"`
|
||||
CurFreeLv int32 `db:"CurFreeLv"`
|
||||
CurPayLv int32 `db:"CurPayLv"`
|
||||
CurSvrTime int32 `db:"CurSvrTime"`
|
||||
ConfigActId int32 `db:"ConfigActId"`
|
||||
}
|
||||
|
||||
type SqlCardCollectStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
ActiveID int32 `db:"ActiveID"`
|
||||
StartSvrTime int32 `db:"StartSvrTime"`
|
||||
EndSvrTime int32 `db:"EndSvrTime"`
|
||||
Fragment int32 `db:"fragment"`
|
||||
CardInfo string `db:"CardInfo"`
|
||||
CardRewardInfo string `db:"CardRewardInfo"`
|
||||
MasterCards string `db:"MasterCards"`
|
||||
CurSvrTime int32 `db:"CurSvrTime"`
|
||||
FinalReward int32 `db:"FinalReward"`
|
||||
Universal int32 `db:"Universal"`
|
||||
RenewSvrTime int32 `db:"RenewSvrTime"`
|
||||
RenewExchangeTime int32 `db:"RenewExchangeTime"`
|
||||
RenewRequestTime int32 `db:"RenewRequestTime"`
|
||||
|
||||
ConfigActId int32 `db:"ConfigActId"`
|
||||
}
|
||||
|
||||
type SqlExchangeCardStruct struct {
|
||||
SenderId int32 `db:"SenderId"`
|
||||
ReceiveId int32 `db:"ReceiveId"`
|
||||
GroupId int32 `db:"GroupId"`
|
||||
ApplicateStatus int32 `db:"ApplicateStatus"`
|
||||
StartTime int32 `db:"StartTime"`
|
||||
EventType int32 `db:"EventType"`
|
||||
EventParam string `db:"EventParam"`
|
||||
ConfigActId int32 `db:"ConfigActId"`
|
||||
AutoId int32 `db:"auto_id"`
|
||||
}
|
||||
|
||||
type SqlExchangeCardReqIncStruct struct {
|
||||
StartTime int32 `db:"StartTime"`
|
||||
AutoId int32 `db:"auto_id"`
|
||||
}
|
||||
type SqlLimitPromotionStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
ActiveID int32 `db:"ActiveID"`
|
||||
StartSvrTime int32 `db:"StartSvrTime"`
|
||||
EndSvrTime int32 `db:"EndSvrTime"`
|
||||
IsPay int32 `db:"IsPay"`
|
||||
CurSvrTime int32 `db:"CurSvrTime"`
|
||||
ConfigActId int32 `db:"ConfigActId"`
|
||||
}
|
||||
|
||||
type SqlLimitInfinitePackStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
ActiveID int32 `db:"ActiveID"`
|
||||
StartSvrTime int32 `db:"StartSvrTime"`
|
||||
EndSvrTime int32 `db:"EndSvrTime"`
|
||||
CurGear int32 `db:"CurGear"`
|
||||
CurSvrTime int32 `db:"CurSvrTime"`
|
||||
ConfigActId int32 `db:"ConfigActId"`
|
||||
}
|
||||
|
||||
type SqlPlayerProfileStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
ImageFrame int32 `db:"ImageFrame"`
|
||||
ImageIcon int32 `db:"ImageIcon"`
|
||||
NickName string `db:"NickName"`
|
||||
PicURL string `db:"PicURL"`
|
||||
UnlockFrame string `db:"UnlockFrame"`
|
||||
UnlockIcon string `db:"UnlockIcon"`
|
||||
}
|
||||
|
||||
type SqlPigDetailInfoStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
PigType int32 `db:"PigType"`
|
||||
StartSvrTime int32 `db:"StartSvrTime"`
|
||||
EndSvrTime int32 `db:"EndSvrTime"`
|
||||
CurDiamonds int32 `db:"CurDiamonds"`
|
||||
CurSvrTime int32 `db:"CurSvrTime"`
|
||||
CurGetLv int32 `db:"CurGetLv"`
|
||||
PigId int32 `db:"PigId"`
|
||||
}
|
||||
|
||||
type SqlSevenDayLoginStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
ActiveID int32 `db:"ActiveID"`
|
||||
StartSvrTime int32 `db:"StartSvrTime"`
|
||||
EndSvrTime int32 `db:"EndSvrTime"`
|
||||
LastGetTime int32 `db:"LastGetTime"`
|
||||
CurSvrTime int32 `db:"CurSvrTime"`
|
||||
ConfigActId int32 `db:"ConfigActId"`
|
||||
GetIndex int32 `db:"GetIndex"`
|
||||
}
|
||||
|
||||
type SqlLimitDataStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
StartLimitTime int32 `db:"StartLimitTime"`
|
||||
EndLimitTime int32 `db:"EndLimitTime"`
|
||||
AddEndTime int32 `db:"AddEndTime"`
|
||||
ParamStr string `db:"ParamStr"`
|
||||
}
|
||||
|
||||
type SqlChampshipsStruct struct {
|
||||
CurChampshipsId int32 `db:"CurChampshipsId"`
|
||||
GroupRankData string `db:"GroupRankData"`
|
||||
ChampshipsGroupID int32 `db:"ChampshipsGroupID"`
|
||||
GroupActive int32 `db:"GroupActive"`
|
||||
}
|
||||
|
||||
type SqlAdPackStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
RenewDailyTime int32 `db:"RenewDailyTime"`
|
||||
Score int32 `db:"Score"`
|
||||
CurTurns int32 `db:"CurTurns"`
|
||||
PackData string `db:"PackData"`
|
||||
RewardInfo string `db:"RewardInfo"`
|
||||
}
|
||||
|
||||
type SqlSingleDataStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
NewbiePackBuyID int32 `db:"NewbiePackBuyID"`
|
||||
NewbiePackOpenTime int32 `db:"NewbiePackOpenTime"`
|
||||
NoAdCnt int32 `db:"NoAdCnt"`
|
||||
NoAdOpenSvrTime int32 `db:"NoAdOpenSvrTime"`
|
||||
WatchAdCnt int32 `db:"WatchAdCnt"`
|
||||
WatchAdOpenTime int32 `db:"WatchAdOpenTime"`
|
||||
LastWatchAdCnt int32 `db:"LastWatchAdCnt"`
|
||||
AllPayCnt string `db:"AllPayCnt"`
|
||||
}
|
||||
|
||||
type SqlChargeStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
PayTime int32 `db:"PayTime"`
|
||||
PayValue string `db:"PayValue"`
|
||||
Autoid int32 `db:"auto_id"`
|
||||
}
|
||||
|
||||
type SqlFriendStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
FriendList string `db:"FriendList"`
|
||||
TreasureStar int32 `db:"TreasureStar"`
|
||||
}
|
||||
|
||||
type SqlInviteFriendStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
GetIndex int32 `db:"GetIndex"`
|
||||
InviteList string `db:"InviteList"`
|
||||
}
|
||||
|
||||
type SqlFriendEventStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
EventStartTime int32 `db:"EventStartTime"`
|
||||
EventType int32 `db:"EventType"`
|
||||
EventParam string `db:"EventParam"`
|
||||
AutoId int32 `db:"auto_id"`
|
||||
}
|
||||
|
||||
type SqlAddFriendStruct struct {
|
||||
SenderId int32 `db:"SenderId"`
|
||||
ReceiverId int32 `db:"ReceiverId"`
|
||||
Auto_id int32 `db:"auto_id"`
|
||||
}
|
||||
|
||||
type SqlModStruct struct {
|
||||
DwUin int32 `db:"dwUin"`
|
||||
ModData []byte `db:"mData"`
|
||||
UpdataTime int32 `db:"updateTime"`
|
||||
}
|
||||
|
||||
type SqlServerModStruct struct {
|
||||
Id int `db:"id"`
|
||||
Key string `db:"key"`
|
||||
ModData []byte `db:"mData"`
|
||||
UpdataTime int64 `db:"updateTime"`
|
||||
}
|
||||
|
||||
type SqlServerMailStruct struct {
|
||||
Id int `db:"mail_id"`
|
||||
Title string `db:"title"`
|
||||
Content string `db:"content"`
|
||||
Items string `db:"items"`
|
||||
Start_time int64 `db:"start_time"`
|
||||
Register_time int64 `db:"register_time"`
|
||||
End_time int64 `db:"end_time"`
|
||||
Mail_type int `db:"mail_type"`
|
||||
To_uids string `db:"to_uids"`
|
||||
}
|
||||
|
||||
type SqlChargeOrderStruct struct {
|
||||
Id int `db:"id"`
|
||||
Uid int `db:"Uid"`
|
||||
OrderId string `db:"OrderId"`
|
||||
ProductId int `db:"ProductId"`
|
||||
ProductName string `db:"ProductName"`
|
||||
ProductDesc string `db:"ProductDesc"`
|
||||
Price float64 `db:"Price"`
|
||||
Currency string `db:"Currency"`
|
||||
CreateTime int64 `db:"CreateTime"`
|
||||
PayTime int64 `db:"PayTime"`
|
||||
PayStatus int `db:"PayStatus"`
|
||||
PayType int `db:"PayType"`
|
||||
PayPlatform string `db:"PayPlatform"`
|
||||
PayChannel string `db:"PayChannel"`
|
||||
PayChannelOrderId string `db:"PayChannelOrderId"`
|
||||
PayChannelUserId string `db:"PayChannelUserId"`
|
||||
PayChannelExtra string `db:"PayChannelExtra"`
|
||||
}
|
||||
785
src/server/game/ChampshipsManager.go
Normal file
785
src/server/game/ChampshipsManager.go
Normal file
@ -0,0 +1,785 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"server/GoUtil"
|
||||
"server/MergeConst"
|
||||
"server/db"
|
||||
"server/msg"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type ChampshipsManager struct {
|
||||
MStatus int32
|
||||
MChampshipMap map[int32]*db.SqlChampshipsStruct
|
||||
MChampshipPlayerMap map[int32][]*msg.ChampshipsPlayerInfo
|
||||
IsSettle int32
|
||||
IsLoadDB bool
|
||||
MUpdateNotifyList []int32
|
||||
McronSave *cron.Cron
|
||||
McronSaveID cron.EntryID
|
||||
RobotCronID cron.EntryID
|
||||
RobotCronID10s cron.EntryID
|
||||
MPlayerBaseInfoMap map[int32]*db.ResPlayerBaseInfo
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) SaveDataFromDB(Key interface{}) bool {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) AIGrow1() {
|
||||
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) DeleteOutLineChampship(CurChampshipsId int32) {
|
||||
sqlStr := "DELETE FROM t_championships_data WHERE CurChampshipsId = ?"
|
||||
|
||||
for k, v := range p.MChampshipPlayerMap {
|
||||
if v[0].CurChampshipsId == CurChampshipsId {
|
||||
delete(p.MChampshipPlayerMap, k)
|
||||
}
|
||||
}
|
||||
result, err := db.SqlDb.Exec(sqlStr, CurChampshipsId)
|
||||
if err != nil {
|
||||
fmt.Printf("exec failed, err:%v\n", err)
|
||||
return
|
||||
}
|
||||
affectedRows, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
fmt.Printf("get affected failed, err:%v\n", err)
|
||||
return
|
||||
} else {
|
||||
fmt.Printf("delete t_championships_data affectedRows:%d\n", affectedRows)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) DeleteUneffectPlayer(deleteIds []int32) {
|
||||
sqlStr := "DELETE FROM t_player_baseinfo WHERE dwUin = ?"
|
||||
|
||||
for i := 0; i < len(deleteIds); i++ {
|
||||
_, err := db.SqlDb.Exec(sqlStr, deleteIds[i])
|
||||
if err != nil {
|
||||
fmt.Printf("exec failed, err:%v\n", err)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) GetFriendListId(id int32) []int32 {
|
||||
|
||||
sqlStr := "SELECT * FROM t_player_Friend_Data WHERE dwUin = ?"
|
||||
sqlStruck := db.SqlFriendStruct{}
|
||||
ret := []int32{}
|
||||
|
||||
if err := db.SqlDb.Get(&sqlStruck, sqlStr, id); err != nil {
|
||||
fmt.Printf("get data failed, err:%v\n", err)
|
||||
|
||||
} else {
|
||||
if sqlStruck.FriendList != "" {
|
||||
arr := strings.Split(sqlStruck.FriendList, "_")
|
||||
for i := 0; i < len(arr); i++ {
|
||||
id, _ := strconv.ParseInt(arr[i], 10, 32)
|
||||
ret = append(ret, int32(id))
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) NotifyOpenNewChampShip(args []interface{}) {
|
||||
go func() {
|
||||
G_GameLogicPtr.M_SvrGlobal.CurChampshipsId = G_GameLogicPtr.M_SvrGlobal.CurChampshipsId + 1
|
||||
G_GameLogicPtr.M_SvrGlobal.StartChampshipsSvrTime = args[0].(int32)
|
||||
}()
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) OpenNewChampShip(args []interface{}) {
|
||||
|
||||
G_GameLogicPtr.M_SvrGlobal.CurChampshipsId = G_GameLogicPtr.M_SvrGlobal.CurChampshipsId + 1
|
||||
G_GameLogicPtr.M_SvrGlobal.StartChampshipsSvrTime = args[0].(int32)
|
||||
p.MUpdateNotifyList = []int32{}
|
||||
|
||||
sqlStr := "SELECT * FROM t_player_baseinfo"
|
||||
sqlStrucks := []db.ResPlayerBaseInfo{}
|
||||
if err := db.SqlDb.Select(&sqlStrucks, sqlStr); err != nil {
|
||||
fmt.Printf("get data failed, err:%v\n", err)
|
||||
return
|
||||
} else {
|
||||
|
||||
}
|
||||
deleteIds := []int32{}
|
||||
sqlStrucksList := []db.ResPlayerBaseInfo{}
|
||||
for i := 0; i < len(sqlStrucks); i++ {
|
||||
if sqlStrucks[i].UserName == "" {
|
||||
deleteIds = append(deleteIds, sqlStrucks[i].DwUin)
|
||||
} else {
|
||||
sqlStrucksList = append(sqlStrucksList, sqlStrucks[i])
|
||||
}
|
||||
}
|
||||
sqlStrucks = sqlStrucksList
|
||||
p.DeleteUneffectPlayer(deleteIds)
|
||||
|
||||
sort.Slice(sqlStrucks, func(i, j int) bool {
|
||||
if sqlStrucks[i].Level != sqlStrucks[j].Level {
|
||||
return sqlStrucks[i].Level < sqlStrucks[j].Level
|
||||
} else {
|
||||
return sqlStrucks[i].Exp < sqlStrucks[j].Exp
|
||||
}
|
||||
|
||||
})
|
||||
var playerCnt int = 15
|
||||
groups := int(math.Ceil((float64)(len(sqlStrucks)) / float64(playerCnt)))
|
||||
StartRobotUin := 200000
|
||||
p.MStatus = 1
|
||||
rand.Seed(time.Now().Unix())
|
||||
for i := 0; i < groups; i++ {
|
||||
if i < groups-1 {
|
||||
temp := db.SqlChampshipsStruct{}
|
||||
temp.CurChampshipsId = G_GameLogicPtr.M_SvrGlobal.CurChampshipsId
|
||||
CSPlayerInfo := []*msg.ChampshipsPlayerInfo{}
|
||||
|
||||
strr := []string{}
|
||||
for j := 0; j < int(playerCnt); j++ {
|
||||
dwUin := sqlStrucks[i*int(playerCnt)+j].DwUin
|
||||
res := strconv.Itoa(int(dwUin)) + "_" + "1" + "_" + "0" + "_" + "0" + "_" + "1" + "_" + strconv.Itoa(int(G_GameLogicPtr.M_SvrGlobal.CurChampshipsId)) + "_0"
|
||||
strr = append(strr, res)
|
||||
playerinfo := &msg.ChampshipsPlayerInfo{}
|
||||
playerinfo.DwUin = dwUin
|
||||
playerinfo.IsGet = 0
|
||||
playerinfo.IsPlayer = 1
|
||||
playerinfo.Score = 0
|
||||
playerinfo.Times = 1
|
||||
playerinfo.AIEnum = 0
|
||||
playerinfo.CurChampshipsId = G_GameLogicPtr.M_SvrGlobal.CurChampshipsId
|
||||
CSPlayerInfo = append(CSPlayerInfo, playerinfo)
|
||||
}
|
||||
for j := int(playerCnt); j < 30; j++ {
|
||||
StartRobotUin = StartRobotUin + 1
|
||||
dwUin := StartRobotUin
|
||||
enum := rand.Intn(4) + 1
|
||||
res := strconv.Itoa(int(dwUin)) + "_" + "0" + "_" + "0" + "_" + "0" + "_" + "1" + "_" + strconv.Itoa(int(G_GameLogicPtr.M_SvrGlobal.CurChampshipsId)) + "_" + strconv.Itoa(enum)
|
||||
strr = append(strr, res)
|
||||
playerinfo := &msg.ChampshipsPlayerInfo{}
|
||||
playerinfo.DwUin = int32(dwUin)
|
||||
playerinfo.IsGet = 0
|
||||
playerinfo.IsPlayer = 0
|
||||
playerinfo.Score = 0
|
||||
playerinfo.Times = 1
|
||||
playerinfo.AIEnum = int32(enum)
|
||||
playerinfo.CurChampshipsId = G_GameLogicPtr.M_SvrGlobal.CurChampshipsId
|
||||
CSPlayerInfo = append(CSPlayerInfo, playerinfo)
|
||||
}
|
||||
temp.GroupRankData = strings.Join(strr, ";")
|
||||
insertId, _ := db.FormatAllMemInsertDb(&temp, "t_championships_data")
|
||||
|
||||
p.MChampshipPlayerMap[int32(insertId)] = CSPlayerInfo
|
||||
|
||||
for j := 0; j < int(playerCnt); j++ {
|
||||
dwUin := sqlStrucks[i*int(playerCnt)+j].DwUin
|
||||
player, ok := G_GameLogicPtr.M_Players[dwUin]
|
||||
if ok {
|
||||
player.GetIFGameData("PlayerBaseData").(*PlayerBaseData).SetChampshipID(int32(insertId), true)
|
||||
} else {
|
||||
player = G_GameLogicPtr.FindOfflinePlayer(dwUin)
|
||||
if player != nil {
|
||||
player.GetIFGameData("PlayerBaseData").(*PlayerBaseData).SetChampshipID(int32(insertId), false)
|
||||
} else {
|
||||
sqlStrucks[i*int(playerCnt)+j].LastChampGroupID = sqlStrucks[i*int(playerCnt)+j].ChampshipsGroupID
|
||||
sqlStrucks[i*int(playerCnt)+j].ChampshipsGroupID = int32(insertId)
|
||||
db.FormatAllMemUpdateDb(&sqlStrucks[i*int(playerCnt)+j], "t_player_baseinfo", "dwUin")
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
remain := len(sqlStrucks) - (groups-1)*int(playerCnt)
|
||||
cnt := 0
|
||||
strr := []string{}
|
||||
temp := db.SqlChampshipsStruct{}
|
||||
temp.CurChampshipsId = G_GameLogicPtr.M_SvrGlobal.CurChampshipsId
|
||||
|
||||
CSPlayerInfo := []*msg.ChampshipsPlayerInfo{}
|
||||
|
||||
for j := 0; j < remain; j++ {
|
||||
dwUin := sqlStrucks[i*int(playerCnt)+j].DwUin
|
||||
res := strconv.Itoa(int(dwUin)) + "_" + "1" + "_" + "0" + "_" + "0" + "_" + "1" + "_" + strconv.Itoa(int(G_GameLogicPtr.M_SvrGlobal.CurChampshipsId)) + "_0"
|
||||
strr = append(strr, res)
|
||||
cnt = cnt + 1
|
||||
playerinfo := &msg.ChampshipsPlayerInfo{}
|
||||
playerinfo.DwUin = dwUin
|
||||
playerinfo.IsGet = 0
|
||||
playerinfo.IsPlayer = 1
|
||||
playerinfo.Score = 0
|
||||
playerinfo.Times = 1
|
||||
playerinfo.AIEnum = 0
|
||||
playerinfo.CurChampshipsId = G_GameLogicPtr.M_SvrGlobal.CurChampshipsId
|
||||
CSPlayerInfo = append(CSPlayerInfo, playerinfo)
|
||||
}
|
||||
for j := cnt; j < 30; j++ {
|
||||
StartRobotUin = StartRobotUin + 1
|
||||
dwUin := StartRobotUin
|
||||
enum := rand.Intn(4) + 1
|
||||
res := strconv.Itoa(int(dwUin)) + "_" + "0" + "_" + "0" + "_" + "0" + "_" + "1" + "_" + strconv.Itoa(int(G_GameLogicPtr.M_SvrGlobal.CurChampshipsId)) + "_" + strconv.Itoa(enum)
|
||||
strr = append(strr, res)
|
||||
playerinfo := &msg.ChampshipsPlayerInfo{}
|
||||
playerinfo.DwUin = int32(dwUin)
|
||||
playerinfo.IsGet = 0
|
||||
playerinfo.IsPlayer = 0
|
||||
playerinfo.Score = 0
|
||||
playerinfo.Times = 1
|
||||
playerinfo.AIEnum = int32(enum)
|
||||
playerinfo.CurChampshipsId = G_GameLogicPtr.M_SvrGlobal.CurChampshipsId
|
||||
CSPlayerInfo = append(CSPlayerInfo, playerinfo)
|
||||
}
|
||||
temp.GroupRankData = strings.Join(strr, ";")
|
||||
insertId, _ := db.FormatAllMemInsertDb(&temp, "t_championships_data")
|
||||
p.MChampshipPlayerMap[int32(insertId)] = CSPlayerInfo
|
||||
for j := 0; j < remain; j++ {
|
||||
dwUin := sqlStrucks[i*int(playerCnt)+j].DwUin
|
||||
player, ok := G_GameLogicPtr.M_Players[dwUin]
|
||||
if ok {
|
||||
player.GetIFGameData("PlayerBaseData").(*PlayerBaseData).SetChampshipID(int32(insertId), true)
|
||||
} else {
|
||||
player = G_GameLogicPtr.FindOfflinePlayer(dwUin)
|
||||
if player != nil {
|
||||
player.GetIFGameData("PlayerBaseData").(*PlayerBaseData).SetChampshipID(int32(insertId), false)
|
||||
} else {
|
||||
|
||||
sqlStrucks[i*int(playerCnt)+j].LastChampGroupID = sqlStrucks[i*int(playerCnt)+j].ChampshipsGroupID
|
||||
sqlStrucks[i*int(playerCnt)+j].ChampshipsGroupID = int32(insertId)
|
||||
db.FormatAllMemUpdateDb(&sqlStrucks[i*int(playerCnt)+j], "t_player_baseinfo", "dwUin")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
p.IsLoadDB = true
|
||||
|
||||
p.AIScoreGrowth1h()
|
||||
db.FormatAllMemUpdateDb(&G_GameLogicPtr.M_SvrGlobal, "t_server_global_data", "Id")
|
||||
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) OpenChampShipTimes(args []interface{}) {
|
||||
p.MStatus = 2
|
||||
notify := &msg.NotifyChampshipTimesOpen{}
|
||||
notify.CurChampshipsId = G_GameLogicPtr.M_SvrGlobal.CurChampshipsId
|
||||
data, _ := proto.Marshal(notify)
|
||||
G_GameLogicPtr.broadcastInfoAllPlayer("NotifyChampshipTimesOpen", data)
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) CloseChampShipTimes(args []interface{}) {
|
||||
p.MStatus = 1
|
||||
notify := &msg.NotifyChampshipTimesClose{}
|
||||
notify.CurChampshipsId = G_GameLogicPtr.M_SvrGlobal.CurChampshipsId
|
||||
data, _ := proto.Marshal(notify)
|
||||
G_GameLogicPtr.broadcastInfoAllPlayer("NotifyChampshipTimesClose", data)
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) Notify_Clock_Tick_Sec(args []interface{}) {
|
||||
timeStamp := args[0].(int64)
|
||||
t := time.Unix(timeStamp, 0).Local()
|
||||
zero := timeStamp - (int64)(t.Hour()*3600+t.Minute()*60+t.Second())
|
||||
OpenTime := zero + MergeConst.G_Champion_Start_Offset
|
||||
OpenTimesTime := zero + MergeConst.G_Champion_Start_Effect_Time
|
||||
CloseTimesTime := zero + MergeConst.G_Champion_Start_Effect_Time + MergeConst.G_Champion_Start_Effect_Durtion
|
||||
DeleteLastTimesTime := zero + MergeConst.G_Champion_settlement_Duration
|
||||
if G_GameLogicPtr.M_SvrGlobal.StartChampshipsSvrTime < int32(OpenTime) { //今日没有开启
|
||||
if timeStamp >= OpenTime { //开启
|
||||
GoUtil.CallEvent(MergeConst.Notify_Champion_Renew, []interface{}{int32(OpenTime)})
|
||||
} else {
|
||||
//开启时间未到
|
||||
if p.MStatus == 1 {
|
||||
GoUtil.CallEvent(MergeConst.Notify_EndChampShip, []interface{}{int32(OpenTime)})
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
if p.MStatus == 0 {
|
||||
p.MStatus = 1
|
||||
}
|
||||
|
||||
if !p.IsLoadDB {
|
||||
p.LoadDbDataByGroupId(G_GameLogicPtr.M_SvrGlobal.CurChampshipsId)
|
||||
if G_GameLogicPtr.M_SvrGlobal.LastChampshipsId > 0 {
|
||||
p.LoadDbDataByGroupId(G_GameLogicPtr.M_SvrGlobal.LastChampshipsId)
|
||||
}
|
||||
p.IsLoadDB = true
|
||||
}
|
||||
}
|
||||
|
||||
if p.MStatus == 1 {
|
||||
if timeStamp >= OpenTimesTime && timeStamp <= CloseTimesTime {
|
||||
GoUtil.CallEvent(MergeConst.Notify_OpenChampShipTimes, []interface{}{int32(OpenTime)})
|
||||
}
|
||||
|
||||
}
|
||||
if p.MStatus == 2 {
|
||||
if timeStamp > CloseTimesTime {
|
||||
GoUtil.CallEvent(MergeConst.Notify_CloseChampShipTimes, []interface{}{int32(OpenTime)})
|
||||
}
|
||||
}
|
||||
if p.IsSettle == 0 {
|
||||
if timeStamp <= DeleteLastTimesTime {
|
||||
p.IsSettle = 1
|
||||
} else {
|
||||
if G_GameLogicPtr.M_SvrGlobal.LastChampshipsId > 0 {
|
||||
p.DeleteOutLineChampship(G_GameLogicPtr.M_SvrGlobal.LastChampshipsId)
|
||||
G_GameLogicPtr.M_SvrGlobal.LastChampshipsId = 0
|
||||
db.FormatAllMemUpdateDb(&G_GameLogicPtr.M_SvrGlobal, "t_server_global_data", "Id")
|
||||
}
|
||||
}
|
||||
}
|
||||
if p.IsSettle == 1 {
|
||||
if timeStamp > DeleteLastTimesTime {
|
||||
notify := &msg.NotifyChampshipSettleClose{}
|
||||
notify.LastChampshipsId = G_GameLogicPtr.M_SvrGlobal.LastChampshipsId
|
||||
data, _ := proto.Marshal(notify)
|
||||
G_GameLogicPtr.broadcastInfoAllPlayer("NotifyChampshipSettleClose", data)
|
||||
p.IsSettle = 0
|
||||
if G_GameLogicPtr.M_SvrGlobal.LastChampshipsId > 0 {
|
||||
p.DeleteOutLineChampship(G_GameLogicPtr.M_SvrGlobal.LastChampshipsId)
|
||||
G_GameLogicPtr.M_SvrGlobal.LastChampshipsId = 0
|
||||
db.FormatAllMemUpdateDb(&G_GameLogicPtr.M_SvrGlobal, "t_server_global_data", "Id")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) EndChampShip(args []interface{}) {
|
||||
p.MStatus = 0
|
||||
G_GameLogicPtr.M_SvrGlobal.LastChampshipsId = G_GameLogicPtr.M_SvrGlobal.CurChampshipsId
|
||||
db.FormatAllMemUpdateDb(&G_GameLogicPtr.M_SvrGlobal, "t_server_global_data", "Id")
|
||||
|
||||
notify := &msg.NotifyChampshipSettleOpen{}
|
||||
notify.LastChampshipsId = G_GameLogicPtr.M_SvrGlobal.LastChampshipsId
|
||||
data, _ := proto.Marshal(notify)
|
||||
G_GameLogicPtr.broadcastInfoAllPlayer("NotifyChampshipSettleOpen", data)
|
||||
|
||||
notify1 := &msg.NotifyChampshipClose{}
|
||||
notify1.CurChampshipsId = G_GameLogicPtr.M_SvrGlobal.CurChampshipsId
|
||||
data1, _ := proto.Marshal(notify1)
|
||||
G_GameLogicPtr.broadcastInfoAllPlayer("NotifyChampshipClose", data1)
|
||||
|
||||
p.NotifyRenewChampshipData()
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) NotifyRenewChampshipData() {
|
||||
for i := 0; i < len(p.MUpdateNotifyList); i++ {
|
||||
groupid := p.MUpdateNotifyList[i]
|
||||
playerlist, ok := p.MChampshipPlayerMap[groupid]
|
||||
if ok {
|
||||
for j := 0; j < len(playerlist); j++ {
|
||||
if playerlist[j].IsPlayer == 1 {
|
||||
dwUin := playerlist[j].DwUin
|
||||
player, ok1 := G_GameLogicPtr.M_Players[dwUin]
|
||||
if ok1 {
|
||||
agent := player.GetAgentByPlayer()
|
||||
notify := &msg.NotifyUpdateChampshipRank{}
|
||||
notify.ChampshipsGroupID = groupid
|
||||
notify.GroupRankDataList = playerlist
|
||||
data, _ := proto.Marshal(notify)
|
||||
G_getGameLogic().PackResInfo(agent, "NotifyUpdateChampshipRank", data)
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
p.MUpdateNotifyList = p.MUpdateNotifyList[0:0]
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) ReqChampshipData(player *Player, buf []byte) {
|
||||
req := &msg.ReqChampshipData{}
|
||||
proto.Unmarshal(buf, req)
|
||||
res := &msg.ResChampshipData{}
|
||||
_, ok := p.MChampshipPlayerMap[req.ChampshipsGroupID]
|
||||
if ok {
|
||||
res.GroupRankDataList = p.MChampshipPlayerMap[req.ChampshipsGroupID]
|
||||
}
|
||||
res.ChampshipsGroupID = req.ChampshipsGroupID
|
||||
res.Status = p.MStatus
|
||||
res.IsSettle = p.IsSettle
|
||||
res.EndTime = G_GameLogicPtr.M_SvrGlobal.StartChampshipsSvrTime + MergeConst.G_Champion_Duration
|
||||
res.EndSettleTime = G_GameLogicPtr.M_SvrGlobal.StartChampshipsSvrTime - MergeConst.G_Champion_Start_Offset + MergeConst.G_Champion_Start_Effect_Time + MergeConst.G_Champion_Start_Effect_Durtion
|
||||
agent := player.GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResChampshipData", data)
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) InitManager() {
|
||||
GoUtil.RegisterEvent(MergeConst.Notify_Champion_Renew, p.OpenNewChampShip, p)
|
||||
GoUtil.RegisterEvent(MergeConst.Notify_OpenChampShipTimes, p.OpenChampShipTimes, p)
|
||||
GoUtil.RegisterEvent(MergeConst.Notify_CloseChampShipTimes, p.CloseChampShipTimes, p)
|
||||
GoUtil.RegisterEvent(MergeConst.Notify_EndChampShip, p.EndChampShip, p)
|
||||
GoUtil.RegisterEvent(MergeConst.Notify_Clock_Tick_Sec, p.Notify_Clock_Tick_Sec, p)
|
||||
p.MChampshipMap = make(map[int32]*db.SqlChampshipsStruct)
|
||||
p.MChampshipPlayerMap = make(map[int32][]*msg.ChampshipsPlayerInfo)
|
||||
p.MStatus = 0
|
||||
p.IsSettle = 0
|
||||
p.IsLoadDB = false
|
||||
p.MUpdateNotifyList = []int32{}
|
||||
p.McronSave = cron.New()
|
||||
p.McronSaveID, _ = p.McronSave.AddFunc("@every 70s", func() {
|
||||
p.NotifyRenewChampshipData()
|
||||
})
|
||||
p.RobotCronID, _ = p.McronSave.AddFunc("@every 1h", func() {
|
||||
p.AIScoreGrowth1h()
|
||||
})
|
||||
|
||||
p.RobotCronID10s, _ = p.McronSave.AddFunc("@every 15m", func() {
|
||||
if p.MStatus == 2 {
|
||||
p.RobotIntervalAddScore15m()
|
||||
}
|
||||
})
|
||||
p.McronSave.Start()
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) RobotIntervalAddScore() {
|
||||
seed := time.Now().Unix()
|
||||
rand.Seed(seed)
|
||||
needToUpdateDb := []int32{}
|
||||
for k, v := range p.MChampshipPlayerMap {
|
||||
ishaveRobot := false
|
||||
for i := 0; i < len(v); i++ {
|
||||
if v[i].IsPlayer == 0 {
|
||||
ishaveRobot = true
|
||||
addScore := 3
|
||||
ran := rand.Intn(100) + 1
|
||||
if ran <= 25 {
|
||||
addScore = addScore + 1
|
||||
} else {
|
||||
if ran <= 50 {
|
||||
addScore = addScore + 2
|
||||
}
|
||||
}
|
||||
v[i].Score = v[i].Score + int32(addScore)
|
||||
}
|
||||
}
|
||||
if ishaveRobot {
|
||||
sort.Slice(v, func(i, j int) bool { return v[i].Score > v[j].Score })
|
||||
isAdd := false
|
||||
for i := 0; i < len(p.MUpdateNotifyList); i++ {
|
||||
if p.MUpdateNotifyList[i] == k {
|
||||
isAdd = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isAdd {
|
||||
p.MUpdateNotifyList = append(p.MUpdateNotifyList, k)
|
||||
}
|
||||
needToUpdateDb = append(needToUpdateDb, k)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
for i := 0; i < len(needToUpdateDb); i++ {
|
||||
p.SaveDbDataByGroupId(needToUpdateDb[i])
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) GetMinGroupId() int32 {
|
||||
var Min int32 = 0
|
||||
for k := range p.MChampshipPlayerMap {
|
||||
if Min == 0 {
|
||||
Min = k
|
||||
continue
|
||||
}
|
||||
if k < Min {
|
||||
Min = k
|
||||
}
|
||||
}
|
||||
return Min
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) AIScoreGrowth1h() {
|
||||
seed := time.Now().Unix()
|
||||
rand.Seed(seed)
|
||||
needToUpdateDb := []int32{}
|
||||
// MinGroupId := p.GetMinGroupId()
|
||||
for k, v := range p.MChampshipPlayerMap {
|
||||
ishaveRobot := false
|
||||
groupId := 0 //k - MinGroupId + 1
|
||||
for i := 0; i < len(v); i++ {
|
||||
if v[i].IsPlayer == 0 {
|
||||
ishaveRobot = true
|
||||
addScore := 0
|
||||
if v[i].AIEnum == 1 {
|
||||
var num1 float64 = 0.5
|
||||
var num2 float64 = 5.5
|
||||
groupId = rand.Intn(7) + 1
|
||||
addScore = addScore + int(math.Floor(float64(groupId-1)*num1*num2))
|
||||
}
|
||||
if v[i].AIEnum == 2 {
|
||||
addScore = 16
|
||||
|
||||
ran := rand.Intn(100) + 1
|
||||
if ran <= 25 {
|
||||
addScore = addScore + 6
|
||||
} else {
|
||||
if ran <= 50 {
|
||||
addScore = addScore + 10
|
||||
}
|
||||
}
|
||||
}
|
||||
if v[i].AIEnum == 3 {
|
||||
addScore = 16
|
||||
|
||||
ran := rand.Intn(100) + 1
|
||||
if ran <= 25 {
|
||||
addScore = addScore + 10
|
||||
} else {
|
||||
if ran <= 75 {
|
||||
addScore = addScore + 6
|
||||
}
|
||||
}
|
||||
var num1 float64 = 0.5
|
||||
var num2 float64 = 5.5
|
||||
groupId = rand.Intn(7) + 1
|
||||
addScore = addScore + int(math.Floor(float64(groupId-1)*num1*num2))
|
||||
}
|
||||
if v[i].AIEnum == 4 {
|
||||
var num1 float64 = 0.5
|
||||
var num2 float64 = 5.5
|
||||
groupId = rand.Intn(7) + 1
|
||||
addScore = addScore + int(math.Floor(float64(groupId-1)*num1*num2))
|
||||
score := rand.Intn(23)
|
||||
addScore = addScore + score
|
||||
}
|
||||
v[i].Score = v[i].Score + int32(addScore)
|
||||
}
|
||||
}
|
||||
if ishaveRobot {
|
||||
sort.Slice(v, func(i, j int) bool { return v[i].Score > v[j].Score })
|
||||
isAdd := false
|
||||
for i := 0; i < len(p.MUpdateNotifyList); i++ {
|
||||
if p.MUpdateNotifyList[i] == k {
|
||||
isAdd = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isAdd {
|
||||
p.MUpdateNotifyList = append(p.MUpdateNotifyList, k)
|
||||
}
|
||||
needToUpdateDb = append(needToUpdateDb, k)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
for i := 0; i < len(needToUpdateDb); i++ {
|
||||
p.SaveDbDataByGroupId(needToUpdateDb[i])
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) RobotIntervalAddScore15m() {
|
||||
seed := time.Now().Unix()
|
||||
rand.Seed(seed)
|
||||
needToUpdateDb := []int32{}
|
||||
for k, v := range p.MChampshipPlayerMap {
|
||||
ishaveRobot := false
|
||||
for i := 0; i < len(v); i++ {
|
||||
if v[i].IsPlayer == 0 {
|
||||
|
||||
addScore := 0
|
||||
if v[i].AIEnum == 1 {
|
||||
|
||||
ran := rand.Intn(100) + 1
|
||||
if ran <= 25 {
|
||||
addScore = addScore + 10
|
||||
} else {
|
||||
if ran <= 75 {
|
||||
addScore = addScore + 6
|
||||
}
|
||||
}
|
||||
ran = rand.Intn(100) + 1
|
||||
if ran <= 25 {
|
||||
addScore = addScore + 5
|
||||
} else {
|
||||
if ran <= 50 {
|
||||
addScore = addScore + 10
|
||||
}
|
||||
}
|
||||
if addScore > 0 {
|
||||
ishaveRobot = true
|
||||
v[i].Score = v[i].Score + int32(addScore)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if ishaveRobot {
|
||||
sort.Slice(v, func(i, j int) bool { return v[i].Score > v[j].Score })
|
||||
isAdd := false
|
||||
for i := 0; i < len(p.MUpdateNotifyList); i++ {
|
||||
if p.MUpdateNotifyList[i] == k {
|
||||
isAdd = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isAdd {
|
||||
p.MUpdateNotifyList = append(p.MUpdateNotifyList, k)
|
||||
}
|
||||
needToUpdateDb = append(needToUpdateDb, k)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
for i := 0; i < len(needToUpdateDb); i++ {
|
||||
p.SaveDbDataByGroupId(needToUpdateDb[i])
|
||||
}
|
||||
}
|
||||
func (p *ChampshipsManager) SaveDbDataByGroupId(GroupId int32) {
|
||||
_, ok := p.MChampshipPlayerMap[GroupId]
|
||||
if ok {
|
||||
List := p.MChampshipPlayerMap[GroupId]
|
||||
strr := []string{}
|
||||
for i := 0; i < len(List); i++ {
|
||||
Item := List[i]
|
||||
unit := strconv.Itoa(int(Item.DwUin)) + "_" + strconv.Itoa(int(Item.IsPlayer)) + "_" + strconv.Itoa(int(Item.Score)) + "_" + strconv.Itoa(int(Item.IsGet)) + "_" + strconv.Itoa(int(Item.Times)) + "_" + strconv.Itoa(int(Item.CurChampshipsId)) + "_" + strconv.Itoa(int(Item.AIEnum))
|
||||
strr = append(strr, unit)
|
||||
}
|
||||
data := strings.Join(strr, ";")
|
||||
sqlStruct := &db.SqlChampionshipsStruct{}
|
||||
sqlStruct.ChampshipsGroupID = GroupId
|
||||
sqlStruct.GroupRankData = data
|
||||
sqlStruct.CurChampshipsId = List[0].CurChampshipsId
|
||||
db.FormatAllMemUpdateDb(sqlStruct, "t_championships_data", "ChampshipsGroupID")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) LoadDbDataByGroupId(ChampshipsId int32) {
|
||||
|
||||
sqlStr := "SELECT * FROM t_championships_data WHERE CurChampshipsId = ?"
|
||||
|
||||
sqlStruck := []db.SqlChampionshipsStruct{}
|
||||
|
||||
if err := db.SqlDb.Select(&sqlStruck, sqlStr, ChampshipsId); err != nil {
|
||||
fmt.Printf("get data failed, err:%v\n", err)
|
||||
|
||||
} else {
|
||||
for m := 0; m < len(sqlStruck); m++ {
|
||||
units := strings.Split(sqlStruck[m].GroupRankData, ";")
|
||||
list := []*msg.ChampshipsPlayerInfo{}
|
||||
for i := 0; i < len(units); i++ {
|
||||
item := units[i]
|
||||
strr := strings.Split(item, "_")
|
||||
temp := &msg.ChampshipsPlayerInfo{}
|
||||
dwuin, _ := strconv.Atoi(strr[0])
|
||||
temp.DwUin = int32(dwuin)
|
||||
IsPlayer, _ := strconv.Atoi(strr[1])
|
||||
temp.IsPlayer = int32(IsPlayer)
|
||||
Score, _ := strconv.Atoi(strr[2])
|
||||
temp.Score = int32(Score)
|
||||
IsGet, _ := strconv.Atoi(strr[3])
|
||||
temp.IsGet = int32(IsGet)
|
||||
Times, _ := strconv.Atoi(strr[4])
|
||||
temp.Times = int32(Times)
|
||||
CS, _ := strconv.Atoi(strr[5])
|
||||
temp.CurChampshipsId = int32(CS)
|
||||
AI, _ := strconv.Atoi(strr[6])
|
||||
temp.AIEnum = int32(AI)
|
||||
list = append(list, temp)
|
||||
}
|
||||
p.MChampshipPlayerMap[sqlStruck[m].ChampshipsGroupID] = list
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) ReqChampshipAddScore(player *Player, buf []byte) {
|
||||
req := &msg.ReqChampshipAddScore{}
|
||||
proto.Unmarshal(buf, req)
|
||||
res := &msg.ResChampshipAddScore{}
|
||||
|
||||
if p.MStatus == 0 {
|
||||
res.ResultCode = MergeConst.Protocol_Champship_End
|
||||
} else {
|
||||
_, ok := p.MChampshipPlayerMap[req.GroupId]
|
||||
if ok {
|
||||
List := p.MChampshipPlayerMap[req.GroupId]
|
||||
isHave := false
|
||||
for i := 0; i < len(List); i++ {
|
||||
if List[i].DwUin == player.M_DwUin {
|
||||
List[i].Score = List[i].Score + req.AddScore
|
||||
res.ResultCode = 0
|
||||
isHave = true
|
||||
break
|
||||
}
|
||||
}
|
||||
sort.Slice(List, func(i, j int) bool { return List[i].Score > List[j].Score })
|
||||
if !isHave {
|
||||
res.ResultCode = MergeConst.Protocol_Champship_No_Join
|
||||
} else {
|
||||
res.GroupRankDataList = List
|
||||
isAdd := false
|
||||
for i := 0; i < len(p.MUpdateNotifyList); i++ {
|
||||
if p.MUpdateNotifyList[i] == req.GroupId {
|
||||
isAdd = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isAdd {
|
||||
p.MUpdateNotifyList = append(p.MUpdateNotifyList, req.GroupId)
|
||||
}
|
||||
|
||||
p.SaveDbDataByGroupId(req.GroupId)
|
||||
}
|
||||
} else {
|
||||
res.ResultCode = MergeConst.Protocol_Champship_No_Exsit
|
||||
}
|
||||
}
|
||||
|
||||
res.GroupId = req.GroupId
|
||||
agent := player.GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResChampshipAddScore", data)
|
||||
}
|
||||
|
||||
func (p *ChampshipsManager) ReqChampshipAddTime(player *Player, buf []byte) {
|
||||
req := &msg.ReqChampshipAddTime{}
|
||||
proto.Unmarshal(buf, req)
|
||||
res := &msg.ResChampshipAddTime{}
|
||||
if p.MStatus == 0 {
|
||||
res.ResultCode = MergeConst.Protocol_Champship_End
|
||||
} else {
|
||||
_, ok := p.MChampshipPlayerMap[req.GroupId]
|
||||
if ok {
|
||||
List := p.MChampshipPlayerMap[req.GroupId]
|
||||
isHave := false
|
||||
for i := 0; i < len(List); i++ {
|
||||
if List[i].DwUin == player.M_DwUin {
|
||||
List[i].Times = List[i].Times + req.AddTimes
|
||||
res.ResultCode = 0
|
||||
isHave = true
|
||||
break
|
||||
}
|
||||
}
|
||||
sort.Slice(List, func(i, j int) bool { return List[i].Score > List[j].Score })
|
||||
if !isHave {
|
||||
res.ResultCode = MergeConst.Protocol_Champship_No_Join
|
||||
} else {
|
||||
res.GroupRankDataList = List
|
||||
p.SaveDbDataByGroupId(req.GroupId)
|
||||
}
|
||||
} else {
|
||||
res.ResultCode = MergeConst.Protocol_Champship_No_Exsit
|
||||
}
|
||||
}
|
||||
res.GroupId = req.GroupId
|
||||
|
||||
agent := player.GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResChampshipAddTime", data)
|
||||
}
|
||||
48
src/server/game/ChargeFunc.go
Normal file
48
src/server/game/ChargeFunc.go
Normal file
@ -0,0 +1,48 @@
|
||||
package game
|
||||
|
||||
import "server/pkg/github.com/name5566/leaf/log"
|
||||
|
||||
func Charge(p *Player, ChargeId int) {
|
||||
ChargeFire(p, ChargeId) // 充值
|
||||
EndlessFire(p, ChargeId) // 无尽礼包
|
||||
PiggyBankFire(p, ChargeId) // 猪猪银行
|
||||
}
|
||||
|
||||
func PiggyBankFire(p *Player, ChargeId int) {
|
||||
PiggyBankMod := p.PlayMod.getPiggyBankMod()
|
||||
Item := PiggyBankMod.Fire(ChargeId)
|
||||
err := p.HandleItem(Item, "PiggyBank")
|
||||
if err != nil {
|
||||
log.Debug("ChargeFire err : %s", err)
|
||||
}
|
||||
LimitedTimePiggyBankTrigger(p)
|
||||
p.PlayMod.save()
|
||||
p.PushClientRes(PiggyBankMod.BackData())
|
||||
}
|
||||
|
||||
// 处理玩家充值
|
||||
func ChargeFire(p *Player, ChargeId int) {
|
||||
ChargeMod := p.PlayMod.getChargeMod()
|
||||
Item := ChargeMod.Fire(ChargeId)
|
||||
err := p.HandleItem(Item, "Charge")
|
||||
if err != nil {
|
||||
log.Debug("ChargeFire err : %s", err)
|
||||
}
|
||||
p.PlayMod.save()
|
||||
p.PushClientRes(ChargeMod.BackData())
|
||||
}
|
||||
|
||||
// 处理玩家充值
|
||||
func EndlessFire(p *Player, ChargeId int) {
|
||||
EndlessMod := p.PlayMod.getEndlessMod()
|
||||
Item := EndlessMod.Fire(ChargeId)
|
||||
if Item == nil {
|
||||
return
|
||||
}
|
||||
err := p.HandleItem(Item, "Endless")
|
||||
if err != nil {
|
||||
log.Debug("ChargeFire err : %s", err)
|
||||
}
|
||||
p.PlayMod.save()
|
||||
p.PushClientRes(EndlessMod.BackData())
|
||||
}
|
||||
42
src/server/game/ClusterMgr.go
Normal file
42
src/server/game/ClusterMgr.go
Normal file
@ -0,0 +1,42 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
mergeCluster "server/cluster"
|
||||
"server/game/mod/msg"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
)
|
||||
|
||||
var clusterHandler map[int]func(*msg.Msg) error
|
||||
|
||||
func ClusterMgrInit() {
|
||||
go func() {
|
||||
for {
|
||||
m := <-mergeCluster.MsgChan
|
||||
clusterHandlerProcess(m)
|
||||
}
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
func clusterHandlerProcess(m *msg.Msg) {
|
||||
log.Debug("clusterHandlerProcess m %v", m)
|
||||
if fun, ok := clusterHandler[m.Type]; ok {
|
||||
fun(m)
|
||||
} else {
|
||||
log.Debug("clusterHandlerProcess not found handler %d", m.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func RegisterClusterHandler(t int, fun func(*msg.Msg) error) {
|
||||
clusterHandler[t] = fun
|
||||
}
|
||||
|
||||
func init() {
|
||||
clusterHandler = make(map[int]func(*msg.Msg) error)
|
||||
RegisterClusterHandler(msg.HANDLE_TYPE_DEL, FriendMgrSend)
|
||||
RegisterClusterHandler(msg.HANDLE_TYPE_APPLY, FriendMgrSend)
|
||||
RegisterClusterHandler(msg.HADNLE_TYPE_AGREE, FriendMgrSend)
|
||||
RegisterClusterHandler(msg.HANDLE_TYPE_REQ_CARD, FriendMgrSend)
|
||||
RegisterClusterHandler(msg.HANDLE_TYPE_AGREE_CARD, FriendMgrSend)
|
||||
RegisterClusterHandler(msg.CLUSTER_FRIEND_SYNC, ClusterFriendSync)
|
||||
}
|
||||
115
src/server/game/FriendMgr.go
Normal file
115
src/server/game/FriendMgr.go
Normal file
@ -0,0 +1,115 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"server/GoUtil"
|
||||
mergeCluster "server/cluster"
|
||||
"server/conf"
|
||||
"server/game/mod/msg"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
)
|
||||
|
||||
type FriendMgr struct {
|
||||
*ServerMod
|
||||
}
|
||||
|
||||
type FirendData struct {
|
||||
List map[int][]*msg.Msg
|
||||
ClusterMsg map[int][]*msg.Msg
|
||||
}
|
||||
|
||||
func (f *FriendMgr) Init() {
|
||||
|
||||
f.key = FRIEND_MGR_KEY
|
||||
f.data = &FirendData{
|
||||
List: make(map[int][]*msg.Msg),
|
||||
ClusterMsg: make(map[int][]*msg.Msg),
|
||||
}
|
||||
// 注册处理函数
|
||||
f.init()
|
||||
f.RegisterHandler(msg.HANDLE_TYPE_APPLY, f.sendToPlayer)
|
||||
f.RegisterHandler(msg.HADNLE_TYPE_AGREE, f.sendToPlayer)
|
||||
f.RegisterHandler(msg.HANDLE_TYPE_DEL, f.sendToPlayer)
|
||||
f.RegisterHandler(msg.HANDLE_TYPE_SYNC, f.sync)
|
||||
|
||||
// 卡牌消息
|
||||
f.RegisterHandler(msg.HANDLE_TYPE_REQ_CARD, f.sendToPlayer)
|
||||
f.RegisterHandler(msg.HANDLE_TYPE_AGREE_CARD, f.sendToPlayer)
|
||||
f.RegisterHandler(msg.HANDLE_TYPE_REG_CARD_REFUSE, f.sendToPlayer)
|
||||
f.RegisterHandler(msg.HANDLE_TYPE_REG_CARD_FINISH, f.sendToPlayer)
|
||||
f.RegisterHandler(msg.HANDLE_TYPE_AGREE_CARD_FAIL, f.sendToPlayer)
|
||||
f.RegisterHandler(msg.HANDLE_TYPE_EX_CARD, f.sendToPlayer)
|
||||
f.RegisterHandler(msg.HANDLE_TYPE_SELECT_EX_CARD, f.sendToPlayer)
|
||||
f.RegisterHandler(msg.HANDLE_TYPE_ARGREE_EX_CARD, f.sendToPlayer)
|
||||
f.RegisterHandler(msg.HANDLE_TYPE_REFUSE_SELECT_CARD, f.sendToPlayer)
|
||||
f.RegisterHandler(msg.HANDLE_TYPE_REFUSE_EX_CARD, f.sendToPlayer)
|
||||
|
||||
}
|
||||
|
||||
func (f *FriendMgr) getData() *FirendData {
|
||||
return f.data.(*FirendData)
|
||||
}
|
||||
|
||||
// 通知玩家
|
||||
func (f *FriendMgr) sendToPlayer(m *msg.Msg) (interface{}, error) {
|
||||
err := sendToPlayer(m)
|
||||
if err != nil {
|
||||
log.Debug("send to player error : %s\n", err)
|
||||
ToServerId := GoUtil.GetServerIdByUid(m.To)
|
||||
if ToServerId != conf.Server.ServerID {
|
||||
f.getData().ClusterMsg[m.To] = append(f.getData().ClusterMsg[m.To], m) // 保存到集群消息
|
||||
} else {
|
||||
f.getData().List[m.To] = append(f.getData().List[m.To], m) // 保存到本地消息
|
||||
}
|
||||
f.update = true
|
||||
return nil, err
|
||||
}
|
||||
log.Debug("send to player success")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 同步信息
|
||||
func (f *FriendMgr) sync(m *msg.Msg) (interface{}, error) {
|
||||
data := f.getData().List[m.From]
|
||||
f.getData().List[m.From] = make([]*msg.Msg, 0)
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// 发送消息给玩家
|
||||
func sendToPlayer(m *msg.Msg) error {
|
||||
p := G_GameLogicPtr.GetPlayerByUid(m.To)
|
||||
if p == nil || p.stop {
|
||||
return fmt.Errorf("player %d not online", m.To)
|
||||
}
|
||||
p.SendMsg(m)
|
||||
return nil
|
||||
}
|
||||
|
||||
func FriendMgrSend(m *msg.Msg) error {
|
||||
ToServer := GoUtil.GetServerIdByUid(m.To)
|
||||
if ToServer != conf.Server.ServerID {
|
||||
err := mergeCluster.SendServerMsg(m, ToServer)
|
||||
if err != nil { // 区服不在线
|
||||
G_GameLogicPtr.FriendMgrSend(m)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
G_GameLogicPtr.FriendMgrSend(m)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 集群好友消息同步
|
||||
func ClusterFriendSync(m *msg.Msg) error {
|
||||
log.Debug("ClusterFriendSync")
|
||||
if v, ok := G_GameLogicPtr.FriendMgr.getData().ClusterMsg[m.To]; ok {
|
||||
for _, msg := range v {
|
||||
mergeCluster.SendServerMsg(msg, m.To)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func FriendMgrCall(m *msg.Msg) interface{} {
|
||||
return G_GameLogicPtr.FriendMgrCall(m)
|
||||
}
|
||||
1173
src/server/game/GameLogic.go
Normal file
1173
src/server/game/GameLogic.go
Normal file
File diff suppressed because it is too large
Load Diff
66
src/server/game/Gm.go
Normal file
66
src/server/game/Gm.go
Normal file
@ -0,0 +1,66 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"server/game/mod/card"
|
||||
"server/game/mod/item"
|
||||
"server/msg"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func ReqGmCommand(args []interface{}) error {
|
||||
_, player, buf := ParseArgs(args)
|
||||
detail := &msg.ReqGmCommand{}
|
||||
proto.Unmarshal(buf, detail)
|
||||
arg := strings.Split(detail.Command, " ")
|
||||
switch arg[0] {
|
||||
case "additem":
|
||||
id, _ := strconv.Atoi(arg[1])
|
||||
num, _ := strconv.Atoi(arg[2])
|
||||
player.HandleItem([]*item.Item{item.NewItem(id, num)}, "GM")
|
||||
case "subitem":
|
||||
id, _ := strconv.Atoi(arg[1])
|
||||
num, _ := strconv.Atoi(arg[2])
|
||||
player.HandleItem([]*item.Item{item.NewItem(id, -num)}, "GM")
|
||||
case "reset_order":
|
||||
player.PlayMod.mod_list.Order.Step = 0
|
||||
player.PlayMod.mod_list.Order.InitData()
|
||||
player.PushClientRes(player.PlayMod.mod_list.Order.BackData())
|
||||
case "add_card_star":
|
||||
num, _ := strconv.Atoi(arg[1])
|
||||
player.PlayMod.mod_list.Card.ExchangeStar += num
|
||||
player.PushClientRes(player.PlayMod.mod_list.Card.BackData())
|
||||
case "addexp":
|
||||
num, _ := strconv.Atoi(arg[1])
|
||||
player.GetPlayerBaseMod().AddExp(num)
|
||||
player.PushClientRes(&player.GetPlayerBaseMod().Data)
|
||||
case "setlv":
|
||||
num, _ := strconv.Atoi(arg[1])
|
||||
player.GetPlayerBaseMod().Data.Level = int32(num)
|
||||
player.GetPlayerBaseMod().Data.Exp = 0
|
||||
player.PushClientRes(&player.GetPlayerBaseMod().Data)
|
||||
case "zeroUpdate":
|
||||
player.PlayMod.getVarMod().DailyResetTime = 0
|
||||
player.ZeroUpdate([]interface{}{})
|
||||
case "setSevenLoginActive":
|
||||
num, _ := strconv.Atoi(arg[1])
|
||||
player.PlayMod.getSevenLoginMod().Active = num
|
||||
case "pay":
|
||||
ChargeId, _ := strconv.Atoi(arg[1])
|
||||
Charge(player, ChargeId)
|
||||
case "resetCardReq":
|
||||
CardMod := player.PlayMod.getCardMod()
|
||||
CardMod.ReqFriend = make(map[int]*card.CardInfo)
|
||||
CardMod.ExCard = make(map[int]*card.CardInfo)
|
||||
CardMod.ExTimes = 10
|
||||
CardMod.ReqTimes = 10
|
||||
|
||||
FriendMod := player.PlayMod.getFriendMod()
|
||||
FriendMod.ApplyCard = make(map[int]*card.CardInfo)
|
||||
FriendMod.ExchangeCard = make(map[int]*card.CardInfo)
|
||||
FriendMod.SelectCard = make(map[int]*card.CardInfo)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
79
src/server/game/HttpSvr.go
Normal file
79
src/server/game/HttpSvr.go
Normal file
@ -0,0 +1,79 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"server/conf"
|
||||
"server/msg"
|
||||
|
||||
// "server/msg"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type HttpManager struct {
|
||||
Rounter *mux.Router
|
||||
}
|
||||
|
||||
func (p *HttpManager) InitRounter() {
|
||||
p.Rounter = mux.NewRouter()
|
||||
p.InitFriendRouter()
|
||||
p.InitPlayerProfileInfo()
|
||||
http.ListenAndServe(conf.Server.HttpPort, p.Rounter)
|
||||
}
|
||||
|
||||
func (p *HttpManager) InitFriendRouter() {
|
||||
bs := p.Rounter.PathPrefix("/Friend").Subrouter()
|
||||
bs.HandleFunc("/Add/{SenderId}/{ReceiveId}", p.AddFriend)
|
||||
bs.HandleFunc("/Del/{SenderId}/{ReceiveId}", p.DeleteFriend)
|
||||
}
|
||||
|
||||
func (p *HttpManager) InitPlayerProfileInfo() {
|
||||
bs := p.Rounter.PathPrefix("/Profile").Subrouter()
|
||||
bs.HandleFunc("/GetBrief/{Id}", p.GetPlayerProfileInfo)
|
||||
}
|
||||
|
||||
func (p *HttpManager) GetPlayerProfileInfo(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
Id, ok := vars["Id"]
|
||||
|
||||
if ok {
|
||||
Uin, _ := strconv.Atoi(Id)
|
||||
data := G_GameLogicPtr.MPlayerProfileManager.HttpReqPlayerBriefProfileData(int32(Uin))
|
||||
test := []*msg.ResPlayerBriefProfileData{data, data}
|
||||
bytes, _ := json.Marshal(test)
|
||||
|
||||
v := []*msg.ResPlayerBriefProfileData{}
|
||||
json.Unmarshal(bytes, &v)
|
||||
|
||||
fmt.Println("bytes Length:" + strconv.Itoa(len(v)))
|
||||
fmt.Println("bytes Length:" + strconv.Itoa(len(v)))
|
||||
w.Write(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *HttpManager) AddFriend(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
SenderId, ok := vars["SenderId"]
|
||||
if ok {
|
||||
fmt.Println("AddFreind SenderId:" + SenderId)
|
||||
}
|
||||
|
||||
ReceiveId, ok1 := vars["ReceiveId"]
|
||||
if ok1 {
|
||||
fmt.Println("AddFreind ReceiveId:" + ReceiveId)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *HttpManager) DeleteFriend(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
id, ok := vars["id"]
|
||||
if !ok {
|
||||
fmt.Println("id is missing in parameters")
|
||||
}
|
||||
fmt.Println(`id := `, id)
|
||||
|
||||
}
|
||||
242
src/server/game/LimiteEventManager.go
Normal file
242
src/server/game/LimiteEventManager.go
Normal file
@ -0,0 +1,242 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/robfig/cron/v3"
|
||||
"server/GoUtil"
|
||||
"server/MergeConst"
|
||||
"server/db"
|
||||
"server/gamedata"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"server/pkg/github.com/name5566/leaf/timer"
|
||||
)
|
||||
|
||||
type LimitEventPeriod struct {
|
||||
StartCronID cron.EntryID
|
||||
EndTimer *timer.Timer
|
||||
StartTime int32
|
||||
EndTime int32
|
||||
Duration int32
|
||||
CronStr string
|
||||
AddTimes int32
|
||||
}
|
||||
|
||||
func NewLimitEventData(dataName string, dbName string, player *Player) *PlayerLimitData {
|
||||
act := &PlayerLimitData{
|
||||
PlayerData: NewPlayerData(dataName, player),
|
||||
MDbName: dbName,
|
||||
}
|
||||
|
||||
return act
|
||||
}
|
||||
|
||||
func CreateLimiteEventData(ID int32, dataName string, player *Player) PlayerDataModule {
|
||||
var data PlayerDataModule
|
||||
if ID == 1 {
|
||||
data = &PlayerChestRainData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Chest_Rain", player)}
|
||||
}
|
||||
if ID == 2 {
|
||||
data = &PlayerSuperEmiterData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Super_Emiter", player)}
|
||||
}
|
||||
if ID == 3 {
|
||||
data = &PlayerStarRainData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Star_Rain", player)}
|
||||
}
|
||||
if ID == 4 {
|
||||
data = &PlayerHighRollerData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_High_Roller", player)}
|
||||
}
|
||||
if ID == 5 {
|
||||
data = &PlayerSuperOrderData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Super_Order", player)}
|
||||
}
|
||||
if ID == 6 {
|
||||
data = &PlayerSceneSprintData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Scene_Sprint", player)}
|
||||
}
|
||||
if ID == 7 {
|
||||
data = &PlayerCardFestivalData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Card_Festival", player)}
|
||||
}
|
||||
if ID == 8 {
|
||||
data = &PlayerDoubleHitData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Double_Hit", player)}
|
||||
}
|
||||
if ID == 9 {
|
||||
data = &PlayerCardSwapData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Card_Swap", player)}
|
||||
}
|
||||
if ID == 10 {
|
||||
data = &PlayerPetRobberData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Pet_Robber", player)}
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
type LimiteEventManager struct {
|
||||
MStatus int32
|
||||
CronList map[int][]string
|
||||
IsSettle int32
|
||||
IsLoadDB bool
|
||||
MUpdateNotifyList []int32
|
||||
McronSave *cron.Cron
|
||||
McronSaveID cron.EntryID
|
||||
RobotCronID cron.EntryID
|
||||
RobotCronID10s cron.EntryID
|
||||
m_MapCronEntryIDs map[int][]*LimitEventPeriod
|
||||
Mdispatr *timer.Dispatcher
|
||||
IsHighRoll bool
|
||||
}
|
||||
|
||||
func (p *LimiteEventManager) GetLimitDataNameById(id int32) string {
|
||||
LimitDataMap := make(map[int32]string)
|
||||
LimitDataMap[1] = "PlayerChestRainData"
|
||||
LimitDataMap[2] = "PlayerSuperEmiterData"
|
||||
LimitDataMap[3] = "PlayerStarRainData"
|
||||
LimitDataMap[4] = "PlayerHighRollerData"
|
||||
LimitDataMap[5] = "PlayerSuperOrderData"
|
||||
LimitDataMap[6] = "PlayerSceneSprintData"
|
||||
LimitDataMap[7] = "PlayerCardFestivalData"
|
||||
LimitDataMap[8] = "PlayerDoubleHitData"
|
||||
LimitDataMap[9] = "PlayerCardSwapData"
|
||||
LimitDataMap[10] = "PlayerPetRobberData"
|
||||
|
||||
return LimitDataMap[id]
|
||||
}
|
||||
|
||||
func (p *LimiteEventManager) SaveDataFromDB(Key interface{}) bool {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *LimiteEventManager) GetSunDayZero() int64 {
|
||||
timeStamp := time.Now().Unix()
|
||||
t := time.Unix(timeStamp, 0).Local()
|
||||
delta := int(t.Weekday()*3600*24) + t.Hour()*3600 + t.Minute()*60 + t.Second()
|
||||
return int64(timeStamp) - int64(delta)
|
||||
}
|
||||
|
||||
func (p *LimiteEventManager) GetLimitDataStatus(id int) *LimitEventPeriod {
|
||||
timeStamp := time.Now().Unix()
|
||||
keys := p.m_MapCronEntryIDs[id]
|
||||
for i := 0; i < len(keys); i++ {
|
||||
if timeStamp >= int64(keys[i].StartTime) && timeStamp < int64(keys[i].EndTime) {
|
||||
return keys[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *LimiteEventManager) GetIsHighRollerPersion() bool {
|
||||
return p.IsHighRoll
|
||||
}
|
||||
|
||||
// 1.宝箱雨
|
||||
func (p *LimiteEventManager) InitManager() {
|
||||
// 0 11 20 12 *
|
||||
p.IsHighRoll = false
|
||||
p.m_MapCronEntryIDs = map[int][]*LimitEventPeriod{}
|
||||
c := cron.New()
|
||||
LimiteCfg := gamedata.GetConfigByName("LimiteEvent")
|
||||
WeekZero := p.GetSunDayZero()
|
||||
timeStamp := time.Now().Unix()
|
||||
|
||||
p.Mdispatr = timer.NewDispatcher(10)
|
||||
for i := 0; i < LimiteCfg.NumRecord(); i++ {
|
||||
record := LimiteCfg.Record(i).(*gamedata.LimiteEvent)
|
||||
startStrr := record.StartTime
|
||||
starts := strings.Split(startStrr, "|")
|
||||
|
||||
DurStrr := record.Duration
|
||||
Durs := strings.Split(DurStrr, "|")
|
||||
|
||||
AddTimesStrr := record.AddTimes
|
||||
ats := strings.Split(AddTimesStrr, "|")
|
||||
|
||||
p.m_MapCronEntryIDs[record.Id] = []*LimitEventPeriod{}
|
||||
for n := 0; n < len(starts); n++ {
|
||||
LEP := &LimitEventPeriod{}
|
||||
start := starts[n]
|
||||
dur, _ := strconv.Atoi(Durs[n])
|
||||
addt, _ := strconv.Atoi(ats[n])
|
||||
LEP.StartCronID, _ = c.AddFunc(start, func() {
|
||||
fmt.Println("Next: UTC", c.Entry(LEP.StartCronID).Next.Unix())
|
||||
fmt.Println("CronStr:" + LEP.CronStr)
|
||||
cur := int32(time.Now().Unix())
|
||||
LEP.StartTime = int32(cur)
|
||||
LEP.EndTime = int32(cur) + int32(dur)
|
||||
if record.Id == 9 {
|
||||
if G_GameLogicPtr.M_SvrGlobal.LimitCardSwapTime < LEP.StartTime {
|
||||
card4Cfg, str4 := gamedata.GetRandomDifferenceSet(4, G_GameLogicPtr.M_SvrGlobal.Limit4CardExclude)
|
||||
card5Cfg, str5 := gamedata.GetRandomDifferenceSet(5, G_GameLogicPtr.M_SvrGlobal.Limit5CardExclude)
|
||||
G_GameLogicPtr.M_SvrGlobal.Limit4Card = int32(card4Cfg.Id)
|
||||
G_GameLogicPtr.M_SvrGlobal.Limit5Card = int32(card5Cfg.Id)
|
||||
G_GameLogicPtr.M_SvrGlobal.Limit4CardExclude = str4
|
||||
G_GameLogicPtr.M_SvrGlobal.Limit5CardExclude = str5
|
||||
G_GameLogicPtr.M_SvrGlobal.LimitCardSwapTime = LEP.StartTime
|
||||
db.FormatAllMemUpdateDb(&G_GameLogicPtr.M_SvrGlobal, "t_server_global_data", "Id")
|
||||
}
|
||||
}
|
||||
GoUtil.CallEvent(MergeConst.OpenNewLimitEvent, []interface{}{record.Id, cur, cur + int32(dur), record.Type})
|
||||
if record.Id == 4 {
|
||||
p.IsHighRoll = true
|
||||
}
|
||||
go func() {
|
||||
LeafTimer := p.Mdispatr.AfterFunc(time.Duration(dur)*time.Second, func() {
|
||||
if record.Id == 4 {
|
||||
p.IsHighRoll = false
|
||||
}
|
||||
})
|
||||
LEP.EndTimer = LeafTimer
|
||||
|
||||
(<-p.Mdispatr.ChanTimer).Cb()
|
||||
}()
|
||||
})
|
||||
LEP.Duration = int32(dur)
|
||||
LEP.CronStr = start
|
||||
LEP.AddTimes = int32(addt)
|
||||
p.m_MapCronEntryIDs[record.Id] = append(p.m_MapCronEntryIDs[record.Id], LEP)
|
||||
}
|
||||
}
|
||||
c.Start()
|
||||
for k, v := range p.m_MapCronEntryIDs {
|
||||
// record := LimiteCfg.Index(k).(*gamedata.LimiteEvent)
|
||||
key := k
|
||||
for i := 0; i < len(v); i++ {
|
||||
Schedule := c.Entry(v[i].StartCronID).Schedule
|
||||
Next := Schedule.Next(time.Unix(WeekZero, 0))
|
||||
// fmt.Println("Next.Unix():" + strconv.Itoa(int(Next.Unix())))
|
||||
value := v[i]
|
||||
if timeStamp >= Next.Unix() && timeStamp < Next.Unix()+int64(value.Duration) {
|
||||
fmt.Println("CronStr:" + value.CronStr)
|
||||
if key == 4 {
|
||||
p.IsHighRoll = true
|
||||
}
|
||||
if key == 9 {
|
||||
if G_GameLogicPtr.M_SvrGlobal.LimitCardSwapTime < int32(Next.Unix()) {
|
||||
card4Cfg, str4 := gamedata.GetRandomDifferenceSet(4, G_GameLogicPtr.M_SvrGlobal.Limit4CardExclude)
|
||||
card5Cfg, str5 := gamedata.GetRandomDifferenceSet(5, G_GameLogicPtr.M_SvrGlobal.Limit5CardExclude)
|
||||
G_GameLogicPtr.M_SvrGlobal.Limit4Card = int32(card4Cfg.Id)
|
||||
G_GameLogicPtr.M_SvrGlobal.Limit5Card = int32(card5Cfg.Id)
|
||||
G_GameLogicPtr.M_SvrGlobal.Limit4CardExclude = str4
|
||||
G_GameLogicPtr.M_SvrGlobal.Limit5CardExclude = str5
|
||||
G_GameLogicPtr.M_SvrGlobal.LimitCardSwapTime = int32(Next.Unix())
|
||||
db.FormatAllMemUpdateDb(&G_GameLogicPtr.M_SvrGlobal, "t_server_global_data", "Id")
|
||||
}
|
||||
}
|
||||
go func() {
|
||||
delta := Next.Unix() + int64(value.Duration) - timeStamp
|
||||
LeafTimer := p.Mdispatr.AfterFunc(time.Duration(delta)*time.Second, func() {
|
||||
if key == 4 {
|
||||
p.IsHighRoll = false
|
||||
}
|
||||
})
|
||||
value.EndTimer = LeafTimer
|
||||
value.StartTime = int32(Next.Unix())
|
||||
value.EndTime = int32(Next.Unix()) + int32(value.Duration)
|
||||
(<-p.Mdispatr.ChanTimer).Cb()
|
||||
}()
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
72
src/server/game/LimitedTimeTrigger.go
Normal file
72
src/server/game/LimitedTimeTrigger.go
Normal file
@ -0,0 +1,72 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"server/GoUtil"
|
||||
"server/game/mod/limitedTimeEvent"
|
||||
"server/msg"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 限时事件触发器
|
||||
func LimitedTimeEventTrigger(p *Player, AddEventId int) {
|
||||
EndTime, TimeoutEvent, AddEvent := p.PlayMod.getLimitedTimeEventMod().Trigger()
|
||||
remainingTime := GoUtil.NextHourRemain()
|
||||
EndTime = GoUtil.IfTrue(EndTime > 0, min(EndTime, int(remainingTime)), int(remainingTime)).(int)
|
||||
if AddEventId != 0 {
|
||||
AddEvent = append(AddEvent, AddEventId)
|
||||
}
|
||||
if EndTime > 0 {
|
||||
p.CallEvent(time.Duration(EndTime)*time.Second, func() {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
LimitedTimeEventTrigger(p, 0)
|
||||
p.SendClientRes()
|
||||
}, "LimitedTimeEvent")
|
||||
}
|
||||
|
||||
for _, v := range TimeoutEvent { // 事件到期处理
|
||||
p.PushClientRes(&msg.LimitEventNotify{
|
||||
Id: int32(v),
|
||||
Type: limitedTimeEvent.EVENT_NOTIFY_TYPE_DEL,
|
||||
})
|
||||
switch v {
|
||||
case limitedTimeEvent.EVENT_TYPE_HIGH_ROLLER:
|
||||
MaxEnergyMul := p.GetPlayerBaseMod().GetMaxEnergyMul()
|
||||
p.PlayMod.getBaseMod().ResetEnergyMul(MaxEnergyMul)
|
||||
p.PushClientRes(p.PlayMod.getBaseMod().BackData())
|
||||
case limitedTimeEvent.EVENT_TYPE_SUPER_ORDER:
|
||||
p.PlayMod.getOrderMod().RemoveSuperOrder()
|
||||
p.PushClientRes(p.PlayMod.getOrderMod().BackData())
|
||||
case limitedTimeEvent.EVENT_TYPE_CARD_FESTIVAL:
|
||||
p.PlayMod.getCardMod().ResetCardFestival()
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range AddEvent { // 增加事件处理
|
||||
switch v {
|
||||
case limitedTimeEvent.EVENT_TYPE_SUPER_ORDER:
|
||||
Emit := p.PlayMod.getChessMod().GetEmitList()
|
||||
Lv := p.GetPlayerBaseMod().GetLevel()
|
||||
p.PlayMod.getOrderMod().CreateSuperOrder(Lv, Emit)
|
||||
p.PushClientRes(p.PlayMod.getOrderMod().BackData())
|
||||
case limitedTimeEvent.EVENT_TYPE_CARD_FESTIVAL:
|
||||
p.PlayMod.getCardMod().CreateCardFestival()
|
||||
}
|
||||
}
|
||||
p.PushClientRes(p.PlayMod.getLimitedTimeEventMod().BackData())
|
||||
p.PlayMod.save()
|
||||
}
|
||||
|
||||
// 限时猪猪存钱罐触发器
|
||||
func LimitedTimePiggyBankTrigger(p *Player) {
|
||||
Remain := p.PlayMod.getPiggyBankMod().TimeOut()
|
||||
if Remain > 0 {
|
||||
p.CallEvent(time.Duration(Remain)*time.Second, func() {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
p.PlayMod.getPiggyBankMod().TimeOut()
|
||||
p.SendClientRes()
|
||||
}, "PiggyBank")
|
||||
}
|
||||
p.PushClientRes(p.PlayMod.getPiggyBankMod().BackData())
|
||||
}
|
||||
77
src/server/game/LogMgr.go
Normal file
77
src/server/game/LogMgr.go
Normal file
@ -0,0 +1,77 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"server/db"
|
||||
"server/game/mod/item"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"sync"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
Login_log = 1
|
||||
LoginOut_log = 2
|
||||
Event_log = 3
|
||||
)
|
||||
|
||||
type LogMgr struct {
|
||||
L []*Log
|
||||
McronSave *cron.Cron
|
||||
Lock sync.Mutex
|
||||
}
|
||||
|
||||
type Log struct {
|
||||
Uid int32
|
||||
Type int32
|
||||
Event string
|
||||
Items []*item.Item
|
||||
TimeStamp int64
|
||||
}
|
||||
|
||||
func (L *LogMgr) InitManager() {
|
||||
L.McronSave = cron.New()
|
||||
L.L = make([]*Log, 0, 10)
|
||||
L.McronSave.AddFunc("@every 10s", func() {
|
||||
L.Lock.Lock()
|
||||
defer L.Lock.Unlock()
|
||||
for _, v := range L.L {
|
||||
switch v.Type {
|
||||
case Login_log:
|
||||
v.InsertLoginLog()
|
||||
case LoginOut_log:
|
||||
v.InsertLoginLog()
|
||||
case Event_log:
|
||||
v.InsertEventLog()
|
||||
default:
|
||||
log.Debug("unknown log type %d", v.Type)
|
||||
continue
|
||||
}
|
||||
}
|
||||
L.L = L.L[:0]
|
||||
})
|
||||
L.McronSave.Start()
|
||||
}
|
||||
|
||||
func (L *LogMgr) AddLog(logs *Log) {
|
||||
return
|
||||
L.Lock.Lock()
|
||||
defer L.Lock.Unlock()
|
||||
L.L = append(L.L, logs)
|
||||
}
|
||||
|
||||
func (Log *Log) InsertEventLog() {
|
||||
sqlStr := "INSERT INTO t_log_event (dwUin, type, event, timestamp) VALUES (?, ?, ?, ?)"
|
||||
_, err := db.SqlDb.Exec(sqlStr, Log.Uid, Log.Type, Log.Event, Log.TimeStamp)
|
||||
if err != nil {
|
||||
log.Debug("log insert event log error %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (Log *Log) InsertLoginLog() {
|
||||
sqlStr := "INSERT INTO t_log_login (dwUin, type, event, timestamp) VALUES (?, ?, ?, ?)"
|
||||
_, err := db.SqlDb.Exec(sqlStr, Log.Uid, Log.Type, Log.Event, Log.TimeStamp)
|
||||
if err != nil {
|
||||
log.Debug("log insert event log error %s", err.Error())
|
||||
}
|
||||
}
|
||||
72
src/server/game/MailMgr.go
Normal file
72
src/server/game/MailMgr.go
Normal file
@ -0,0 +1,72 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"server/GoUtil"
|
||||
"server/db"
|
||||
"server/game/mod/item"
|
||||
"server/game/mod/msg"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MailMgr struct {
|
||||
*ServerMod
|
||||
list map[int]*ServerMail
|
||||
}
|
||||
|
||||
type MailData struct {
|
||||
List map[int][]*msg.Msg
|
||||
}
|
||||
|
||||
type ServerMail struct {
|
||||
Id int
|
||||
Title string
|
||||
Content string
|
||||
Items []*item.Item
|
||||
Start_time int64
|
||||
Register_time int64
|
||||
End_time int64
|
||||
Mail_type int
|
||||
To_uids []int
|
||||
}
|
||||
|
||||
func (m *MailMgr) Init() {
|
||||
m.key = MAIL_MGR_KEY
|
||||
m.data = &MailData{
|
||||
List: make(map[int][]*msg.Msg),
|
||||
}
|
||||
m.list = make(map[int]*ServerMail)
|
||||
// 注册处理函数
|
||||
m.init()
|
||||
m.LoadMail()
|
||||
}
|
||||
|
||||
func (r *MailMgr) LoadMail() {
|
||||
// 从数据库加载邮件
|
||||
data := make([]*db.SqlServerMailStruct, 0)
|
||||
db.GetServerMailData(&data)
|
||||
for _, v := range data {
|
||||
Uids := make([]int, 0)
|
||||
UidArr := strings.Split(v.To_uids, ",")
|
||||
for _, v := range UidArr {
|
||||
Uids = append(Uids, GoUtil.Int(v))
|
||||
}
|
||||
var items []interface{}
|
||||
json.Unmarshal([]byte(v.Items), &items)
|
||||
r.list[v.Id] = &ServerMail{
|
||||
Id: v.Id,
|
||||
Title: v.Title,
|
||||
Content: v.Content,
|
||||
Items: item.ParseItem(items),
|
||||
Start_time: v.Start_time,
|
||||
Register_time: v.Register_time,
|
||||
End_time: v.End_time,
|
||||
Mail_type: v.Mail_type,
|
||||
To_uids: Uids,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *MailMgr) Sync() {
|
||||
G_GameLogicPtr.NotifyAll(&msg.Msg{Type: msg.HANDLE_TYPE_MAIL, Extra: r.list[1]})
|
||||
}
|
||||
9
src/server/game/Model.go
Normal file
9
src/server/game/Model.go
Normal file
@ -0,0 +1,9 @@
|
||||
package game
|
||||
|
||||
type PlayerSimpleData struct {
|
||||
Uid int
|
||||
Name string
|
||||
Avatar int
|
||||
Level int
|
||||
Face int
|
||||
}
|
||||
1391
src/server/game/NewChampshipsManager.go
Normal file
1391
src/server/game/NewChampshipsManager.go
Normal file
File diff suppressed because it is too large
Load Diff
113
src/server/game/OldPlayerCompensateMgr.go
Normal file
113
src/server/game/OldPlayerCompensateMgr.go
Normal file
@ -0,0 +1,113 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"server/db"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type OldPlayerCompensateMgr struct {
|
||||
MSqlCompensateStruct map[string]*db.SqlCompensateStruct
|
||||
}
|
||||
|
||||
func (p *OldPlayerCompensateMgr) SuccessSendEmail(username string) bool {
|
||||
|
||||
emailst, ok := p.MSqlCompensateStruct[username]
|
||||
if ok {
|
||||
emailst.IsSendEmail = 1
|
||||
db.FormatAllMemUpdateDb(emailst, "t_player_compensate_Data", "auto_id")
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *OldPlayerCompensateMgr) SendEmailToDb(username string, dwUin int32) bool {
|
||||
|
||||
emailst, ok := p.MSqlCompensateStruct[username]
|
||||
if ok {
|
||||
if emailst.IsSendEmail == 1 {
|
||||
return false
|
||||
} else {
|
||||
sqlSt := &db.SqlEmailStruct{}
|
||||
sqlSt.DwUin = dwUin
|
||||
sqlSt.Content = `Welcome back to our game!
|
||||
Here comes your refund for your scene progress and payment in test version!
|
||||
Have fun in new version!`
|
||||
sqlSt.CurrencyCount = 0
|
||||
sqlSt.CurrencyInfo = ""
|
||||
sqlSt.RecvTime = 0
|
||||
sqlSt.Title = "Test Players' Refund"
|
||||
sqlSt.Sender = "System"
|
||||
sqlSt.ItemCount = 0
|
||||
sqlSt.ItemInfo = ""
|
||||
sqlSt.SendTime = int32(time.Now().Unix())
|
||||
sqlSt.Status = 0
|
||||
sqlSt.Type = 1
|
||||
sqlSt.RewardId = ""
|
||||
sqlSt.RewardCount = ""
|
||||
sqlSt.LinkUrl = ""
|
||||
strarr := []string{}
|
||||
if emailst.DecorationCnt-5 > 0 {
|
||||
SceneDiamond := (emailst.DecorationCnt-5)*10 + 25
|
||||
|
||||
temp := fmt.Sprintf("Diamond|%d", SceneDiamond)
|
||||
strarr = append(strarr, temp)
|
||||
}
|
||||
f, err := strconv.ParseFloat(emailst.ChargeCnt, 64)
|
||||
var ChargeDiamond float64 = 0
|
||||
if err == nil {
|
||||
ChargeDiamond = f * 1.5 * 75
|
||||
}
|
||||
if ChargeDiamond > 0 {
|
||||
cd := int32(math.Ceil(ChargeDiamond))
|
||||
remain := cd % 10
|
||||
if remain != 0 && remain != 5 {
|
||||
if remain < 5 {
|
||||
cd = cd - remain + 5
|
||||
} else {
|
||||
cd = cd - remain + 10
|
||||
}
|
||||
}
|
||||
temp := fmt.Sprintf("Diamond|%d", cd)
|
||||
strarr = append(strarr, temp)
|
||||
|
||||
}
|
||||
sqlSt.RewardType = strings.Join(strarr, "_")
|
||||
|
||||
insertId, err1 := db.FormatAllMemInsertDb(sqlSt, "system_mail_info")
|
||||
|
||||
if err1 == nil {
|
||||
p.SuccessSendEmail(username)
|
||||
fmt.Sprintln("Success Intert Mail:" + strconv.Itoa(int(insertId)))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *OldPlayerCompensateMgr) LoadData() {
|
||||
sqlStr := "SELECT * FROM t_player_compensate_Data"
|
||||
sqlStrucks := []db.SqlCompensateStruct{}
|
||||
|
||||
p.MSqlCompensateStruct = make(map[string]*db.SqlCompensateStruct)
|
||||
if err := db.SqlDb.Select(&sqlStrucks, sqlStr); err != nil {
|
||||
fmt.Printf("get data failed, err:%v\n", err)
|
||||
return
|
||||
} else {
|
||||
|
||||
}
|
||||
for i := 0; i < len(sqlStrucks); i++ {
|
||||
p.MSqlCompensateStruct[sqlStrucks[i].DeviceId] = &sqlStrucks[i]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (p *OldPlayerCompensateMgr) InitManager() {
|
||||
p.LoadData()
|
||||
}
|
||||
664
src/server/game/Player.go
Normal file
664
src/server/game/Player.go
Normal file
@ -0,0 +1,664 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
// "server/GoUtil"
|
||||
// "server/MergeConst"
|
||||
|
||||
"errors"
|
||||
"fmt"
|
||||
"server/GoUtil"
|
||||
"server/MergeConst"
|
||||
itemCfg "server/conf/item"
|
||||
"server/game/mod/item"
|
||||
"server/game/mod/limitedTimeEvent"
|
||||
MsgMod "server/game/mod/msg"
|
||||
"server/game/mod/quest"
|
||||
"server/msg"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"server/pkg/github.com/name5566/leaf/gate"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"server/pkg/github.com/name5566/leaf/timer"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// import "reflect"
|
||||
|
||||
//"fmt"
|
||||
|
||||
type Player struct {
|
||||
playerdata map[string]PlayerDataModule
|
||||
playerdataIF map[string]interface{}
|
||||
PlayMod PlayerMod
|
||||
M_DwUin int32
|
||||
agent gate.Agent
|
||||
PAMgr *PlayerActiveMgr
|
||||
lock sync.Mutex
|
||||
stopSignal chan bool
|
||||
Msg map[string]PlayerMsg
|
||||
Trigger []*quest.Trigger
|
||||
MDispatr *timer.Dispatcher
|
||||
McronSave *cron.Cron
|
||||
McronSaveID cron.EntryID
|
||||
msgChan chan *MsgMod.Msg
|
||||
args map[string]interface{}
|
||||
timerList map[string]*timer.Timer
|
||||
stop bool
|
||||
}
|
||||
|
||||
type PlayerBackUp struct {
|
||||
PlayerBaseData *PlayerBaseData
|
||||
PlayMod []byte
|
||||
}
|
||||
|
||||
type PlayerMsg struct {
|
||||
F string
|
||||
B []byte
|
||||
}
|
||||
|
||||
func (p *Player) Stop() {
|
||||
select {
|
||||
case <-p.stopSignal:
|
||||
// 通道已经关闭
|
||||
return
|
||||
default:
|
||||
close(p.stopSignal)
|
||||
close(p.msgChan)
|
||||
}
|
||||
G_GameLogicPtr.AddLog(&Log{
|
||||
Uid: p.M_DwUin,
|
||||
Type: LoginOut_log,
|
||||
})
|
||||
p.McronSave.Stop()
|
||||
p.stop = true
|
||||
}
|
||||
|
||||
func (p *Player) CallEvent(Duration time.Duration, F func(), Label string) {
|
||||
if v, ok := p.timerList[Label]; ok {
|
||||
v.Stop()
|
||||
}
|
||||
t := p.MDispatr.AfterFunc(Duration, F)
|
||||
p.timerList[Label] = t
|
||||
}
|
||||
|
||||
// 异步请求
|
||||
func (p *Player) Send(m *MsgMod.Msg) {
|
||||
p.msgChan <- m
|
||||
}
|
||||
|
||||
func (p *Player) Call(m MsgMod.Msg) {
|
||||
HandleMsg(p, &m)
|
||||
}
|
||||
|
||||
func (p *Player) SendClientRes() {
|
||||
for _, v := range p.Msg {
|
||||
G_GameLogicPtr.PackResInfo(p.GetAgent(), v.F, v.B)
|
||||
}
|
||||
p.Msg = make(map[string]PlayerMsg)
|
||||
}
|
||||
|
||||
func (p *Player) PushClientRes(m proto.Message) {
|
||||
key := GetStructName(m)
|
||||
buff, _ := proto.Marshal(m)
|
||||
p.Msg[key] = PlayerMsg{
|
||||
F: key,
|
||||
B: buff,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Player) PushAndSendClienRes(m proto.Message) {
|
||||
key := GetStructName(m)
|
||||
buff, _ := proto.Marshal(m)
|
||||
G_GameLogicPtr.PackResInfo(p.GetAgent(), key, buff)
|
||||
}
|
||||
|
||||
func (p *Player) SendErrClienRes(m proto.Message) {
|
||||
key := GetStructName(m)
|
||||
buff, _ := proto.Marshal(m)
|
||||
G_GameLogicPtr.PackResInfo(p.GetAgent(), key, buff)
|
||||
}
|
||||
|
||||
func (p *Player) QuestTrigger(tr *quest.Trigger) {
|
||||
p.Trigger = append(p.Trigger, tr)
|
||||
}
|
||||
|
||||
func (p *Player) QuestTriggerList(tr []*quest.Trigger) {
|
||||
p.Trigger = append(p.Trigger, tr...)
|
||||
}
|
||||
|
||||
func (p *Player) ProcessTrigger() {
|
||||
IsDailyBack := false
|
||||
DailyTaskMod := p.PlayMod.getDailyTaskMod()
|
||||
|
||||
for _, tr := range p.Trigger {
|
||||
if DailyTaskMod.Trigger(tr) {
|
||||
IsDailyBack = true
|
||||
}
|
||||
}
|
||||
|
||||
if IsDailyBack {
|
||||
p.PushClientRes(DailyTaskMod.BackData())
|
||||
}
|
||||
p.Trigger = make([]*quest.Trigger, 0)
|
||||
}
|
||||
|
||||
// 接口请求之前备份数据
|
||||
func (p *Player) BackUp() *PlayerBackUp {
|
||||
BackUp := PlayerBackUp{}
|
||||
p.PlayMod.BackUp(&BackUp)
|
||||
BackUp.PlayerBaseData = p.GetPlayerBaseMod().BackUp()
|
||||
return &BackUp
|
||||
}
|
||||
|
||||
// 接口发生错误时 还原数据
|
||||
func (p *Player) Recover(backUp *PlayerBackUp) {
|
||||
backUp.PlayerBaseData.PlayerData = NewPlayerData(PLAYER_BASE_DATA, p)
|
||||
p.playerdata[PLAYER_BASE_DATA] = backUp.PlayerBaseData
|
||||
p.playerdataIF[PLAYER_BASE_DATA] = backUp.PlayerBaseData
|
||||
p.PlayMod.Recover(backUp)
|
||||
p.Msg = make(map[string]PlayerMsg)
|
||||
}
|
||||
|
||||
func (p *Player) InitPlayer(UserName string) error {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
p.msgChan = make(chan *MsgMod.Msg, 100)
|
||||
p.Msg = make(map[string]PlayerMsg)
|
||||
p.args = make(map[string]interface{})
|
||||
p.timerList = make(map[string]*timer.Timer)
|
||||
p.MDispatr = timer.NewDispatcher(10)
|
||||
p.stopSignal = make(chan bool)
|
||||
p.playerdata = make(map[string]PlayerDataModule)
|
||||
p.playerdataIF = make(map[string]interface{})
|
||||
Base := &PlayerBaseData{PlayerData: NewPlayerData(PLAYER_BASE_DATA, p)}
|
||||
p.playerdata[PLAYER_BASE_DATA] = Base
|
||||
p.playerdataIF[PLAYER_BASE_DATA] = Base
|
||||
|
||||
// 玩家基础数据
|
||||
ok := Base.LoadDataFromDB(UserName)
|
||||
if !ok {
|
||||
log.Debug("load PlayerBaseData failed:", UserName)
|
||||
return errors.New("load PlayerBaseData failed")
|
||||
}
|
||||
p.playerdata[PLAYER_BASE_DATA] = Base
|
||||
p.playerdataIF[PLAYER_BASE_DATA] = Base
|
||||
p.M_DwUin = Base.Data.DwUin
|
||||
|
||||
// 发射器解锁数据
|
||||
unlock := &PlayerEmitUnlockData{PlayerData: NewPlayerData("PlayerEmitUnlockData", p)}
|
||||
ok = unlock.LoadDataFromDB(Base.Data.DwUin)
|
||||
if !ok {
|
||||
log.Debug("load PlayerEmitUnlockData failed:", UserName)
|
||||
return errors.New("load PlayerEmitUnlockData failed")
|
||||
}
|
||||
p.playerdata["PlayerEmitUnlockData"] = unlock
|
||||
p.playerdataIF["PlayerEmitUnlockData"] = unlock
|
||||
|
||||
// 发射器数据
|
||||
Detail := &PlayerEmitDetailData{PlayerData: NewPlayerData("PlayerEmitDetailData", p)}
|
||||
ok = Detail.LoadDataFromDB(Base.Data.DwUin)
|
||||
if !ok {
|
||||
log.Debug("load PlayerEmitDetailData failed! username: %s", UserName)
|
||||
return errors.New("load PlayerEmitDetailData failed")
|
||||
}
|
||||
p.playerdata["PlayerEmitDetailData"] = Detail
|
||||
p.playerdataIF["PlayerEmitDetailData"] = Detail
|
||||
G_getGameLogic().Mlogger.Debug("load PlayerEmitDetailData:", Base.Data.DwUin)
|
||||
|
||||
// 棋盘数据
|
||||
Chess := &PlayerChessData{PlayerData: NewPlayerData("PlayerChessData", p)}
|
||||
ok = Chess.LoadDataFromDB(Base.Data.DwUin)
|
||||
if !ok {
|
||||
log.Debug("load PlayerChessData failed:", UserName)
|
||||
return errors.New("load PlayerChessData failed")
|
||||
}
|
||||
p.playerdata["PlayerChessData"] = Chess
|
||||
p.playerdataIF["PlayerChessData"] = Chess
|
||||
|
||||
// 玩家解锁宝箱数据
|
||||
Chest := &PlayerUnlockingChestData{PlayerData: NewPlayerData("PlayerUnlockingChestData", p)}
|
||||
ok = Chest.LoadDataFromDB(Base.Data.DwUin)
|
||||
if !ok {
|
||||
log.Debug("load PlayerUnlockingChestData failed:", UserName)
|
||||
return errors.New("load PlayerUnlockingChestData failed")
|
||||
}
|
||||
p.playerdata["PlayerUnlockingChestData"] = Chest
|
||||
p.playerdataIF["PlayerUnlockingChestData"] = Chest
|
||||
|
||||
// 玩家解锁宝箱数据
|
||||
Single := &PlayerSingleData{PlayerData: NewPlayerData("PlayerSingleData", p)}
|
||||
ok = Single.LoadDataFromDB(Base.Data.DwUin)
|
||||
if !ok {
|
||||
log.Debug("load PlayerSingleData failed:", UserName)
|
||||
return errors.New("load PlayerSingleData failed")
|
||||
}
|
||||
p.playerdata["PlayerSingleData"] = Single
|
||||
p.playerdataIF["PlayerSingleData"] = Single
|
||||
|
||||
// 玩家订单数据
|
||||
Charge := &PlayerChargeData{PlayerData: NewPlayerData("PlayerChargeData", p)}
|
||||
ok = Charge.LoadDataFromDB(Base.Data.DwUin)
|
||||
if !ok {
|
||||
log.Debug("load PlayerChargeData failed:", UserName)
|
||||
return errors.New("load PlayerChargeData failed")
|
||||
}
|
||||
p.playerdata["PlayerChargeData"] = Charge
|
||||
p.playerdataIF["PlayerChargeData"] = Charge
|
||||
|
||||
// 玩家好友数据
|
||||
friendEvt := &PlayerFriendEventData{PlayerData: NewPlayerData("PlayerFriendEventData", p)}
|
||||
ok = friendEvt.LoadDataFromDB(Base.Data.DwUin)
|
||||
if !ok {
|
||||
log.Debug("load PlayerFriendEventData failed:", UserName)
|
||||
return errors.New("load PlayerFriendEventData failed")
|
||||
}
|
||||
p.playerdata["PlayerFriendEventData"] = friendEvt
|
||||
p.playerdataIF["PlayerFriendEventData"] = friendEvt
|
||||
|
||||
// 玩家模块数据
|
||||
modData := &PlayerModData{PlayerData: NewPlayerData("PlayerModData", p)}
|
||||
ok = modData.LoadDataFromDB(Base.Data.DwUin)
|
||||
if !ok {
|
||||
log.Debug("load PlayerModData failed:", UserName)
|
||||
return errors.New("load PlayerModData failed")
|
||||
}
|
||||
IsUpdate := modData.InitMod()
|
||||
p.PlayMod.mod_list = modData.ModList
|
||||
p.PlayMod.is_update = IsUpdate
|
||||
|
||||
p.PAMgr = new(PlayerActiveMgr)
|
||||
p.PAMgr.InitActiveMgr(p)
|
||||
go func() { // 处理数据回调
|
||||
var cb *timer.Timer
|
||||
for {
|
||||
select {
|
||||
case <-p.stopSignal:
|
||||
return
|
||||
case cb = <-p.MDispatr.ChanTimer:
|
||||
if cb != nil {
|
||||
cb.Cb()
|
||||
} else {
|
||||
log.Debug("Timer callback or Timer is nil")
|
||||
}
|
||||
case msg := <-p.msgChan:
|
||||
fmt.Println("player recive msg:", msg)
|
||||
go HandleMsg(p, msg)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
p.McronSave = cron.New()
|
||||
_, err := p.McronSave.AddFunc("@every 1m", p.AutoSaveData)
|
||||
if err != nil {
|
||||
log.Debug("AddFunc failed:", err)
|
||||
}
|
||||
p.McronSave.Start()
|
||||
p.ZeroUpdate(nil)
|
||||
p.NoonUpdate(nil)
|
||||
p.Login()
|
||||
p.LoginBackData()
|
||||
GoUtil.RegisterEvent(MergeConst.Notify_Daily_Renew, p.ZeroUpdate, p)
|
||||
GoUtil.RegisterEvent(MergeConst.Notify_Midday_Renew, p.ZeroUpdate, p)
|
||||
SyncFriendMsg(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 异步发送消息
|
||||
func (p *Player) SendMsg(m *MsgMod.Msg) {
|
||||
p.msgChan <- m
|
||||
}
|
||||
|
||||
func (p *Player) Test() {
|
||||
p.PlayMod.getBaseMod().EnergyMul = 100
|
||||
}
|
||||
|
||||
// 零点更新
|
||||
func (p *Player) ZeroUpdate(a []interface{}) {
|
||||
VarMod := p.PlayMod.getVarMod()
|
||||
zeroTimestamp := GoUtil.ZeroTimestamp()
|
||||
PlayerBaseMod := p.GetPlayerBaseMod()
|
||||
// 零点更新
|
||||
if VarMod.DailyResetTime < zeroTimestamp {
|
||||
VarMod.DailyResetTime = zeroTimestamp
|
||||
VarMod.DailyVar = make(map[int]interface{})
|
||||
//卡牌
|
||||
p.PlayMod.getCardMod().ZeroUpdate()
|
||||
p.PushClientRes(p.PlayMod.getCardMod().BackData())
|
||||
|
||||
// 每日任务
|
||||
p.PlayMod.getDailyTaskMod().ZeroUpdate(p.GetPlayerBaseMod().GetLevel(), p.PlayMod.getDecorateMod().GetAreaId())
|
||||
p.PushClientRes(p.PlayMod.getDailyTaskMod().BackData())
|
||||
|
||||
// 能量商店
|
||||
p.PlayMod.getBaseMod().ZeroUpdate()
|
||||
p.PushClientRes(p.PlayMod.getBaseMod().BackData())
|
||||
|
||||
// 七日签到
|
||||
p.PlayMod.getSevenLoginMod().ZeroUpdate(PlayerBaseMod.GetSevenLoginAdd(), PlayerBaseMod.GetLastLoginTime())
|
||||
p.PushClientRes(p.PlayMod.getSevenLoginMod().BackData())
|
||||
|
||||
// 礼包充值
|
||||
ChessMod := p.PlayMod.getChessMod()
|
||||
p.PlayMod.getChargeMod().ZeroUpdate(ChessMod.GetEmitList())
|
||||
p.PushClientRes(p.PlayMod.getChargeMod().BackData())
|
||||
|
||||
// 无尽礼包
|
||||
p.PlayMod.getEndlessMod().ZeroUpdate(p.PlayMod.getChargeMod().GetMaxCharge())
|
||||
p.PushClientRes(p.PlayMod.getEndlessMod().BackData())
|
||||
|
||||
p.PlayMod.save()
|
||||
}
|
||||
// 周更新
|
||||
weekZeroTimestamp := GoUtil.WeekZeroTimestamp()
|
||||
if VarMod.WeeklyResetTime < weekZeroTimestamp {
|
||||
VarMod.WeeklyResetTime = weekZeroTimestamp
|
||||
VarMod.WeeklyVar = make(map[int]interface{})
|
||||
p.PlayMod.getDailyTaskMod().WeekUpdate()
|
||||
p.PushClientRes(p.PlayMod.getDailyTaskMod().BackData())
|
||||
|
||||
p.PlayMod.getLimitedTimeEventMod().WeekUpdate()
|
||||
|
||||
p.PlayMod.save()
|
||||
}
|
||||
}
|
||||
|
||||
// 十二点更新
|
||||
func (p *Player) NoonUpdate(a []interface{}) {
|
||||
VarMod := p.PlayMod.getVarMod()
|
||||
noonTimestamp := GoUtil.NoonTimestamp()
|
||||
// 零点更新
|
||||
if VarMod.NoonResetTime < noonTimestamp {
|
||||
VarMod.NoonResetTime = noonTimestamp
|
||||
ChessMod := p.PlayMod.getChessMod()
|
||||
// 礼包充值
|
||||
p.PlayMod.getChargeMod().NoonUpdate(ChessMod.GetEmitList())
|
||||
p.PushClientRes(p.PlayMod.getChargeMod().BackData())
|
||||
p.PlayMod.save()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (p *Player) Login() {
|
||||
// 添加定时器
|
||||
// 限时事件触发
|
||||
LimitedTimeEventTrigger(p, 0)
|
||||
// 猪猪银行触发
|
||||
LimitedTimePiggyBankTrigger(p)
|
||||
|
||||
p.PlayMod.getCardMod().Login(G_GameLogicPtr.SeverInfo.OpenTime)
|
||||
}
|
||||
|
||||
// 离线 保存数据
|
||||
func (p *Player) ClearData() {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
log.Release("uid: %d, ClearData", p.M_DwUin)
|
||||
for _, v := range p.playerdata {
|
||||
v.ClearData()
|
||||
}
|
||||
p.PlayMod.ClearData(p)
|
||||
GoUtil.RemoveEvent(MergeConst.Notify_Daily_Renew, p.ZeroUpdate, p)
|
||||
p.Stop()
|
||||
}
|
||||
|
||||
func (p *Player) AutoSaveData() {
|
||||
//保存数据
|
||||
for _, v := range p.playerdata {
|
||||
v.SaveDataFromDB("")
|
||||
}
|
||||
p.PlayMod.ClearData(p)
|
||||
}
|
||||
|
||||
// 重新连接
|
||||
func (p *Player) Reconnect() {
|
||||
for _, v := range p.playerdata {
|
||||
v.Reconnect(true)
|
||||
}
|
||||
p.LoginBackData()
|
||||
}
|
||||
|
||||
// 获取conn连接
|
||||
func (p *Player) GetAgent() gate.Agent {
|
||||
return p.agent
|
||||
}
|
||||
|
||||
// 设置conn连接
|
||||
func (p *Player) SetAgent(a gate.Agent) {
|
||||
p.agent = a
|
||||
}
|
||||
|
||||
func (p *Player) GetIFGameData(key string) interface{} {
|
||||
|
||||
v, ok := p.playerdataIF[key]
|
||||
if ok {
|
||||
return v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Player) GetPlayerBaseMod() *PlayerBaseData {
|
||||
v, ok := p.playerdataIF[PLAYER_BASE_DATA]
|
||||
if ok {
|
||||
return v.(*PlayerBaseData)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Player) GetGameData(key string) PlayerDataModule {
|
||||
v, ok := p.playerdata[key]
|
||||
if ok {
|
||||
return v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Player) GetGameMod(key string) interface{} {
|
||||
v, ok := p.playerdata[key]
|
||||
if ok {
|
||||
return v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Player) GetAgentByPlayer() gate.Agent {
|
||||
return p.agent
|
||||
}
|
||||
|
||||
// 处理物品
|
||||
func (p *Player) HandleItem(itemList []*item.Item, Label string) error {
|
||||
if len(itemList) == 0 {
|
||||
return nil
|
||||
}
|
||||
is_update := false
|
||||
ResCard := make([]*msg.CardPack, 0)
|
||||
ResItem := make([]*msg.ItemInfo, 0)
|
||||
for _, v := range itemList {
|
||||
if v.Num == 0 {
|
||||
continue
|
||||
}
|
||||
if v.Num > 0 && Label != "" {
|
||||
ResItem = append(ResItem, &msg.ItemInfo{Id: int32(v.Id), Num: int32(v.Num)})
|
||||
}
|
||||
IType := itemCfg.GetItemType(v.Id)
|
||||
switch IType {
|
||||
case item.ITEM_TYPE_ENERGY: // 能量
|
||||
err := p.GetPlayerBaseMod().AddEnergy(v.Num)
|
||||
is_update = true
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case item.ITEM_TYPE_STAR: // 星星
|
||||
err := p.GetPlayerBaseMod().AddStar(v.Num)
|
||||
is_update = true
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case item.ITEM_TYPE_DIAMOND: // 钻石
|
||||
err := p.GetPlayerBaseMod().AddDiamond(v.Num)
|
||||
is_update = true
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case item.ITEM_TYPE_CARD_PACK: // 卡包
|
||||
CardMod := p.PlayMod.getCardMod()
|
||||
Effect := itemCfg.GetItemEffect(v.Id)
|
||||
for i := 0; i < v.Num; i++ {
|
||||
NewCard, err := CardMod.OpenCardPack(Effect)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ResCard = append(ResCard, &msg.CardPack{Id: int32(v.Id), Card: GoUtil.SliceIntToInt32(NewCard)})
|
||||
}
|
||||
p.PushClientRes(CardMod.BackData())
|
||||
case item.ITEM_TYPE_CHESS: // 棋子
|
||||
ChessMod := p.PlayMod.getChessMod()
|
||||
for i := 0; i < v.Num; i++ {
|
||||
ChessMod.AddChessBuff(v.Id)
|
||||
}
|
||||
p.PushClientRes(ChessMod.BackData())
|
||||
case item.ITEM_TYPE_LIMIED_TIME_EVENT: // 限时事件
|
||||
EffectList := itemCfg.GetItemEffectList(v.Id)
|
||||
LimitedTimeEventMod := p.PlayMod.getLimitedTimeEventMod()
|
||||
if len(EffectList) < 2 {
|
||||
log.Debug("Effect List error;item id :%d", v.Id)
|
||||
continue
|
||||
}
|
||||
EndTime := LimitedTimeEventMod.AddEvent(EffectList[0], EffectList[1])
|
||||
p.PushClientRes(&msg.LimitEventNotify{
|
||||
Id: int32(EffectList[0]),
|
||||
Type: limitedTimeEvent.EVENT_NOTIFY_TYPE_ADD,
|
||||
EndTime: int32(EndTime),
|
||||
Cd: int32(EffectList[1]),
|
||||
})
|
||||
LimitedTimeEventTrigger(p, EffectList[0])
|
||||
case item.ITEM_TYPE_PIGGY_BANK: // 猪猪银行
|
||||
PiggyBankMod := p.PlayMod.getPiggyBankMod()
|
||||
Effect := itemCfg.GetItemEffect(v.Id)
|
||||
PiggyBankMod.AddPiggyBank(Effect)
|
||||
LimitedTimePiggyBankTrigger(p)
|
||||
p.PushClientRes(PiggyBankMod.BackData())
|
||||
default:
|
||||
log.Debug("Item type error;item id :%d", v.Id)
|
||||
}
|
||||
}
|
||||
ResItemPopId := 0
|
||||
if v, ok := p.args["ResItemPopId"]; ok {
|
||||
ResItemPopId = v.(int)
|
||||
}
|
||||
if len(ResItem) != 0 || len(ResCard) != 0 {
|
||||
p.SendErrClienRes(&msg.ResItemPop{
|
||||
Id: int32(ResItemPopId),
|
||||
Items: ResItem,
|
||||
CardPacks: ResCard,
|
||||
Lable: Label,
|
||||
})
|
||||
}
|
||||
|
||||
if is_update {
|
||||
p.PushClientRes(p.GetPlayerBaseMod().BackAsset())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 登录返回数据
|
||||
func (p *Player) LoginBackData() {
|
||||
p.PushClientRes(p.PlayMod.mod_list.Base.BackData())
|
||||
p.PushClientRes(p.PlayMod.mod_list.Handbook.BackData())
|
||||
p.PushClientRes(p.PlayMod.mod_list.Base.BackData())
|
||||
p.PushClientRes(p.PlayMod.mod_list.Chess.BackData())
|
||||
p.PushClientRes(p.PlayMod.mod_list.Order.BackData())
|
||||
p.PushClientRes(p.PlayMod.mod_list.Card.BackData())
|
||||
p.PushClientRes(p.PlayMod.mod_list.Decorate.BackData())
|
||||
p.PushClientRes(p.PlayMod.mod_list.DailyTask.BackData())
|
||||
p.PushClientRes(p.PlayMod.mod_list.Face.BackData())
|
||||
p.PushClientRes(p.PlayMod.mod_list.Avatar.BackData())
|
||||
p.PushClientRes(p.PlayMod.mod_list.SevenLogin.BackData())
|
||||
p.PushClientRes(p.PlayMod.mod_list.Activity.BackData())
|
||||
p.PushClientRes(p.PlayMod.mod_list.LimitedTimeEvent.ProgressBackData())
|
||||
p.PushClientRes(p.PlayMod.mod_list.Charge.BackData())
|
||||
p.PushClientRes(p.PlayMod.mod_list.Endless.BackData())
|
||||
p.PushClientRes(p.PlayMod.mod_list.PiggyBank.BackData())
|
||||
p.PushClientRes(p.GetPlayerBaseMod().BackAsset())
|
||||
p.PushClientRes(p.GetPlayerBaseMod().BackKv())
|
||||
|
||||
p.PushClientRes(p.PlayMod.mod_list.Champship.BackData())
|
||||
FriendBackData(p)
|
||||
}
|
||||
|
||||
// 获取玩家简单数据
|
||||
func (p *Player) GetSimpleData(Uid int, simple *PlayerSimpleData) error {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
p.Msg = make(map[string]PlayerMsg)
|
||||
p.args = make(map[string]interface{})
|
||||
p.timerList = make(map[string]*timer.Timer)
|
||||
p.MDispatr = timer.NewDispatcher(10)
|
||||
p.stopSignal = make(chan bool)
|
||||
p.playerdata = make(map[string]PlayerDataModule)
|
||||
p.playerdataIF = make(map[string]interface{})
|
||||
Base := &PlayerBaseData{PlayerData: NewPlayerData(PLAYER_BASE_DATA, p)}
|
||||
p.playerdata[PLAYER_BASE_DATA] = Base
|
||||
p.playerdataIF[PLAYER_BASE_DATA] = Base
|
||||
|
||||
// 玩家基础数据
|
||||
ok := Base.GetDataByUid(Uid)
|
||||
if !ok {
|
||||
return errors.New("load PlayerBaseData failed")
|
||||
}
|
||||
p.playerdata[PLAYER_BASE_DATA] = Base
|
||||
p.playerdataIF[PLAYER_BASE_DATA] = Base
|
||||
p.M_DwUin = Base.Data.DwUin
|
||||
|
||||
// 玩家模块数据
|
||||
modData := &PlayerModData{PlayerData: NewPlayerData("PlayerModData", p)}
|
||||
ok = modData.LoadDataFromDB(Base.Data.DwUin)
|
||||
if !ok {
|
||||
return errors.New("load PlayerModData failed")
|
||||
}
|
||||
modData.InitMod()
|
||||
p.PlayMod.mod_list = modData.ModList
|
||||
simple.Name = p.GetPlayerBaseMod().GetName()
|
||||
simple.Avatar = p.PlayMod.getAvatarMod().SetId
|
||||
simple.Face = p.PlayMod.getFaceMod().SetId
|
||||
simple.Level = p.GetPlayerBaseMod().GetLevel()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Player) HandleInUserRank() {
|
||||
DecorateMod := p.PlayMod.getDecorateMod()
|
||||
AreaId := DecorateMod.GetAreaId()
|
||||
Progress := DecorateMod.GetProgress()
|
||||
Score := float64(AreaId*1000 + Progress)
|
||||
// 更新排行榜
|
||||
m := &MsgMod.Msg{
|
||||
Type: MsgMod.HANDLE_TYPE_RANK,
|
||||
SendT: GoUtil.Now(),
|
||||
Extra: RankMsg{
|
||||
Uid: int(p.M_DwUin),
|
||||
Score: Score,
|
||||
RankType: RANK_TYPE_USER,
|
||||
},
|
||||
}
|
||||
G_GameLogicPtr.RankMgrSend(m)
|
||||
}
|
||||
|
||||
func (p *Player) HandleInChampshipRank() {
|
||||
ChampshipMod := p.PlayMod.getChampshipMod()
|
||||
|
||||
Score := float64(ChampshipMod.GetScore())
|
||||
// 更新排行榜
|
||||
m := &MsgMod.Msg{
|
||||
Type: MsgMod.HANDLE_TYPE_RANK,
|
||||
SendT: GoUtil.Now(),
|
||||
Extra: RankMsg{
|
||||
Uid: int(p.M_DwUin),
|
||||
Score: Score,
|
||||
RankType: RANK_TYPE_USER,
|
||||
},
|
||||
}
|
||||
G_GameLogicPtr.RankMgrSend(m)
|
||||
}
|
||||
2724
src/server/game/PlayerActiveData.go
Normal file
2724
src/server/game/PlayerActiveData.go
Normal file
File diff suppressed because it is too large
Load Diff
208
src/server/game/PlayerActiveManager.go
Normal file
208
src/server/game/PlayerActiveManager.go
Normal file
@ -0,0 +1,208 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"server/db"
|
||||
"server/gamedata"
|
||||
"server/msg"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type PlayerActiveMgr struct {
|
||||
M_Player *Player
|
||||
}
|
||||
|
||||
func (p *PlayerActiveMgr) OpenNewLimitActivity(args []interface{}) {
|
||||
notify := &msg.NotifyLimitedTimeActiveData{}
|
||||
notify.MActiveList = []*msg.LimitedTimeActiveStruct{}
|
||||
|
||||
id := args[0].(int)
|
||||
activityCfg := gamedata.GetConfigByName("Activity")
|
||||
record := activityCfg.Index(id).(*gamedata.ActivityRecord)
|
||||
|
||||
act := &msg.LimitedTimeActiveStruct{}
|
||||
act.StartSvrTime = args[1].(int32)
|
||||
act.EndSvrTime = args[2].(int32)
|
||||
act.Type = int32(record.Type)
|
||||
ActiveID := args[3].(int32)
|
||||
if act.Type == 1 {
|
||||
|
||||
if ActiveID == int32(0) {
|
||||
act.ActiveID = G_GameLogicPtr.InitPassportInsertDb(p.M_Player, act.StartSvrTime, act.EndSvrTime, id)
|
||||
} else {
|
||||
act.ActiveID = ActiveID
|
||||
}
|
||||
actor := &PlayerPassportData{PlayerActiveData: NewActiveData("PlayerPassportData", p.M_Player)}
|
||||
ok := actor.LoadDataFromDB(p.M_Player.M_DwUin)
|
||||
if ok {
|
||||
p.M_Player.playerdata["PlayerPassportData"] = actor
|
||||
p.M_Player.playerdataIF["PlayerPassportData"] = actor
|
||||
}
|
||||
|
||||
}
|
||||
if act.Type == 2 {
|
||||
if ActiveID == int32(0) {
|
||||
act.ActiveID = G_GameLogicPtr.InitPromotionInsertDb(p.M_Player, act.StartSvrTime, act.EndSvrTime, id)
|
||||
} else {
|
||||
act.ActiveID = ActiveID
|
||||
}
|
||||
actor := &PlayerPromotionData{PlayerActiveData: NewActiveData("PlayerPromotionData", p.M_Player)}
|
||||
ok := actor.LoadDataFromDB(p.M_Player.M_DwUin)
|
||||
if ok {
|
||||
p.M_Player.playerdata["PlayerPromotionData"] = actor
|
||||
p.M_Player.playerdataIF["PlayerPromotionData"] = actor
|
||||
}
|
||||
}
|
||||
if act.Type == 3 {
|
||||
if ActiveID == int32(0) {
|
||||
act.ActiveID = G_GameLogicPtr.InitInfinitePackInsertDb(p.M_Player, act.StartSvrTime, act.EndSvrTime, id)
|
||||
} else {
|
||||
act.ActiveID = ActiveID
|
||||
}
|
||||
actor := &PlayerInfinitePackData{PlayerActiveData: NewActiveData("PlayerInfinitePackData", p.M_Player)}
|
||||
ok := actor.LoadDataFromDB(p.M_Player.M_DwUin)
|
||||
if ok {
|
||||
p.M_Player.playerdata["PlayerInfinitePackData"] = actor
|
||||
p.M_Player.playerdataIF["PlayerInfinitePackData"] = actor
|
||||
}
|
||||
}
|
||||
|
||||
if act.Type == 4 {
|
||||
if ActiveID == int32(0) {
|
||||
act.ActiveID = G_GameLogicPtr.Init7DayLoginInsertDb(p.M_Player, act.StartSvrTime, act.EndSvrTime, id)
|
||||
} else {
|
||||
act.ActiveID = ActiveID
|
||||
}
|
||||
actor := &Player7DayLoginData{PlayerActiveData: NewActiveData("Player7DayLoginData", p.M_Player)}
|
||||
ok := actor.LoadDataFromDB(p.M_Player.M_DwUin)
|
||||
if ok {
|
||||
p.M_Player.playerdata["Player7DayLoginData"] = actor
|
||||
p.M_Player.playerdataIF["Player7DayLoginData"] = actor
|
||||
}
|
||||
}
|
||||
|
||||
if act.Type == 5 {
|
||||
if ActiveID == int32(0) {
|
||||
act.ActiveID = G_GameLogicPtr.InitCardCollectInsertDb(p.M_Player, act.StartSvrTime, act.EndSvrTime, id)
|
||||
} else {
|
||||
act.ActiveID = ActiveID
|
||||
}
|
||||
actor := &PlayerCardCollectData{PlayerActiveData: NewActiveData("PlayerCardCollectData", p.M_Player)}
|
||||
ok := actor.LoadDataFromDB(p.M_Player.M_DwUin)
|
||||
if ok {
|
||||
p.M_Player.playerdata["PlayerCardCollectData"] = actor
|
||||
p.M_Player.playerdataIF["PlayerCardCollectData"] = actor
|
||||
}
|
||||
}
|
||||
|
||||
notify.MActiveList = append(notify.MActiveList, act)
|
||||
data, _ := proto.Marshal(notify)
|
||||
agent := p.M_Player.GetAgentByPlayer()
|
||||
G_GameLogicPtr.PackResInfo(agent, "NotifyLimitedTimeActiveData", data)
|
||||
}
|
||||
|
||||
func NewActiveData(dataName string, player *Player) *PlayerActiveData {
|
||||
act := &PlayerActiveData{
|
||||
PlayerData: NewPlayerData(dataName, player),
|
||||
MisDirty: false,
|
||||
}
|
||||
|
||||
return act
|
||||
}
|
||||
|
||||
func (p *PlayerActiveMgr) InitActiveMgr(player *Player) {
|
||||
p.M_Player = player
|
||||
activityCfg := gamedata.GetConfigByName("Activity")
|
||||
map1 := make(map[int]string)
|
||||
map1[1] = "t_player_LimitPassport"
|
||||
map1[2] = "t_player_LimitPromotion"
|
||||
map1[3] = "t_player_LimitInfinitePack"
|
||||
map1[4] = "t_player_Limit7DayLogin"
|
||||
map1[5] = "t_player_card_data"
|
||||
for i := 0; i < len(G_GameLogicPtr.M_LimitActiveList); i++ {
|
||||
Id := G_GameLogicPtr.M_LimitActiveList[i]
|
||||
record := activityCfg.Index(Id).(*gamedata.ActivityRecord)
|
||||
sqlStr := "Select * From " + map1[record.Type] + " Where ConfigActId = ? And dwUin = ?"
|
||||
if record.Type == 1 {
|
||||
struct1 := []db.SqlLimitPassportStruct{}
|
||||
st := G_GameLogicPtr.GetActiveParamById(Id)
|
||||
Start := st.StartTime
|
||||
EndTime := st.EndTime
|
||||
if err := db.SqlDb.Select(&struct1, sqlStr, Id, player.M_DwUin); err != nil {
|
||||
p.OpenNewLimitActivity([]interface{}{Id, Start, EndTime, int32(0)})
|
||||
} else {
|
||||
if len(struct1) == 0 {
|
||||
p.OpenNewLimitActivity([]interface{}{Id, Start, EndTime, int32(0)})
|
||||
} else {
|
||||
p.OpenNewLimitActivity([]interface{}{Id, Start, EndTime, struct1[0].ActiveID})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if record.Type == 2 {
|
||||
struct1 := []db.SqlLimitPromotionStruct{}
|
||||
st := G_GameLogicPtr.GetActiveParamById(Id)
|
||||
Start := st.StartTime
|
||||
EndTime := st.EndTime
|
||||
if err := db.SqlDb.Select(&struct1, sqlStr, Id, player.M_DwUin); err != nil {
|
||||
p.OpenNewLimitActivity([]interface{}{Id, Start, EndTime, int32(0)})
|
||||
} else {
|
||||
if len(struct1) == 0 {
|
||||
p.OpenNewLimitActivity([]interface{}{Id, Start, EndTime, int32(0)})
|
||||
} else {
|
||||
p.OpenNewLimitActivity([]interface{}{Id, Start, EndTime, struct1[0].ActiveID})
|
||||
}
|
||||
}
|
||||
}
|
||||
if record.Type == 3 {
|
||||
struct1 := []db.SqlLimitInfinitePackStruct{}
|
||||
st := G_GameLogicPtr.GetActiveParamById(Id)
|
||||
Start := st.StartTime
|
||||
EndTime := st.EndTime
|
||||
if err := db.SqlDb.Select(&struct1, sqlStr, Id, player.M_DwUin); err != nil {
|
||||
p.OpenNewLimitActivity([]interface{}{Id, Start, EndTime, int32(0)})
|
||||
} else {
|
||||
if len(struct1) == 0 {
|
||||
p.OpenNewLimitActivity([]interface{}{Id, Start, EndTime, int32(0)})
|
||||
} else {
|
||||
p.OpenNewLimitActivity([]interface{}{Id, Start, EndTime, struct1[0].ActiveID})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if record.Type == 4 {
|
||||
struct1 := []db.SqlSevenDayLoginStruct{}
|
||||
st := G_GameLogicPtr.GetActiveParamById(Id)
|
||||
Start := st.StartTime
|
||||
EndTime := st.EndTime
|
||||
if err := db.SqlDb.Select(&struct1, sqlStr, Id, player.M_DwUin); err != nil {
|
||||
p.OpenNewLimitActivity([]interface{}{Id, Start, EndTime, int32(0)})
|
||||
} else {
|
||||
if len(struct1) == 0 {
|
||||
p.OpenNewLimitActivity([]interface{}{Id, Start, EndTime, int32(0)})
|
||||
} else {
|
||||
p.OpenNewLimitActivity([]interface{}{Id, Start, EndTime, struct1[0].ActiveID})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if record.Type == 5 {
|
||||
struct1 := []db.SqlCardCollectStruct{}
|
||||
st := G_GameLogicPtr.GetActiveParamById(Id)
|
||||
Start := st.StartTime
|
||||
EndTime := st.EndTime
|
||||
if err := db.SqlDb.Select(&struct1, sqlStr, Id, player.M_DwUin); err != nil {
|
||||
p.OpenNewLimitActivity([]interface{}{Id, Start, EndTime, int32(0)})
|
||||
} else {
|
||||
if len(struct1) == 0 {
|
||||
p.OpenNewLimitActivity([]interface{}{Id, Start, EndTime, int32(0)})
|
||||
} else {
|
||||
p.OpenNewLimitActivity([]interface{}{Id, Start, EndTime, struct1[0].ActiveID})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
723
src/server/game/PlayerBaseMod.go
Normal file
723
src/server/game/PlayerBaseMod.go
Normal file
@ -0,0 +1,723 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"server/GoUtil"
|
||||
"server/MergeConst"
|
||||
userCfg "server/conf/user"
|
||||
"server/db"
|
||||
"server/game/mod/limitedTimeEvent"
|
||||
"server/game/mod/quest"
|
||||
"server/msg"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"server/pkg/github.com/name5566/leaf/timer"
|
||||
"time"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type PlayerBaseData struct {
|
||||
*PlayerData
|
||||
Data msg.ResPlayerBaseInfo
|
||||
KeyValueData map[int]string
|
||||
MLeafTimer *timer.Timer
|
||||
MTicker *time.Ticker
|
||||
McronSave *cron.Cron
|
||||
McronSaveID cron.EntryID
|
||||
Mdispatr *timer.Dispatcher
|
||||
DailyRenewTime int32
|
||||
Update bool
|
||||
isKeyValueDb bool
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) GetData() interface{} {
|
||||
return &p.Data
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) BackUp() *PlayerBaseData {
|
||||
return &PlayerBaseData{
|
||||
Data: msg.ResPlayerBaseInfo{
|
||||
Diamond: p.Data.Diamond,
|
||||
DwUin: p.Data.DwUin,
|
||||
Energy: p.Data.Energy,
|
||||
Star: p.Data.Star,
|
||||
RecoverTime: p.Data.RecoverTime,
|
||||
Level: p.Data.Level,
|
||||
Exp: p.Data.Exp,
|
||||
StartOrderId: p.Data.StartOrderId,
|
||||
MusicCode: p.Data.MusicCode,
|
||||
Guild: p.Data.Guild,
|
||||
PackUnlockCount: p.Data.PackUnlockCount,
|
||||
LastPlayTime: p.Data.LastPlayTime,
|
||||
EnergyBuyCount: p.Data.EnergyBuyCount,
|
||||
LoginTime: p.Data.LoginTime,
|
||||
UserName: p.Data.UserName,
|
||||
LogoutTime: p.Data.LogoutTime,
|
||||
Todayolinetime: p.Data.Todayolinetime,
|
||||
Rolecreatetime: p.Data.Rolecreatetime,
|
||||
LastChampGroupID: p.Data.LastChampGroupID,
|
||||
ChampshipsGroupID: p.Data.ChampshipsGroupID,
|
||||
NoAd: p.Data.NoAd,
|
||||
FaceBookId: p.Data.FaceBookId,
|
||||
},
|
||||
MLeafTimer: p.MLeafTimer,
|
||||
MTicker: p.MTicker,
|
||||
McronSave: p.McronSave,
|
||||
McronSaveID: p.McronSaveID,
|
||||
Mdispatr: p.Mdispatr,
|
||||
DailyRenewTime: p.DailyRenewTime,
|
||||
isKeyValueDb: p.isKeyValueDb,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) Recover(old *PlayerBaseData) *PlayerBaseData {
|
||||
old.Data = msg.ResPlayerBaseInfo{
|
||||
Diamond: p.Data.Diamond,
|
||||
DwUin: p.Data.DwUin,
|
||||
Energy: p.Data.Energy,
|
||||
Star: p.Data.Star,
|
||||
RecoverTime: p.Data.RecoverTime,
|
||||
Level: p.Data.Level,
|
||||
Exp: p.Data.Exp,
|
||||
StartOrderId: p.Data.StartOrderId,
|
||||
MusicCode: p.Data.MusicCode,
|
||||
Guild: p.Data.Guild,
|
||||
PackUnlockCount: p.Data.PackUnlockCount,
|
||||
LastPlayTime: p.Data.LastPlayTime,
|
||||
EnergyBuyCount: p.Data.EnergyBuyCount,
|
||||
LoginTime: p.Data.LoginTime,
|
||||
UserName: p.Data.UserName,
|
||||
LogoutTime: p.Data.LogoutTime,
|
||||
Todayolinetime: p.Data.Todayolinetime,
|
||||
Rolecreatetime: p.Data.Rolecreatetime,
|
||||
LastChampGroupID: p.Data.LastChampGroupID,
|
||||
ChampshipsGroupID: p.Data.ChampshipsGroupID,
|
||||
NoAd: p.Data.NoAd,
|
||||
FaceBookId: p.Data.FaceBookId,
|
||||
}
|
||||
return old
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) LoadDataFromDB(UserName interface{}) bool {
|
||||
sqlStr := "SELECT * FROM t_player_baseinfo WHERE user_name = ?"
|
||||
sqlStruck := db.ResPlayerBaseInfo{}
|
||||
if err := db.SqlDb.Get(&sqlStruck, sqlStr, UserName); err != nil {
|
||||
log.Debug("get data failed, err:%v\n", err)
|
||||
return false
|
||||
}
|
||||
sqlStr1 := "SELECT * FROM t_player_client_data WHERE dwUin = ?"
|
||||
sqlStruck1 := db.SqlModStruct{}
|
||||
db.SqlDb.Get(&sqlStruck1, sqlStr1, sqlStruck.DwUin)
|
||||
|
||||
p.Data.Diamond = sqlStruck.Diamond
|
||||
p.Data.DwUin = sqlStruck.DwUin
|
||||
p.Data.Energy = sqlStruck.Energy
|
||||
p.Data.Star = sqlStruck.Star
|
||||
p.Data.RecoverTime = sqlStruck.RecoverTime
|
||||
p.Data.Level = sqlStruck.Level
|
||||
p.Data.Exp = sqlStruck.Exp
|
||||
p.Data.StartOrderId = sqlStruck.StartOrderId
|
||||
p.Data.MusicCode = sqlStruck.MusicCode
|
||||
p.Data.Guild = sqlStruck.Guild
|
||||
p.Data.PackUnlockCount = sqlStruck.PackUnlockCount
|
||||
p.Data.LastPlayTime = sqlStruck.LastPlayTime
|
||||
p.Data.EnergyBuyCount = sqlStruck.EnergyBuyCount
|
||||
p.Data.LoginTime = int32(time.Now().Unix())
|
||||
p.Data.UserName = sqlStruck.UserName
|
||||
p.Data.LogoutTime = sqlStruck.LogoutTime
|
||||
p.Data.Todayolinetime = sqlStruck.Todayolinetime
|
||||
p.Data.Rolecreatetime = sqlStruck.Rolecreatetime
|
||||
p.Data.LastChampGroupID = sqlStruck.LastChampGroupID
|
||||
p.Data.ChampshipsGroupID = sqlStruck.ChampshipsGroupID
|
||||
p.DailyRenewTime = sqlStruck.DailyRenewTime
|
||||
p.Data.NoAd = sqlStruck.NoAd
|
||||
p.Data.FaceBookId = sqlStruck.FaceBookId
|
||||
p.McronSave = cron.New()
|
||||
p.Reconnect(false)
|
||||
p.AddCompensateEmail()
|
||||
p.KeyValueData = make(map[int]string)
|
||||
var buf bytes.Buffer
|
||||
buf.Write(sqlStruck1.ModData)
|
||||
decode := gob.NewDecoder(&buf)
|
||||
err := decode.Decode(&p.KeyValueData)
|
||||
if err != nil {
|
||||
p.KeyValueData = make(map[int]string)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) ProcessCallback() {
|
||||
deltaTime := p.Data.LoginTime - p.Data.LogoutTime
|
||||
|
||||
if p.M_Player.GetGameData("Player7DayCallBackData") == nil {
|
||||
data := &Player7DayCallBackData{PlayerData: NewPlayerData("Player7DayCallBackData", p.M_Player)}
|
||||
ok := data.LoadDataFromDB(p.Data.DwUin)
|
||||
if ok {
|
||||
p.M_Player.playerdata["Player7DayCallBackData"] = data
|
||||
p.M_Player.playerdataIF["Player7DayCallBackData"] = data
|
||||
}
|
||||
}
|
||||
|
||||
if deltaTime >= 7*3600*24 && p.Data.LogoutTime > 0 {
|
||||
p.M_Player.playerdataIF["Player7DayCallBackData"].(*Player7DayCallBackData).OpenNewCallBack()
|
||||
} else {
|
||||
p.M_Player.playerdataIF["Player7DayCallBackData"].(*Player7DayCallBackData).ProcessIsOutline()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) IsPlayerLoginCallback() bool {
|
||||
return p.Data.LoginTime-p.Data.LogoutTime >= 7*3600*24 && p.Data.LogoutTime > 0
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) GetRoleCreateTime() int32 {
|
||||
return p.Data.Rolecreatetime
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) AddSta() error {
|
||||
curtime := time.Now().Unix()
|
||||
delta := curtime - (int64)(p.Data.RecoverTime)
|
||||
Recover := userCfg.GetRecover(int(p.Data.Level))
|
||||
Addsta := int(delta) / Recover
|
||||
if Addsta <= 0 {
|
||||
return nil
|
||||
}
|
||||
if p.GetMaxEnergy() > p.Data.Energy {
|
||||
p.Data.Energy = p.Data.Energy + int32(Addsta)
|
||||
if p.Data.Energy > p.GetMaxEnergy() {
|
||||
p.Data.Energy = p.GetMaxEnergy()
|
||||
}
|
||||
p.M_Player.CallEvent(time.Duration(Recover)*time.Second, func() {
|
||||
p.M_Player.lock.Lock()
|
||||
defer p.M_Player.lock.Unlock()
|
||||
p.AddSta()
|
||||
}, "AddEnergy")
|
||||
}
|
||||
p.Data.RecoverTime = int32(curtime)
|
||||
p.M_Player.SendErrClienRes(p.BackAsset())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) Reconnect(b bool) {
|
||||
p.AddSta()
|
||||
if G_GameLogicPtr.DailyTaskTimestamp > (int64)(p.DailyRenewTime) {
|
||||
p.DailyRenewTime = int32(G_GameLogicPtr.DailyTaskTimestamp)
|
||||
p.Data.EnergyBuyCount = 0
|
||||
}
|
||||
GoUtil.RegisterEvent(MergeConst.Notify_Daily_Renew, p.Notify_Daily_Renew, p)
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) AddCompensateEmail() {
|
||||
G_GameLogicPtr.MOldPlayerCompensateMgr.SendEmailToDb(p.Data.UserName, p.Data.DwUin)
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) SetChampshipID(ChampshipsGroupID int32, isNotify bool) {
|
||||
p.Data.LastChampGroupID = p.Data.ChampshipsGroupID
|
||||
p.Data.ChampshipsGroupID = ChampshipsGroupID
|
||||
|
||||
if isNotify {
|
||||
notify := &msg.NotifyChampshipOpen{}
|
||||
notify.CurChampshipsId = G_GameLogicPtr.M_SvrGlobal.CurChampshipsId
|
||||
notify.LastChampshipsGroupID = p.Data.LastChampGroupID
|
||||
notify.ChampshipsGroupID = p.Data.ChampshipsGroupID
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(notify)
|
||||
G_getGameLogic().PackResInfo(agent, "NotifyChampshipOpen", data)
|
||||
|
||||
}
|
||||
|
||||
p.SaveDataFromDB("")
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) Notify_Daily_Renew(param []interface{}) {
|
||||
p.Data.EnergyBuyCount = 0
|
||||
p.DailyRenewTime = int32(G_GameLogicPtr.DailyTaskTimestamp)
|
||||
notify := &msg.NotifyRenewBuyEnergyCnt{}
|
||||
notify.DwUin = p.M_Player.M_DwUin
|
||||
notify.CurCnt = 0
|
||||
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(notify)
|
||||
G_getGameLogic().PackResInfo(agent, "NotifyRenewBuyEnergyCnt", data)
|
||||
p.SaveDataFromDB("")
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) SaveDataFromDB(Key interface{}) bool {
|
||||
// G_getGameLogic().Mlogger.Debug("SaveDataFromDB:", p.Data.DwUin)
|
||||
sqlStruck := db.ResPlayerBaseInfo{}
|
||||
sqlStruck.Diamond = p.Data.Diamond
|
||||
sqlStruck.DwUin = p.Data.DwUin
|
||||
sqlStruck.Energy = p.Data.Energy
|
||||
sqlStruck.Star = p.Data.Star
|
||||
sqlStruck.RecoverTime = p.Data.RecoverTime
|
||||
sqlStruck.Level = p.Data.Level
|
||||
sqlStruck.Exp = p.Data.Exp
|
||||
sqlStruck.StartOrderId = p.Data.StartOrderId
|
||||
sqlStruck.MusicCode = p.Data.MusicCode
|
||||
sqlStruck.Guild = p.Data.Guild
|
||||
sqlStruck.PackUnlockCount = p.Data.PackUnlockCount
|
||||
sqlStruck.LastPlayTime = p.Data.LastPlayTime
|
||||
sqlStruck.EnergyBuyCount = p.Data.EnergyBuyCount
|
||||
sqlStruck.LoginTime = p.Data.LoginTime
|
||||
sqlStruck.UserName = p.Data.UserName
|
||||
sqlStruck.LogoutTime = p.Data.LogoutTime
|
||||
sqlStruck.Todayolinetime = p.Data.Todayolinetime
|
||||
sqlStruck.Rolecreatetime = p.Data.Rolecreatetime
|
||||
sqlStruck.DailyRenewTime = p.DailyRenewTime
|
||||
sqlStruck.NoAd = p.Data.NoAd
|
||||
sqlStruck.ChampshipsGroupID = p.Data.ChampshipsGroupID
|
||||
sqlStruck.LastChampGroupID = p.Data.LastChampGroupID
|
||||
sqlStruck.FaceBookId = p.Data.FaceBookId
|
||||
db.FormatAllMemUpdateDb(&sqlStruck, "t_player_baseinfo", "dwUin")
|
||||
|
||||
// 存储KeyValue
|
||||
var buf bytes.Buffer
|
||||
encode := gob.NewEncoder(&buf)
|
||||
encode.Encode(p.KeyValueData)
|
||||
db.SavePlayerClientData(&db.SqlModStruct{
|
||||
DwUin: p.Data.DwUin,
|
||||
ModData: buf.Bytes(),
|
||||
UpdataTime: int32(GoUtil.Now()),
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) GetMaxEnergyMul() int {
|
||||
MaxEnergyMul := userCfg.GetEnergyMulByLv(int(p.Data.Level))
|
||||
if p.M_Player.PlayMod.getLimitedTimeEventMod().CheckExist(limitedTimeEvent.EVENT_TYPE_HIGH_ROLLER) {
|
||||
MaxEnergyMul = 10
|
||||
}
|
||||
return MaxEnergyMul
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) GetMaxEnergy() int32 {
|
||||
MaxSta := MergeConst.G_Sta_Limit
|
||||
|
||||
if p.Data.Level < 7 {
|
||||
MaxSta = MergeConst.G_Sta_Limit
|
||||
} else if p.Data.Level < 12 {
|
||||
MaxSta = 120
|
||||
} else if p.Data.Level < 19 {
|
||||
MaxSta = 130
|
||||
} else if p.Data.Level < 27 {
|
||||
MaxSta = 135
|
||||
} else if p.Data.Level < 38 {
|
||||
MaxSta = 140
|
||||
} else if p.Data.Level < 44 {
|
||||
MaxSta = 145
|
||||
} else if p.Data.Level < 59 {
|
||||
MaxSta = 150
|
||||
} else {
|
||||
MaxSta = 155
|
||||
}
|
||||
return MaxSta
|
||||
}
|
||||
|
||||
// 定时增加体力
|
||||
func (p *PlayerBaseData) NotifyAddSta(cnt int, timeStamp int64) {
|
||||
p.M_Player.lock.Lock()
|
||||
defer p.M_Player.lock.Unlock()
|
||||
if p.GetMaxEnergy() <= p.Data.Energy {
|
||||
return
|
||||
}
|
||||
G_getGameLogic().Mlogger.Debug("NotifyAddSta:", p.Data.DwUin)
|
||||
p.Data.Energy = p.Data.Energy + int32(cnt)
|
||||
p.Data.RecoverTime = int32(timeStamp)
|
||||
|
||||
notify := &msg.NotifyAddEnergy{}
|
||||
notify.AddCnt = int32(cnt)
|
||||
notify.DwUin = p.M_Player.M_DwUin
|
||||
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(notify)
|
||||
G_getGameLogic().PackResInfo(agent, "NotifyAddEnergy", data)
|
||||
}
|
||||
|
||||
// 更新游戏道具
|
||||
func (p *PlayerBaseData) UpdateBaseItemInfo(update *msg.UpdateBaseItemInfo) {
|
||||
for k, v := range update.MUpdateItem {
|
||||
switch k {
|
||||
case 4:
|
||||
p.Data.EnergyBuyCount = v
|
||||
case 8:
|
||||
p.Data.Guild = v
|
||||
case 9:
|
||||
p.Data.PackUnlockCount = v
|
||||
case 10:
|
||||
p.Data.EmitOrderCnt = v
|
||||
case 11:
|
||||
p.Data.LastPlayTime = v
|
||||
}
|
||||
}
|
||||
p.SaveDataFromDB("")
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) ReqRemoveAd(buf []byte) {
|
||||
req := &msg.ReqRemoveAd{}
|
||||
res := &msg.ResRemoveAd{}
|
||||
proto.Unmarshal(buf, req)
|
||||
|
||||
p.Data.NoAd = 1
|
||||
res.ResultCode = 0
|
||||
p.SaveDataFromDB("")
|
||||
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResRemoveAd", data)
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) ResPlayerBaseInfo(player *Player) {
|
||||
if player != p.M_Player {
|
||||
return
|
||||
}
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(&p.Data)
|
||||
G_getGameLogic().PackResInfo(agent, "ResPlayerBaseInfo", data)
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) BackKv() *msg.ResKv {
|
||||
kv := make(map[int32]string)
|
||||
for k, v := range p.KeyValueData {
|
||||
kv[int32(k)] = v
|
||||
}
|
||||
return &msg.ResKv{
|
||||
Kv: kv,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) ReqBindFacebookAccount(buf []byte) {
|
||||
req := &msg.ReqBindFacebookAccount{}
|
||||
res := &msg.ResBindFacebookAccount{}
|
||||
proto.Unmarshal(buf, req)
|
||||
|
||||
sqlStr := "SELECT * FROM t_player_baseinfo WHERE FaceBookId = ?"
|
||||
sqlStruck := db.ResPlayerBaseInfo{}
|
||||
isHaveOther := false
|
||||
|
||||
if err := db.SqlDb.Get(&sqlStruck, sqlStr, req.BindAccountId); err != nil {
|
||||
isHaveOther = false
|
||||
} else {
|
||||
isHaveOther = true
|
||||
}
|
||||
if isHaveOther {
|
||||
if sqlStruck.DwUin == p.Data.DwUin {
|
||||
res.ResultCode = MergeConst.Protocol_FaceBook_Binded
|
||||
} else {
|
||||
res.ResultCode = MergeConst.Protocol_FaceBook_Binded_other
|
||||
}
|
||||
} else {
|
||||
res.ResultCode = 0
|
||||
p.Data.FaceBookId = req.BindAccountId
|
||||
res.BindAccountId = req.BindAccountId
|
||||
p.SaveDataFromDB("")
|
||||
}
|
||||
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResBindFacebookAccount", data)
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) ReqUnBindFacebook(buf []byte) {
|
||||
req := &msg.ReqUnBindFacebook{}
|
||||
res := &msg.ResUnBindFacebook{}
|
||||
proto.Unmarshal(buf, req)
|
||||
|
||||
res.ResultCode = 0
|
||||
res.BindAccountId = req.BindAccountId
|
||||
p.Data.FaceBookId = ""
|
||||
p.SaveDataFromDB("")
|
||||
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResUnBindFacebook", data)
|
||||
}
|
||||
func (p *PlayerBaseData) ReqOnlyBindFacebook(buf []byte) {
|
||||
req := &msg.ReqOnlyBindFacebook{}
|
||||
res := &msg.ResOnlyBindFacebook{}
|
||||
proto.Unmarshal(buf, req)
|
||||
|
||||
sqlStr := "SELECT * FROM t_player_baseinfo WHERE FaceBookId = ?"
|
||||
sqlStruck := db.ResPlayerBaseInfo{}
|
||||
isHaveOther := false
|
||||
|
||||
if err := db.SqlDb.Get(&sqlStruck, sqlStr, req.BindAccountId); err != nil {
|
||||
isHaveOther = false
|
||||
} else {
|
||||
isHaveOther = true
|
||||
}
|
||||
if isHaveOther {
|
||||
if sqlStruck.DwUin == p.Data.DwUin {
|
||||
res.ResultCode = MergeConst.Protocol_FaceBook_Binded
|
||||
} else {
|
||||
sqlStruck.FaceBookId = ""
|
||||
db.FormatAllMemUpdateDb(&sqlStruck, "t_player_baseinfo", "dwUin")
|
||||
res.ResultCode = 0
|
||||
p.Data.FaceBookId = req.BindAccountId
|
||||
res.BindAccountId = req.BindAccountId
|
||||
p.SaveDataFromDB("")
|
||||
}
|
||||
} else {
|
||||
res.ResultCode = 0
|
||||
p.Data.FaceBookId = req.BindAccountId
|
||||
res.BindAccountId = req.BindAccountId
|
||||
p.SaveDataFromDB("")
|
||||
}
|
||||
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResOnlyBindFacebook", data)
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) ReqSynGameData(buf []byte) {
|
||||
req := &msg.ReqSynGameData{}
|
||||
res := &msg.ResSynGameData{}
|
||||
proto.Unmarshal(buf, req)
|
||||
|
||||
sqlStr := "SELECT * FROM t_player_baseinfo WHERE FaceBookId = ?"
|
||||
sqlStruck := db.ResPlayerBaseInfo{}
|
||||
isHaveOther := false
|
||||
|
||||
if err := db.SqlDb.Get(&sqlStruck, sqlStr, req.NewFBId); err != nil {
|
||||
isHaveOther = false
|
||||
} else {
|
||||
isHaveOther = true
|
||||
}
|
||||
if sqlStruck.DwUin == p.M_Player.M_DwUin {
|
||||
return
|
||||
}
|
||||
|
||||
if OldPlayer, ok := G_GameLogicPtr.M_Players[sqlStruck.DwUin]; ok {
|
||||
agent := OldPlayer.GetAgentByPlayer()
|
||||
// notify := &msg.ForceKickOut{}
|
||||
notify := &msg.ResSynGameData{}
|
||||
data, _ := proto.Marshal(notify)
|
||||
if agent != nil {
|
||||
G_getGameLogic().PackResInfo(agent, "ResSynGameData", data)
|
||||
}
|
||||
OldPlayer.ClearData()
|
||||
delete(G_GameLogicPtr.M_Players, sqlStruck.DwUin)
|
||||
} else {
|
||||
player := G_GameLogicPtr.FindOfflinePlayer(sqlStruck.DwUin)
|
||||
if player != nil {
|
||||
timer1 := G_GameLogicPtr.MReadyToRemoveList[player]
|
||||
timer1.Disabled()
|
||||
G_GameLogicPtr.Mdispatr.ChanTimer <- timer1
|
||||
timer1.Stop()
|
||||
delete(G_GameLogicPtr.MReadyToRemoveList, player)
|
||||
}
|
||||
}
|
||||
|
||||
if isHaveOther {
|
||||
if sqlStruck.DwUin == p.Data.DwUin {
|
||||
res.ResultCode = MergeConst.Protocol_FaceBook_Binded
|
||||
} else {
|
||||
ReplaceName := sqlStruck.UserName
|
||||
UserName := p.Data.UserName
|
||||
res.ResultCode = 0
|
||||
|
||||
sqlStr1 := "SELECT * FROM t_account WHERE user_name = ?"
|
||||
sqlAccStruck1 := db.Db_Account{}
|
||||
if err2 := db.SqlDb.Get(&sqlAccStruck1, sqlStr1, UserName); err2 != nil {
|
||||
|
||||
} else {
|
||||
sqlAccStruck1.UserName = ""
|
||||
db.FormatAllMemUpdateDb(&sqlAccStruck1, "t_account", "auto_id")
|
||||
}
|
||||
p.Data.UserName = ""
|
||||
p.SaveDataFromDB("")
|
||||
|
||||
sqlStruck.FaceBookId = req.NewFBId
|
||||
sqlStruck.UserName = UserName
|
||||
db.FormatAllMemUpdateDb(&sqlStruck, "t_player_baseinfo", "dwUin")
|
||||
|
||||
sqlStr := "SELECT * FROM t_account WHERE user_name = ?"
|
||||
sqlAccStruck := db.Db_Account{}
|
||||
|
||||
if err2 := db.SqlDb.Get(&sqlAccStruck, sqlStr, ReplaceName); err2 != nil {
|
||||
|
||||
} else {
|
||||
sqlAccStruck.UserName = UserName
|
||||
db.FormatAllMemUpdateDb(&sqlAccStruck, "t_account", "auto_id")
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
res.ResultCode = 0
|
||||
|
||||
}
|
||||
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResSynGameData", data)
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) ClearData() bool {
|
||||
p.Data.LogoutTime = int32(time.Now().Unix())
|
||||
p.SaveDataFromDB("")
|
||||
GoUtil.RemoveEvent(MergeConst.Notify_Daily_Renew, p.Notify_Daily_Renew, p)
|
||||
p.McronSave.Remove(p.McronSaveID)
|
||||
p.McronSave.Stop()
|
||||
if p.MLeafTimer != nil {
|
||||
p.MLeafTimer.Stop()
|
||||
p.MLeafTimer = nil
|
||||
}
|
||||
if p.MTicker != nil {
|
||||
p.MTicker.Stop()
|
||||
p.MTicker = nil
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 增加减少体力
|
||||
func (p *PlayerBaseData) AddEnergy(cnt int) error {
|
||||
NewEnergy := p.Data.Energy + int32(cnt)
|
||||
if NewEnergy < 0 {
|
||||
return errors.New("能量不足")
|
||||
}
|
||||
if cnt < 0 {
|
||||
p.M_Player.QuestTrigger(&quest.Trigger{Label: quest.TRIGGER_LABEL_ENERGY, A: []interface{}{-cnt}})
|
||||
}
|
||||
if p.Data.Energy >= p.GetMaxEnergy() && NewEnergy < p.GetMaxEnergy() {
|
||||
Recover := userCfg.GetRecover(int(p.Data.Level))
|
||||
p.M_Player.CallEvent(time.Duration(Recover)*time.Second, func() {
|
||||
p.M_Player.lock.Lock()
|
||||
defer p.M_Player.lock.Unlock()
|
||||
p.AddSta()
|
||||
}, "AddEnergy")
|
||||
p.Data.RecoverTime = int32(time.Now().Unix())
|
||||
}
|
||||
p.Data.Energy = NewEnergy
|
||||
return nil
|
||||
}
|
||||
|
||||
// 增加减少星星
|
||||
func (p *PlayerBaseData) AddStar(cnt int) error {
|
||||
NewStar := p.Data.Star + int32(cnt)
|
||||
if NewStar < 0 {
|
||||
return errors.New("星星不足")
|
||||
}
|
||||
|
||||
p.Data.Star = NewStar
|
||||
return nil
|
||||
}
|
||||
|
||||
// 增加减少钻石
|
||||
func (p *PlayerBaseData) AddDiamond(cnt int) error {
|
||||
NewDiamond := p.Data.Diamond + int32(cnt)
|
||||
if NewDiamond < 0 {
|
||||
return errors.New("钻石不足")
|
||||
}
|
||||
p.Data.Diamond = NewDiamond
|
||||
return nil
|
||||
}
|
||||
|
||||
// 增加经验
|
||||
func (p *PlayerBaseData) AddExp(exp int) (int, error) {
|
||||
p.Data.Exp += int32(exp)
|
||||
upLv := 0
|
||||
upExp := userCfg.GetLevUpExp(int(p.Data.Level))
|
||||
if p.Data.Exp >= int32(upExp) {
|
||||
p.Data.Level++
|
||||
p.Data.Exp -= int32(upExp)
|
||||
|
||||
// 日常任务解锁
|
||||
DailyTaskMod := p.M_Player.PlayMod.getDailyTaskMod()
|
||||
DecorateMod := p.M_Player.PlayMod.getDecorateMod()
|
||||
if DailyTaskMod.LevUpTrigger(int(p.Data.Level), DecorateMod.GetAreaId()) {
|
||||
p.M_Player.PushClientRes(DailyTaskMod.BackData())
|
||||
}
|
||||
upLv = int(p.Data.Level)
|
||||
|
||||
// 棋盘背包解锁
|
||||
p.M_Player.PushClientRes(p.BackAsset())
|
||||
ChessMod := p.M_Player.PlayMod.getChessMod()
|
||||
if ChessMod.TriggerChessBagUnlock(int(p.Data.Level)) {
|
||||
p.M_Player.PushClientRes(ChessMod.BackData())
|
||||
}
|
||||
|
||||
ChargeMod := p.M_Player.PlayMod.getChargeMod()
|
||||
ChargeMod.TriggerChargeUnlock(int(p.Data.Level), ChessMod.GetEmitList())
|
||||
p.M_Player.PushClientRes(ChargeMod.BackData())
|
||||
}
|
||||
p.M_Player.PushClientRes(p.BackAsset())
|
||||
return upLv, nil
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) GetLevel() int {
|
||||
return int(p.Data.Level)
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) BackAsset() *msg.ResPlayerAsset {
|
||||
return &msg.ResPlayerAsset{
|
||||
DwUin: p.Data.DwUin,
|
||||
Diamond: p.Data.Diamond,
|
||||
Energy: p.Data.Energy,
|
||||
Star: p.Data.Star,
|
||||
RecoverTime: p.Data.RecoverTime,
|
||||
Level: p.Data.Level,
|
||||
Exp: p.Data.Exp,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) GetSevenLoginAdd() int {
|
||||
return userCfg.GetSevenloginAdd(int(p.Data.Level))
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) GetLastLoginTime() int {
|
||||
return int(p.Data.LoginTime)
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) GetName() string {
|
||||
return p.Data.UserName
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) GetLoginTime() int64 {
|
||||
return int64(p.Data.LoginTime)
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) GetDataByUid(Uid interface{}) bool {
|
||||
sqlStr := "SELECT * FROM t_player_baseinfo WHERE dwUin = ?"
|
||||
sqlStruck := db.ResPlayerBaseInfo{}
|
||||
if err := db.SqlDb.Get(&sqlStruck, sqlStr, Uid); err != nil {
|
||||
log.Debug("get data failed, err:%v\n", err)
|
||||
return false
|
||||
}
|
||||
|
||||
p.Data.Diamond = sqlStruck.Diamond
|
||||
p.Data.DwUin = sqlStruck.DwUin
|
||||
p.Data.Energy = sqlStruck.Energy
|
||||
p.Data.Star = sqlStruck.Star
|
||||
p.Data.RecoverTime = sqlStruck.RecoverTime
|
||||
p.Data.Level = sqlStruck.Level
|
||||
p.Data.Exp = sqlStruck.Exp
|
||||
p.Data.StartOrderId = sqlStruck.StartOrderId
|
||||
p.Data.MusicCode = sqlStruck.MusicCode
|
||||
p.Data.Guild = sqlStruck.Guild
|
||||
p.Data.PackUnlockCount = sqlStruck.PackUnlockCount
|
||||
p.Data.LastPlayTime = sqlStruck.LastPlayTime
|
||||
p.Data.EnergyBuyCount = sqlStruck.EnergyBuyCount
|
||||
p.Data.LoginTime = int32(time.Now().Unix())
|
||||
p.Data.UserName = sqlStruck.UserName
|
||||
p.Data.LogoutTime = sqlStruck.LogoutTime
|
||||
p.Data.Todayolinetime = sqlStruck.Todayolinetime
|
||||
p.Data.Rolecreatetime = sqlStruck.Rolecreatetime
|
||||
p.Data.LastChampGroupID = sqlStruck.LastChampGroupID
|
||||
p.Data.ChampshipsGroupID = sqlStruck.ChampshipsGroupID
|
||||
p.DailyRenewTime = sqlStruck.DailyRenewTime
|
||||
p.Data.NoAd = sqlStruck.NoAd
|
||||
p.Data.FaceBookId = sqlStruck.FaceBookId
|
||||
p.McronSave = cron.New()
|
||||
p.Reconnect(false)
|
||||
p.AddCompensateEmail()
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerBaseData) SetKv(Key int, Value string) error {
|
||||
if p.KeyValueData == nil {
|
||||
p.KeyValueData = make(map[int]string)
|
||||
}
|
||||
p.KeyValueData[Key] = Value
|
||||
return nil
|
||||
}
|
||||
340
src/server/game/PlayerChessMod.go
Normal file
340
src/server/game/PlayerChessMod.go
Normal file
@ -0,0 +1,340 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"server/GoUtil"
|
||||
mergeDataCfg "server/conf/mergeData"
|
||||
"server/db"
|
||||
"server/game/mod/item"
|
||||
"server/game/mod/quest"
|
||||
"server/msg"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type PlayerChessData struct {
|
||||
*PlayerData
|
||||
Data msg.ResPlayerChessData
|
||||
ColorData msg.ResChessColorData
|
||||
}
|
||||
|
||||
func (p *PlayerChessData) LoadDataFromDB(dwUin interface{}) bool {
|
||||
sqlStr := "SELECT * FROM t_player_chess_data WHERE dwUin = ?"
|
||||
sqlStruck := db.SqlChessStruct{}
|
||||
p.Data.MChessData = make(map[string]int32)
|
||||
p.ColorData.MChessColorData = make(map[string]int32)
|
||||
|
||||
if err := db.SqlDb.Get(&sqlStruck, sqlStr, dwUin.(int32)); err != nil {
|
||||
fmt.Printf("get data failed, err:%v\n", err)
|
||||
p.IsHaveDataDb = false
|
||||
} else {
|
||||
p.IsHaveDataDb = true
|
||||
}
|
||||
|
||||
if sqlStruck.MChessData != "" {
|
||||
arr := strings.Split(sqlStruck.MChessData, "_")
|
||||
|
||||
for i := 0; i < len(arr); i++ {
|
||||
ss := strings.Split(arr[i], ",")
|
||||
id, err := strconv.ParseInt(ss[1], 10, 32)
|
||||
key := ss[0]
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
p.Data.MChessData[key] = int32(id)
|
||||
}
|
||||
}
|
||||
if sqlStruck.MChessColorData != "" {
|
||||
arr := strings.Split(sqlStruck.MChessColorData, "_")
|
||||
|
||||
for i := 0; i < len(arr); i++ {
|
||||
ss := strings.Split(arr[i], ",")
|
||||
id, err := strconv.ParseInt(ss[1], 10, 32)
|
||||
key := ss[0]
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
p.ColorData.MChessColorData[key] = int32(id)
|
||||
}
|
||||
}
|
||||
|
||||
p.Data.DwUin = dwUin.(int32)
|
||||
p.Reconnect(false)
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerChessData) Reconnect(b bool) {
|
||||
|
||||
}
|
||||
|
||||
func (p *PlayerChessData) SetValueByKey(k string) {
|
||||
if k != "" {
|
||||
p.Data.MChessData[k] = p.Data.MChessData[k] + 1
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PlayerChessData) GetValueByKey(k string) int32 {
|
||||
|
||||
v, ok := p.Data.MChessData[k]
|
||||
if ok {
|
||||
return v
|
||||
}
|
||||
return -1
|
||||
}
|
||||
func (p *PlayerChessData) GetKeyByEmitID(EmitID int32) string {
|
||||
for k := range p.Data.MChessData {
|
||||
units := strings.Split(k, "@")
|
||||
if len(units) >= 4 {
|
||||
n, _ := strconv.Atoi(units[3])
|
||||
if EmitID == int32(n) {
|
||||
return k
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *PlayerChessData) SaveDataFromDB(Key interface{}) bool {
|
||||
var strarr []string
|
||||
var strarr1 []string
|
||||
for k, v := range p.Data.MChessData {
|
||||
str := fmt.Sprintf("%s,%d", k, v)
|
||||
strarr = append(strarr, str)
|
||||
}
|
||||
str_concat := strings.Join(strarr, "_")
|
||||
|
||||
for k, v := range p.ColorData.MChessColorData {
|
||||
str := fmt.Sprintf("%s,%d", k, v)
|
||||
strarr1 = append(strarr1, str)
|
||||
}
|
||||
str_concat1 := strings.Join(strarr1, "_")
|
||||
|
||||
sqlStruck := db.SqlChessStruct{}
|
||||
sqlStruck.DwUin = p.M_Player.M_DwUin
|
||||
sqlStruck.MChessData = str_concat
|
||||
sqlStruck.MChessColorData = str_concat1
|
||||
if p.IsHaveDataDb {
|
||||
db.FormatAllMemUpdateDb(&sqlStruck, "t_player_chess_data", "dwUin")
|
||||
} else {
|
||||
db.FormatAllMemInsertDb(&sqlStruck, "t_player_chess_data")
|
||||
}
|
||||
p.IsHaveDataDb = true
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerChessData) ResPlayerChessData(player *Player) {
|
||||
if player != p.M_Player {
|
||||
return
|
||||
}
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
Msg := &p.Data
|
||||
Msg.ChessList = p.M_Player.PlayMod.getChessMod().BackData().ChessList
|
||||
data, _ := proto.Marshal(Msg)
|
||||
G_getGameLogic().PackResInfo(agent, "ResPlayerChessData", data)
|
||||
}
|
||||
|
||||
func (p *PlayerChessData) ResChessColorData(player *Player) {
|
||||
if player != p.M_Player {
|
||||
return
|
||||
}
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(&p.ColorData)
|
||||
G_getGameLogic().PackResInfo(agent, "ResChessColorData", data)
|
||||
}
|
||||
|
||||
// 同步棋盘数据
|
||||
func (p *PlayerChessData) UpdatePlayerChessData(buf []byte) error {
|
||||
update := &msg.UpdatePlayerChessData{}
|
||||
proto.Unmarshal(buf, update)
|
||||
err := p.HandleChess(update.MChessHandle)
|
||||
if err != nil {
|
||||
res := &msg.ResUpdatePlayerChessData{
|
||||
Code: msg.RES_CODE_FAIL,
|
||||
Msg: err.Error(),
|
||||
}
|
||||
p.M_Player.SendErrClienRes(res)
|
||||
return err
|
||||
}
|
||||
p.M_Player.PushClientRes(&msg.ResUpdatePlayerChessData{
|
||||
Code: msg.RES_CODE_SUCCESS,
|
||||
})
|
||||
p.Data.MChessData = update.MChessData
|
||||
|
||||
if !p.checkChessEqual() {
|
||||
res := &msg.ResUpdatePlayerChessData{
|
||||
Code: msg.RES_CODE_FAIL,
|
||||
Msg: "棋子数据不一致",
|
||||
}
|
||||
log.Debug("棋子数据不一致, %v---%v", p.Data.MChessData, p.M_Player.PlayMod.getChessMod().GetChessList())
|
||||
p.M_Player.SendErrClienRes(res)
|
||||
return fmt.Errorf("棋子数据不一致")
|
||||
}
|
||||
p.SaveDataFromDB("")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PlayerChessData) UpdateChessData(MChessData map[string]int32) error {
|
||||
p.Data.MChessData = MChessData
|
||||
if !p.checkChessEqual() {
|
||||
res := &msg.ResUpdatePlayerChessData{
|
||||
Code: msg.RES_CODE_FAIL,
|
||||
Msg: "棋子数据不一致",
|
||||
}
|
||||
log.Debug("棋子数据不一致, %v---%v", p.Data.MChessData, p.M_Player.PlayMod.getChessMod().GetChessList())
|
||||
p.M_Player.SendErrClienRes(res)
|
||||
return fmt.Errorf("棋子数据不一致")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 检查棋子数据是否一致
|
||||
func (p *PlayerChessData) checkChessEqual() bool {
|
||||
if len(p.Data.MChessData) == 0 {
|
||||
return true
|
||||
}
|
||||
ChessList := p.M_Player.PlayMod.getChessMod().GetChessList()
|
||||
if len(ChessList) != len(p.Data.MChessData) {
|
||||
return false
|
||||
}
|
||||
aCopy := make([]int, len(ChessList))
|
||||
bCopy := make([]int, len(p.Data.MChessData))
|
||||
for _, v := range ChessList {
|
||||
aCopy = append(aCopy, int(v))
|
||||
}
|
||||
|
||||
for _, v := range p.Data.MChessData {
|
||||
bCopy = append(bCopy, int(v))
|
||||
}
|
||||
return SlicesEqual(aCopy, bCopy)
|
||||
}
|
||||
|
||||
// 棋子操作
|
||||
func (p *PlayerChessData) HandleChess(handle_list []*msg.ChessHandle) error {
|
||||
sort.Slice(handle_list, func(i, j int) bool {
|
||||
return handle_list[i].Id < handle_list[j].Id
|
||||
})
|
||||
ChessMod := p.M_Player.PlayMod.getChessMod()
|
||||
HandbookMod := p.M_Player.PlayMod.getHandbookMod()
|
||||
var addChessCostEnergy int
|
||||
var buyChess int
|
||||
TriggerList := make([]*quest.Trigger, 0)
|
||||
itemList := make([]*item.Item, 0)
|
||||
AddChessList := make([]int, 0)
|
||||
AddNewEmit := make([]int, 0)
|
||||
for _, v := range handle_list {
|
||||
ChessId := int(v.ChessId)
|
||||
EmitId := int(v.Emit)
|
||||
switch v.Type {
|
||||
case msg.HANDLE_TYPE_ADD: //增加棋子
|
||||
err := ChessMod.AddChess(ChessId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
AddChessList = append(AddChessList, ChessId)
|
||||
if !GoUtil.InArray(EmitId, []int{561, 562, 563, 564, 701, 702, 703, 704, 705, 706}) { // 宝箱生成的棋子不扣体力
|
||||
addChessCostEnergy++
|
||||
}
|
||||
|
||||
b := HandbookMod.SetHandbook(ChessId) // 添加图鉴
|
||||
if b {
|
||||
AddNewEmit = append(AddNewEmit, ChessId)
|
||||
}
|
||||
p.M_Player.PushClientRes(HandbookMod.BackData())
|
||||
case msg.HANDLE_TYPE_COMPOSE: //合成棋子
|
||||
NewChessId, err := ChessMod.ComposeChess(ChessId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
HandbookMod := p.M_Player.PlayMod.getHandbookMod() // 添加图鉴
|
||||
b := HandbookMod.SetHandbook(NewChessId)
|
||||
if b {
|
||||
AddNewEmit = append(AddNewEmit, NewChessId)
|
||||
}
|
||||
AddChessList = append(AddChessList, NewChessId)
|
||||
NewChessIdLv := mergeDataCfg.GetLvById(NewChessId)
|
||||
TriggerList = append(TriggerList, &quest.Trigger{Label: quest.TRIGGER_LABEL_MERGELVTIME, A: []interface{}{NewChessIdLv}})
|
||||
TriggerList = append(TriggerList, &quest.Trigger{Label: quest.TRIGGER_LABEL_MERGETIME})
|
||||
p.M_Player.PushClientRes(HandbookMod.BackData())
|
||||
case msg.HANDLE_TYPE_BUY: //购买棋子
|
||||
loseGold, err := ChessMod.BuyChess(ChessId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buyChess += loseGold
|
||||
itemList = append(itemList, &item.Item{Id: item.ITEM_STAR_ID, Num: int(-loseGold)})
|
||||
case msg.HANDLE_TYPE_SELL: //出售棋子
|
||||
items, err := ChessMod.SellChess(ChessId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
itemList = item.Merge(itemList, items)
|
||||
case msg.HANDLE_TYPE_REMOVE: //移除棋子
|
||||
ChessMod.RemoveChess(ChessId)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//扣除体力
|
||||
if addChessCostEnergy > 0 {
|
||||
EnergyPow := p.M_Player.PlayMod.getBaseMod().GetEnergyMul()
|
||||
ReduceEneny := int(math.Pow(2, float64(EnergyPow))) * addChessCostEnergy
|
||||
itemList = append(itemList, &item.Item{Id: item.ITEM_ENERGY_ID, Num: -ReduceEneny})
|
||||
G_GameLogicPtr.AddLog(&Log{
|
||||
Type: Event_log,
|
||||
Uid: p.M_Player.M_DwUin,
|
||||
Event: "sync map info",
|
||||
})
|
||||
}
|
||||
err := p.M_Player.HandleItem(itemList, "HandleChess")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
OrderMod := p.M_Player.PlayMod.getOrderMod()
|
||||
Update := OrderMod.CreateExtraOrder(AddChessList, AddNewEmit, ChessMod.GetChessList())
|
||||
if Update {
|
||||
p.M_Player.PushClientRes(OrderMod.BackData())
|
||||
}
|
||||
p.M_Player.QuestTriggerList(TriggerList)
|
||||
p.M_Player.PushClientRes(ChessMod.BackData())
|
||||
p.M_Player.PlayMod.save()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PlayerChessData) UpdateChessColorData(buf []byte) {
|
||||
update := &msg.UpdateChessColorData{}
|
||||
err := proto.Unmarshal(buf, update)
|
||||
if err != nil {
|
||||
fmt.Println("unmarshal failed, err:", err)
|
||||
return
|
||||
|
||||
}
|
||||
p.ColorData.MChessColorData = update.MChessColorData
|
||||
|
||||
p.SaveDataFromDB("")
|
||||
}
|
||||
func (p *PlayerChessData) GetChestKeyByValue(id int32) string {
|
||||
for k, v := range p.Data.MChessData {
|
||||
if id == v {
|
||||
return k
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *PlayerChessData) ClearData() bool {
|
||||
p.SaveDataFromDB("")
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// api
|
||||
2327
src/server/game/PlayerDataModule.go
Normal file
2327
src/server/game/PlayerDataModule.go
Normal file
File diff suppressed because it is too large
Load Diff
283
src/server/game/PlayerEmailData.go
Normal file
283
src/server/game/PlayerEmailData.go
Normal file
@ -0,0 +1,283 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/robfig/cron/v3"
|
||||
"server/MergeConst"
|
||||
"server/db"
|
||||
"server/msg"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type PlayerEmailData struct {
|
||||
*PlayerData
|
||||
Data msg.ResBriefEmailData
|
||||
SqlStructs []db.SqlEmailStruct
|
||||
ZeroCronID cron.EntryID
|
||||
WeekCronID cron.EntryID
|
||||
Mcron *cron.Cron
|
||||
}
|
||||
|
||||
func (p *PlayerEmailData) LoadDataFromDB(dwUin interface{}) bool {
|
||||
|
||||
sqlStr := "SELECT * FROM system_mail_info WHERE dwUin = ?"
|
||||
if err := db.SqlDb.Select(&p.SqlStructs, sqlStr, dwUin.(int32)); err != nil {
|
||||
fmt.Printf("get data failed, err:%v\n", err)
|
||||
p.IsHaveDataDb = false
|
||||
} else {
|
||||
p.IsHaveDataDb = true
|
||||
}
|
||||
|
||||
CurTime := int32(time.Now().Unix())
|
||||
|
||||
deleteList := []int{}
|
||||
deleteDbList := []int32{}
|
||||
for i := 0; i < len(p.SqlStructs); i++ {
|
||||
item := p.SqlStructs[i]
|
||||
if item.RecvTime > 0 && item.Status == 1 && CurTime-item.RecvTime >= MergeConst.G_Clear_Read_Email_Limit {
|
||||
deleteList = append(deleteList, i)
|
||||
deleteDbList = append(deleteDbList, item.EmailId)
|
||||
}
|
||||
}
|
||||
tempList := []db.SqlEmailStruct{}
|
||||
startIndex := 0
|
||||
for i := 0; i < len(deleteList); i++ {
|
||||
curIndex := deleteList[i]
|
||||
if curIndex == startIndex {
|
||||
startIndex = startIndex + 1
|
||||
continue
|
||||
}
|
||||
tempList = append(tempList, p.SqlStructs[startIndex:curIndex]...)
|
||||
startIndex = curIndex + 1
|
||||
}
|
||||
if startIndex <= len(p.SqlStructs)-1 {
|
||||
tempList = append(tempList, p.SqlStructs[startIndex:]...)
|
||||
}
|
||||
p.SqlStructs = tempList
|
||||
p.DeleteOutlineMail(deleteDbList)
|
||||
|
||||
sort.Slice(p.SqlStructs, func(i, j int) bool {
|
||||
if p.SqlStructs[i].Status == p.SqlStructs[j].Status {
|
||||
if p.SqlStructs[i].Type == p.SqlStructs[j].Type {
|
||||
return p.SqlStructs[i].SendTime > p.SqlStructs[j].SendTime
|
||||
} else {
|
||||
return p.SqlStructs[i].Type > p.SqlStructs[j].Type
|
||||
}
|
||||
|
||||
} else {
|
||||
return p.SqlStructs[i].Status < p.SqlStructs[j].Status
|
||||
}
|
||||
})
|
||||
|
||||
for i := 0; i < len(p.SqlStructs); i++ {
|
||||
item := p.SqlStructs[i]
|
||||
if item.Status == 0 {
|
||||
p.SqlStructs[i].Status = 1
|
||||
db.FormatAllMemUpdateDb(&p.SqlStructs[i], "system_mail_info", "mail_id")
|
||||
}
|
||||
}
|
||||
|
||||
p.Mcron = cron.New()
|
||||
p.Reconnect(false)
|
||||
|
||||
return true
|
||||
}
|
||||
func (p *PlayerEmailData) Reconnect(b bool) {
|
||||
p.ZeroCronID, _ = p.Mcron.AddFunc("@every 5s", func() {
|
||||
p.IntervalGetUnsendMails()
|
||||
})
|
||||
p.Mcron.Start()
|
||||
}
|
||||
func (p *PlayerEmailData) DeleteOutlineMail(deleteList []int32) {
|
||||
sqlStr := "DELETE FROM system_mail_info WHERE mail_id = ?"
|
||||
for i := 0; i < len(deleteList); i++ {
|
||||
|
||||
result, err := db.SqlDb.Exec(sqlStr, deleteList[i])
|
||||
if err != nil {
|
||||
fmt.Printf("exec failed, err:%v\n", err)
|
||||
return
|
||||
}
|
||||
affectedRows, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
fmt.Printf("get affected failed, err:%v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("delete data success, affected rows:%d\n", affectedRows)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PlayerEmailData) IntervalGetUnsendMails() {
|
||||
sqlStr := "SELECT * FROM system_mail_info WHERE dwUin = ? AND state = ?"
|
||||
SqlStructs := []db.SqlEmailStruct{}
|
||||
if err := db.SqlDb.Select(&SqlStructs, sqlStr, p.M_Player.M_DwUin, 0); err != nil {
|
||||
|
||||
} else {
|
||||
for i := 0; i < len(SqlStructs); i++ {
|
||||
SqlStructs[i].Status = 1
|
||||
db.FormatAllMemUpdateDb(&SqlStructs[i], "system_mail_info", "mail_id")
|
||||
}
|
||||
if len(SqlStructs) > 0 {
|
||||
p.NotifyNewBriefEmailData(SqlStructs)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PlayerEmailData) NotifyNewBriefEmailData(SqlStructs []db.SqlEmailStruct) {
|
||||
notify := &msg.NotifyNewBriefEmailData{}
|
||||
notify.DwUin = p.M_Player.M_DwUin
|
||||
notify.MEmailList = []*msg.BriefEmailStruct{}
|
||||
|
||||
p.SqlStructs = append(p.SqlStructs, SqlStructs...)
|
||||
|
||||
for i := 0; i < len(SqlStructs); i++ {
|
||||
st := &msg.BriefEmailStruct{}
|
||||
st.EmailId = SqlStructs[i].EmailId
|
||||
st.Sender = SqlStructs[i].Sender
|
||||
st.Title = SqlStructs[i].Title
|
||||
st.CurrencyCount = SqlStructs[i].CurrencyCount
|
||||
st.CurrencyInfo = SqlStructs[i].CurrencyInfo
|
||||
st.ItemCount = SqlStructs[i].ItemCount
|
||||
st.ItemInfo = SqlStructs[i].ItemInfo
|
||||
st.SendTime = SqlStructs[i].SendTime
|
||||
st.Status = 1
|
||||
st.Type = SqlStructs[i].Type
|
||||
SqlStructs[i].Status = 1
|
||||
notify.MEmailList = append(notify.MEmailList, st)
|
||||
}
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(notify)
|
||||
G_getGameLogic().PackResInfo(agent, "NotifyNewBriefEmailData", data)
|
||||
}
|
||||
|
||||
func (p *PlayerEmailData) ResBriefEmailData() {
|
||||
res := &msg.ResBriefEmailData{}
|
||||
res.DwUin = p.M_Player.M_DwUin
|
||||
res.MEmailList = []*msg.BriefEmailStruct{}
|
||||
for i := 0; i < len(p.SqlStructs); i++ {
|
||||
st := &msg.BriefEmailStruct{}
|
||||
st.EmailId = p.SqlStructs[i].EmailId
|
||||
st.Sender = p.SqlStructs[i].Sender
|
||||
st.Title = p.SqlStructs[i].Title
|
||||
st.CurrencyCount = p.SqlStructs[i].CurrencyCount
|
||||
st.CurrencyInfo = p.SqlStructs[i].CurrencyInfo
|
||||
st.ItemCount = p.SqlStructs[i].ItemCount
|
||||
st.ItemInfo = p.SqlStructs[i].ItemInfo
|
||||
st.SendTime = p.SqlStructs[i].SendTime
|
||||
st.Status = p.SqlStructs[i].Status
|
||||
st.Type = p.SqlStructs[i].Type
|
||||
res.MEmailList = append(res.MEmailList, st)
|
||||
}
|
||||
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResBriefEmailData", data)
|
||||
}
|
||||
|
||||
func (p *PlayerEmailData) FindSqlStructByMailId(mailId int32) *db.SqlEmailStruct {
|
||||
for i := 0; i < len(p.SqlStructs); i++ {
|
||||
if p.SqlStructs[i].EmailId == mailId {
|
||||
return &p.SqlStructs[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PlayerEmailData) DeleteSqlStructByMailId(mailId int32) *db.SqlEmailStruct {
|
||||
var temp *db.SqlEmailStruct = nil
|
||||
var list []db.SqlEmailStruct
|
||||
for i := 0; i < len(p.SqlStructs); i++ {
|
||||
if p.SqlStructs[i].EmailId == mailId {
|
||||
temp = &p.SqlStructs[i]
|
||||
if i > 0 {
|
||||
list = append(list, p.SqlStructs[:i]...)
|
||||
}
|
||||
if i < len(p.SqlStructs)-1 {
|
||||
list = append(list, p.SqlStructs[i+1:]...)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
p.SqlStructs = list
|
||||
|
||||
return temp
|
||||
}
|
||||
|
||||
func (p *PlayerEmailData) ResDetailEmailData(buf []byte) {
|
||||
res := &msg.ResDetailEmailData{}
|
||||
req := &msg.ReqDetailEmailData{}
|
||||
proto.Unmarshal(buf, req)
|
||||
|
||||
st := p.FindSqlStructByMailId(req.EmailId)
|
||||
if st != nil {
|
||||
res.ResultCode = 0
|
||||
res.Content = st.Content
|
||||
res.EmailId = req.EmailId
|
||||
res.RewardType = st.RewardType
|
||||
res.RewardId = st.RewardId
|
||||
res.RewardCount = st.RewardCount
|
||||
res.LinkUrl = st.LinkUrl
|
||||
if st.Type == 0 {
|
||||
st.Status = 2
|
||||
st.RecvTime = int32(time.Now().Unix())
|
||||
db.FormatAllMemUpdateDb(st, "system_mail_info", "mail_id")
|
||||
}
|
||||
|
||||
} else {
|
||||
res.ResultCode = MergeConst.Protocol_Email_Find_Fail
|
||||
}
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResDetailEmailData", data)
|
||||
}
|
||||
func (p *PlayerEmailData) ResDeleteEmail(buf []byte) {
|
||||
res := &msg.ResDeleteEmail{}
|
||||
req := &msg.ReqDeleteEmail{}
|
||||
proto.Unmarshal(buf, req)
|
||||
|
||||
if p.DeleteSqlStructByMailId(req.EmailId) != nil {
|
||||
res.EmailId = req.EmailId
|
||||
res.ResultCode = 0
|
||||
deleteList := []int32{req.EmailId}
|
||||
p.DeleteOutlineMail(deleteList)
|
||||
|
||||
} else {
|
||||
res.ResultCode = MergeConst.Protocol_Email_Find_Fail
|
||||
}
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResDeleteEmail", data)
|
||||
}
|
||||
|
||||
func (p *PlayerEmailData) ResGetEmailReward(buf []byte) {
|
||||
res := &msg.ResGetEmailReward{}
|
||||
req := &msg.ReqGetEmailReward{}
|
||||
proto.Unmarshal(buf, req)
|
||||
|
||||
st := p.FindSqlStructByMailId(req.EmailId)
|
||||
if st != nil {
|
||||
res.ResultCode = 0
|
||||
res.EmailId = req.EmailId
|
||||
res.RewardType = st.RewardType
|
||||
res.RewardId = st.RewardId
|
||||
res.RewardCount = st.RewardCount
|
||||
st.Status = 2
|
||||
st.RecvTime = int32(time.Now().Unix())
|
||||
db.FormatAllMemUpdateDb(st, "system_mail_info", "mail_id")
|
||||
///发送奖励
|
||||
} else {
|
||||
res.ResultCode = MergeConst.Protocol_Email_Find_Fail
|
||||
}
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResGetEmailReward", data)
|
||||
}
|
||||
func (p *PlayerEmailData) ClearData() bool {
|
||||
p.SaveDataFromDB("")
|
||||
p.Mcron.Remove(p.ZeroCronID)
|
||||
p.Mcron.Stop()
|
||||
return true
|
||||
}
|
||||
129
src/server/game/PlayerEmitUnlockMod.go
Normal file
129
src/server/game/PlayerEmitUnlockMod.go
Normal file
@ -0,0 +1,129 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"server/GoUtil"
|
||||
"server/MergeConst"
|
||||
"server/db"
|
||||
"server/msg"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type PlayerEmitUnlockData struct {
|
||||
*PlayerData
|
||||
Data msg.ResPlayerEmitUnlockData
|
||||
}
|
||||
|
||||
func (p *PlayerEmitUnlockData) LoadDataFromDB(dwUin interface{}) bool {
|
||||
sqlStr := "SELECT * FROM t_player_emit_unlock WHERE dwUin = ?"
|
||||
sqlStruck := db.SqlEmitUnlockStruct{RenewTime: 0}
|
||||
p.Data.MEmitUnlockData = make(map[int32]int32)
|
||||
|
||||
if err := db.SqlDb.Get(&sqlStruck, sqlStr, dwUin.(int32)); err != nil {
|
||||
fmt.Printf("get data failed, err:%v\n", err)
|
||||
p.IsHaveDataDb = false
|
||||
} else {
|
||||
p.IsHaveDataDb = true
|
||||
}
|
||||
if sqlStruck.Value != "" {
|
||||
arr := strings.Split(sqlStruck.Value, "_")
|
||||
for i := 0; i < len(arr); i++ {
|
||||
ss := strings.Split(arr[i], ",")
|
||||
id, err := strconv.ParseInt(ss[0], 10, 32)
|
||||
cnt, _ := strconv.ParseInt(ss[1], 10, 32)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
p.Data.MEmitUnlockData[int32(id)] = int32(cnt)
|
||||
}
|
||||
}
|
||||
p.Data.DwUin = dwUin.(int32)
|
||||
p.Data.RenewTime = sqlStruck.RenewTime
|
||||
|
||||
p.Reconnect(false)
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerEmitUnlockData) Reconnect(b bool) {
|
||||
if G_GameLogicPtr.DailyTaskTimestamp > (int64)(p.Data.RenewTime) {
|
||||
p.Data.RenewTime = int32(G_GameLogicPtr.DailyTaskTimestamp)
|
||||
for k := range p.Data.MEmitUnlockData {
|
||||
p.Data.MEmitUnlockData[k] = 0
|
||||
}
|
||||
if b {
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(&p.Data)
|
||||
G_getGameLogic().PackResInfo(agent, "NotifyDailyRenewEmitUnlock", data)
|
||||
}
|
||||
}
|
||||
GoUtil.RegisterEvent(MergeConst.Notify_Daily_Renew, p.NotifyDailyRenewEmitUnlock, p)
|
||||
}
|
||||
|
||||
func (p *PlayerEmitUnlockData) GetUnlockCntByID(id int32) int32 {
|
||||
cnt, ok := p.Data.MEmitUnlockData[id]
|
||||
if ok {
|
||||
return cnt
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (p *PlayerEmitUnlockData) ClearData() bool {
|
||||
p.SaveDataFromDB("")
|
||||
GoUtil.RemoveEvent(MergeConst.Notify_Daily_Renew, p.NotifyDailyRenewEmitUnlock, p)
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerEmitUnlockData) SaveDataFromDB(Key interface{}) bool {
|
||||
var strarr []string
|
||||
for k, v := range p.Data.MEmitUnlockData {
|
||||
str := fmt.Sprintf("%d,%d", k, v)
|
||||
strarr = append(strarr, str)
|
||||
}
|
||||
str_concat := strings.Join(strarr, "_")
|
||||
// sqlStr := "UPDATE user SET age = ?, degree = ? WHERE id = ?"
|
||||
// result, err := SqlDb.Exec(sqlStr, 22, 10, 4)
|
||||
sqlStruck := db.SqlEmitUnlockStruct{}
|
||||
sqlStruck.DwUin = p.M_Player.M_DwUin
|
||||
sqlStruck.Value = str_concat
|
||||
if p.IsHaveDataDb {
|
||||
db.FormatAllMemUpdateDb(&sqlStruck, "t_player_emit_unlock", "dwUin")
|
||||
} else {
|
||||
db.FormatAllMemInsertDb(&sqlStruck, "t_player_emit_unlock")
|
||||
}
|
||||
p.IsHaveDataDb = true
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerEmitUnlockData) ResPlayerEmitUnlockData(player *Player) {
|
||||
if player != p.M_Player {
|
||||
return
|
||||
}
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(&p.Data)
|
||||
G_getGameLogic().PackResInfo(agent, "ResPlayerEmitUnlockData", data)
|
||||
}
|
||||
|
||||
func (p *PlayerEmitUnlockData) NotifyDailyRenewEmitUnlock(param []interface{}) {
|
||||
p.Data.RenewTime = int32(param[0].(int64))
|
||||
for k := range p.Data.MEmitUnlockData {
|
||||
p.Data.MEmitUnlockData[k] = 0
|
||||
}
|
||||
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(&p.Data)
|
||||
G_getGameLogic().PackResInfo(agent, "NotifyDailyRenewEmitUnlock", data)
|
||||
// p.SaveDataFromDB("")
|
||||
}
|
||||
|
||||
func (p *PlayerEmitUnlockData) UpdatePlayerEmitUnlockData(buf []byte) {
|
||||
|
||||
update := &msg.UpdatePlayerEmitUnlockData{}
|
||||
proto.Unmarshal(buf, update)
|
||||
|
||||
p.Data.MEmitUnlockData = update.MEmitUnlockData
|
||||
|
||||
p.SaveDataFromDB("")
|
||||
}
|
||||
1527
src/server/game/PlayerFriendData.go
Normal file
1527
src/server/game/PlayerFriendData.go
Normal file
File diff suppressed because it is too large
Load Diff
291
src/server/game/PlayerFunc.go
Normal file
291
src/server/game/PlayerFunc.go
Normal file
@ -0,0 +1,291 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"server/GoUtil"
|
||||
"server/MergeConst"
|
||||
mergeCluster "server/cluster"
|
||||
chargeCfg "server/conf/charge"
|
||||
"server/db"
|
||||
"server/game/mod/card"
|
||||
"server/game/mod/msg"
|
||||
proto "server/msg"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// 处理玩家异步请求
|
||||
func HandleMsg(p *Player, m *msg.Msg) {
|
||||
p.lock.Lock() //加锁
|
||||
backup := p.BackUp() // 备份当前的 Player 值
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Debug("Handle msg uid : %d, msg : %v, fatal : %s", p.M_DwUin, m, r)
|
||||
p.Recover(backup) //还原Player的数据
|
||||
}
|
||||
p.lock.Unlock() //解锁
|
||||
}()
|
||||
p.args = make(map[string]interface{})
|
||||
err := handle(p, m)
|
||||
if err != nil {
|
||||
log.Debug("uid : %d, err : %s", p.M_DwUin, err)
|
||||
p.Recover(backup) //还原Player的数据
|
||||
return
|
||||
}
|
||||
p.ProcessTrigger()
|
||||
p.SendClientRes()
|
||||
}
|
||||
|
||||
// 消息处理
|
||||
func handle(p *Player, m *msg.Msg) error {
|
||||
switch m.Type {
|
||||
case msg.HANDLE_TYPE_DEL, msg.HANDLE_TYPE_APPLY, msg.HADNLE_TYPE_AGREE, msg.HANDLE_TYPE_REQ_CARD:
|
||||
return HandleFriendMsg(p, m)
|
||||
case msg.HANDLE_TYPE_AGREE_CARD: // A收到B同意卡牌
|
||||
CardInfo := m.Extra.(*card.CardInfo)
|
||||
CardMod := p.PlayMod.getCardMod()
|
||||
CardMod.AddCard(CardInfo.CardId)
|
||||
OtherUid, err := CardMod.DelRequestCard(CardInfo.BUid)
|
||||
if err != nil { // 同意失败,请求已失效
|
||||
msg := &msg.Msg{Type: msg.HANDLE_TYPE_AGREE_CARD_FAIL, From: CardInfo.AUid, End: CardInfo.EndTime}
|
||||
FriendMgrSend(msg)
|
||||
return nil
|
||||
}
|
||||
for _, v := range OtherUid { // 通知好友请求已结束
|
||||
msg := &msg.Msg{Type: msg.HANDLE_TYPE_REG_CARD_FINISH, From: v}
|
||||
FriendMgrSend(msg)
|
||||
}
|
||||
p.PlayMod.save()
|
||||
p.PushClientRes(CardMod.BackData())
|
||||
case msg.HANDLE_TYPE_REG_CARD_REFUSE: // A收到B拒绝索要卡牌
|
||||
CardInfo := m.Extra.(*card.CardInfo)
|
||||
CardMod := p.PlayMod.getCardMod()
|
||||
CardMod.DelRequestCard(CardInfo.BUid)
|
||||
p.PlayMod.save()
|
||||
p.PushClientRes(CardMod.BackData())
|
||||
case msg.HANDLE_TYPE_EX_CARD: // B收到A置换卡牌
|
||||
FriendMod := p.PlayMod.getFriendMod()
|
||||
CardInfo := m.Extra.(*card.CardInfo)
|
||||
if CardInfo.Type == card.TYPE_GIVE { // A卡牌白送
|
||||
CardMod := p.PlayMod.getCardMod()
|
||||
CardMod.AddCard(CardInfo.CardId)
|
||||
p.PushClientRes(CardMod.BackData())
|
||||
} else {
|
||||
FriendMod.SetCardExchange(CardInfo)
|
||||
}
|
||||
p.PlayMod.save()
|
||||
FriendBackData(p)
|
||||
case msg.HANDLE_TYPE_SELECT_EX_CARD: // A收到B选择卡牌进行置换
|
||||
FriendMod := p.PlayMod.getFriendMod()
|
||||
CardInfo := m.Extra.(*card.CardInfo)
|
||||
FriendMod.CardSelectExchange(CardInfo)
|
||||
p.PlayMod.save()
|
||||
FriendBackData(p)
|
||||
case msg.HANDLE_TYPE_ARGREE_EX_CARD: // B收到A同意置换卡牌
|
||||
CardMod := p.PlayMod.getCardMod()
|
||||
CardInfo := m.Extra.(*card.CardInfo)
|
||||
CardMod.AddCard(CardInfo.CardId)
|
||||
FriendMod := p.PlayMod.getFriendMod()
|
||||
FriendMod.DelCardExchange(CardInfo.AUid)
|
||||
p.PlayMod.save()
|
||||
p.PushClientRes(CardMod.BackData())
|
||||
case msg.HANDLE_TYPE_REFUSE_SELECT_CARD: // A收到B拒绝置换卡牌
|
||||
CardMod := p.PlayMod.getCardMod()
|
||||
CardInfo := m.Extra.(*card.CardInfo)
|
||||
CardMod.AddExTimes()
|
||||
CardMod.AddCard(CardInfo.CardId)
|
||||
CardMod.DelExCard(CardInfo)
|
||||
p.PlayMod.save()
|
||||
p.PushClientRes(CardMod.BackData())
|
||||
case msg.HANDLE_TYPE_REFUSE_EX_CARD: // B收到A拒绝置换卡牌
|
||||
CardMod := p.PlayMod.getCardMod()
|
||||
CardInfo := m.Extra.(*card.CardInfo)
|
||||
CardMod.AddCard(CardInfo.ExId)
|
||||
FriendMod := p.PlayMod.getFriendMod()
|
||||
FriendMod.DelCardExchange(CardInfo.AUid)
|
||||
p.PlayMod.save()
|
||||
p.PushClientRes(CardMod.BackData())
|
||||
case msg.HANDLE_TYPE_MAIL: // 邮件操作
|
||||
MailMod := p.PlayMod.getMailMod()
|
||||
if m.Extra == nil {
|
||||
return nil
|
||||
}
|
||||
mail := m.Extra.(*ServerMail)
|
||||
Now := GoUtil.Now()
|
||||
if mail.Mail_type == 1 {
|
||||
if mail.Start_time > 0 && mail.Start_time > Now {
|
||||
return nil
|
||||
}
|
||||
if mail.End_time > 0 && mail.End_time < Now {
|
||||
return nil
|
||||
}
|
||||
|
||||
MailMod.Send(mail.Title, mail.Content, mail.Items)
|
||||
} else if mail.Mail_type == 2 {
|
||||
if GoUtil.InArray(int(p.M_DwUin), mail.To_uids) {
|
||||
MailMod.Send(mail.Title, mail.Content, mail.Items)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理系统请求
|
||||
func HandleServerMsg(p *Player, msg *msg.Msg) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理好友请求
|
||||
func HandleFriendMsg(p *Player, msg *msg.Msg) error {
|
||||
FriendMod := p.PlayMod.getFriendMod()
|
||||
FriendMod.HandleMsg(msg)
|
||||
FriendBackData(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 同步好友请求
|
||||
func SyncFriendMsg(p *Player) {
|
||||
MsgList := G_GameLogicPtr.FriendMgrCall(&msg.Msg{Type: msg.HANDLE_TYPE_SYNC, From: int(p.M_DwUin)})
|
||||
if MsgList == nil {
|
||||
return
|
||||
}
|
||||
ml := MsgList.([]*msg.Msg)
|
||||
if len(ml) == 0 {
|
||||
return
|
||||
}
|
||||
sort.Slice(ml, func(i, j int) bool {
|
||||
return ml[i].SendT < ml[j].SendT
|
||||
})
|
||||
for _, v := range ml {
|
||||
handle(p, v)
|
||||
}
|
||||
p.PlayMod.save()
|
||||
FriendBackData(p)
|
||||
}
|
||||
|
||||
// 返回好友信息
|
||||
func FriendBackData(p *Player) {
|
||||
FriendMod := p.PlayMod.getFriendMod()
|
||||
var fl []*proto.ResPlayerSimple
|
||||
var al []*proto.ResPlayerSimple
|
||||
var log []*proto.ResFriendLog
|
||||
var msgList []*proto.ResFriendCard
|
||||
for k := range FriendMod.FriendList {
|
||||
ps := G_GameLogicPtr.GetSimplePlayerByUid(k)
|
||||
if ps != nil {
|
||||
fl = append(fl, &proto.ResPlayerSimple{
|
||||
Uid: int32(ps.Uid),
|
||||
Name: ps.Name,
|
||||
Level: int32(ps.Level),
|
||||
Avatar: int32(ps.Avatar),
|
||||
Face: int32(ps.Face),
|
||||
})
|
||||
}
|
||||
}
|
||||
for k := range FriendMod.Apply {
|
||||
ps := G_GameLogicPtr.GetSimplePlayerByUid(k)
|
||||
if ps != nil {
|
||||
al = append(al, &proto.ResPlayerSimple{
|
||||
Uid: int32(ps.Uid),
|
||||
Name: ps.Name,
|
||||
Level: int32(ps.Level),
|
||||
Avatar: int32(ps.Avatar),
|
||||
Face: int32(ps.Face),
|
||||
})
|
||||
}
|
||||
}
|
||||
for _, v := range FriendMod.Log {
|
||||
ps := G_GameLogicPtr.GetSimplePlayerByUid(v.Uid)
|
||||
log = append(log, &proto.ResFriendLog{
|
||||
Uid: int32(v.Uid),
|
||||
Name: ps.Name,
|
||||
Face: int32(ps.Face),
|
||||
Avatar: int32(ps.Avatar),
|
||||
Level: int32(ps.Level),
|
||||
Type: int32(v.Type),
|
||||
Time: int32(v.Time),
|
||||
})
|
||||
}
|
||||
for _, v := range FriendMod.ApplyCard {
|
||||
ps := G_GameLogicPtr.GetSimplePlayerByUid(v.BUid)
|
||||
msgList = append(msgList, &proto.ResFriendCard{
|
||||
Uid: int32(v.AUid),
|
||||
Name: ps.Name,
|
||||
Face: int32(ps.Face),
|
||||
Avatar: int32(ps.Avatar),
|
||||
Level: int32(ps.Level),
|
||||
CardId: int32(v.CardId),
|
||||
Type: int32(v.Type),
|
||||
Time: int32(v.EndTime),
|
||||
})
|
||||
}
|
||||
for _, v := range FriendMod.ExchangeCard {
|
||||
ps := G_GameLogicPtr.GetSimplePlayerByUid(v.BUid)
|
||||
msgList = append(msgList, &proto.ResFriendCard{
|
||||
Uid: int32(v.AUid),
|
||||
Name: ps.Name,
|
||||
Face: int32(ps.Face),
|
||||
Avatar: int32(ps.Avatar),
|
||||
Level: int32(ps.Level),
|
||||
Type: int32(v.Type),
|
||||
CardId: int32(v.CardId),
|
||||
Time: int32(v.EndTime),
|
||||
})
|
||||
|
||||
}
|
||||
p.PushClientRes(&proto.ResFriendList{
|
||||
FriendList: fl,
|
||||
ApplyList: al,
|
||||
MsgList: msgList,
|
||||
LogList: log,
|
||||
})
|
||||
}
|
||||
|
||||
// 发送消息给玩家
|
||||
func ClusterSendMsg(ServerId int, m *msg.Msg) {
|
||||
mergeCluster.SendServerMsg(m, ServerId)
|
||||
}
|
||||
|
||||
// 创建订单
|
||||
func CreateOrderSn(p *Player, ChargeId int, Platform, Channel string) (string, error) {
|
||||
Uid := int(p.M_DwUin)
|
||||
OrderSn := GoUtil.CreateOrderSn(Uid)
|
||||
|
||||
Price, Currency := chargeCfg.GetChargeInfo(ChargeId)
|
||||
err := db.CreateOrderSn(Uid, ChargeId, OrderSn, Platform, Channel, Price, Currency)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return OrderSn, nil
|
||||
}
|
||||
|
||||
func GoogleVerify(p *Player, OrderSn, PayOrderSn string, Status int) (*db.SqlChargeOrderStruct, error) {
|
||||
Order, err := db.GetPlayerChargeData(OrderSn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if Order.PayStatus != MergeConst.ORDER_STATUS_IDLE {
|
||||
return nil, fmt.Errorf("订单已经支付")
|
||||
}
|
||||
// TODO 验证订单
|
||||
Order.PayTime = GoUtil.Now()
|
||||
Order.PayChannelOrderId = PayOrderSn
|
||||
Order.PayStatus = Status
|
||||
err = db.UpdatePlayerChargeData(Order)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Order, nil
|
||||
}
|
||||
|
||||
// func PlayerFriendRecommend(p *Player) {
|
||||
// FriendMod := p.PlayMod.getFriendMod()
|
||||
// n := 0
|
||||
// if len(FriendMod.FriendList) < 10 {
|
||||
// n = 3
|
||||
// } else {
|
||||
// n = int(3 - float64(len(FriendMod.FriendList))*0.1)
|
||||
// }
|
||||
|
||||
// UserList := G_GameLogicPtr.RankMgr.getRank(RANK_TYPE_USER)
|
||||
// }
|
||||
97
src/server/game/PlayerGiftMod.go
Normal file
97
src/server/game/PlayerGiftMod.go
Normal file
@ -0,0 +1,97 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"server/db"
|
||||
"server/msg"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type PlayerGiftData struct {
|
||||
*PlayerData
|
||||
Data msg.ResPlayerGiftData
|
||||
}
|
||||
|
||||
func (p *PlayerGiftData) LoadDataFromDB(dwUin interface{}) bool {
|
||||
|
||||
sqlStr := "SELECT * FROM t_player_gift_data WHERE dwUin = ?"
|
||||
sqlStruck := db.SqlGiftStruct{}
|
||||
p.Data.MGiftData = make(map[int32]int32)
|
||||
if err := db.SqlDb.Get(&sqlStruck, sqlStr, dwUin.(int32)); err != nil {
|
||||
fmt.Printf("get data failed, err:%v\n", err)
|
||||
p.IsHaveDataDb = false
|
||||
} else {
|
||||
p.IsHaveDataDb = true
|
||||
}
|
||||
if sqlStruck.MGiftData != "" {
|
||||
arr := strings.Split(sqlStruck.MGiftData, "_")
|
||||
|
||||
for i := 0; i < len(arr); i++ {
|
||||
ss := strings.Split(arr[i], ",")
|
||||
id, err := strconv.ParseInt(ss[1], 10, 32)
|
||||
key, _ := strconv.ParseInt(ss[0], 10, 32)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
p.Data.MGiftData[int32(key)] = int32(id)
|
||||
}
|
||||
}
|
||||
|
||||
p.Data.DwUin = dwUin.(int32)
|
||||
p.Reconnect(false)
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerGiftData) Reconnect(b bool) {
|
||||
|
||||
}
|
||||
|
||||
func (p *PlayerGiftData) SaveDataFromDB(Key interface{}) bool {
|
||||
var strarr []string
|
||||
for k, v := range p.Data.MGiftData {
|
||||
str := fmt.Sprintf("%d,%d", k, v)
|
||||
strarr = append(strarr, str)
|
||||
}
|
||||
str_concat := strings.Join(strarr, "_")
|
||||
|
||||
sqlStruck := db.SqlGiftStruct{}
|
||||
sqlStruck.DwUin = p.M_Player.M_DwUin
|
||||
sqlStruck.MGiftData = str_concat
|
||||
if p.IsHaveDataDb {
|
||||
db.FormatAllMemUpdateDb(&sqlStruck, "t_player_gift_data", "dwUin")
|
||||
} else {
|
||||
db.FormatAllMemInsertDb(&sqlStruck, "t_player_gift_data")
|
||||
}
|
||||
p.IsHaveDataDb = true
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerGiftData) ResPlayerGiftData(player *Player) {
|
||||
if player != p.M_Player {
|
||||
return
|
||||
}
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(&p.Data)
|
||||
G_getGameLogic().PackResInfo(agent, "ResPlayerGiftData", data)
|
||||
}
|
||||
|
||||
func (p *PlayerGiftData) UpdatePlayerGiftData(buf []byte) {
|
||||
|
||||
update := &msg.UpdatePlayerGiftData{}
|
||||
proto.Unmarshal(buf, update)
|
||||
|
||||
p.Data.MGiftData = update.MGiftData
|
||||
|
||||
p.SaveDataFromDB("")
|
||||
}
|
||||
|
||||
func (p *PlayerGiftData) ClearData() bool {
|
||||
p.SaveDataFromDB("")
|
||||
|
||||
return true
|
||||
}
|
||||
1279
src/server/game/PlayerLimitEventData.go
Normal file
1279
src/server/game/PlayerLimitEventData.go
Normal file
File diff suppressed because it is too large
Load Diff
266
src/server/game/PlayerMod.go
Normal file
266
src/server/game/PlayerMod.go
Normal file
@ -0,0 +1,266 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"server/db"
|
||||
"server/game/mod/activity"
|
||||
"server/game/mod/avatar"
|
||||
"server/game/mod/base"
|
||||
"server/game/mod/card"
|
||||
"server/game/mod/champship"
|
||||
"server/game/mod/charge"
|
||||
"server/game/mod/chess"
|
||||
"server/game/mod/dailyTask"
|
||||
"server/game/mod/decorate"
|
||||
"server/game/mod/endless"
|
||||
"server/game/mod/face"
|
||||
"server/game/mod/friend"
|
||||
"server/game/mod/guild"
|
||||
"server/game/mod/handbook"
|
||||
"server/game/mod/limitedTimeEvent"
|
||||
"server/game/mod/mail"
|
||||
"server/game/mod/order"
|
||||
"server/game/mod/piggyBank"
|
||||
"server/game/mod/sevenLogin"
|
||||
Var "server/game/mod/var"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"time"
|
||||
)
|
||||
|
||||
type PlayerModData struct {
|
||||
*PlayerData
|
||||
Data db.SqlModStruct
|
||||
ModList PlayerModList
|
||||
}
|
||||
|
||||
// PlayerModList 玩家模块列表
|
||||
type PlayerModList struct {
|
||||
Base base.Base `json:"base"`
|
||||
Chess chess.ChessBorad `json:"chess"`
|
||||
Handbook handbook.Handbook `json:"handbook"`
|
||||
Order order.OrderMod `json:"order"`
|
||||
Decorate decorate.Decorate `json:"decorate"`
|
||||
Card card.CardMod `json:"card"`
|
||||
Var Var.Var `json:"var"`
|
||||
Guild guild.Guild `json:"guild"`
|
||||
DailyTask dailyTask.DailyTaskMod `json:"dailyTask"`
|
||||
Face face.FaceMod `json:"face"`
|
||||
Avatar avatar.AvatarMod `json:"avatar"`
|
||||
SevenLogin sevenLogin.SevenLoginMod `json:"sevenLogin"`
|
||||
Activity activity.ActivityMod `json:"activity"`
|
||||
LimitedTimeEvent limitedTimeEvent.LimitedTimeEventMod `json:"limitedTimeEvent"`
|
||||
Friend friend.FriendMod `json:"friend"`
|
||||
Mail mail.MailMod `json:"mail"`
|
||||
Charge charge.ChargeMod `json:"charge"`
|
||||
Endless endless.EndlessMod `json:"endless"`
|
||||
PiggyBank piggyBank.PiggyBankMod `json:"piggyBank"`
|
||||
Champship champship.ChampshipMod `json:"champship"`
|
||||
}
|
||||
|
||||
func (p *PlayerModData) LoadDataFromDB(dwUin interface{}) bool {
|
||||
sqlStr := "SELECT * FROM t_player_mod WHERE dwUin = ?"
|
||||
p.Data = db.SqlModStruct{}
|
||||
if err := db.SqlDb.Get(&p.Data, sqlStr, dwUin.(int32)); err != nil {
|
||||
fmt.Printf("get data failed, err:%v\n", err)
|
||||
p.IsHaveDataDb = false
|
||||
} else {
|
||||
p.IsHaveDataDb = true
|
||||
}
|
||||
p.Data.DwUin = dwUin.(int32)
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerModData) ClearData() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerModData) SaveDataFromDB(Key interface{}) bool {
|
||||
//序列化数据
|
||||
db.FormatAllMemUpdateDb(&p.Data, "t_player_mod", "dwUin")
|
||||
p.IsHaveDataDb = true
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerModData) ReqModData(buf []byte) {
|
||||
|
||||
}
|
||||
|
||||
// 推送基础数据
|
||||
func (p *PlayerModData) Reconnect(b bool) []byte {
|
||||
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
func (p *PlayerModData) InitMod() bool {
|
||||
playerModList := PlayerModList{}
|
||||
buf := bytes.NewBuffer(p.Data.ModData)
|
||||
decoder := gob.NewDecoder(buf)
|
||||
err := decoder.Decode(&playerModList)
|
||||
// err := json.Unmarshal([]byte(p.Data.ModData), &playerModList)
|
||||
if err != nil {
|
||||
fmt.Printf("playmod get data failed, err:%v\n", err)
|
||||
}
|
||||
p.ModList = playerModList
|
||||
is_update := false
|
||||
// 初始化基础模块
|
||||
if p.ModList.Base == (base.Base{}) {
|
||||
var baseMod base.Base
|
||||
baseMod.InitData()
|
||||
p.ModList.Base = baseMod
|
||||
is_update = true
|
||||
}
|
||||
|
||||
// 初始化棋盘模块
|
||||
|
||||
if p.ModList.Chess.IsEmpty() {
|
||||
var chessMod chess.ChessBorad
|
||||
chessMod.InitData()
|
||||
p.ModList.Chess = chessMod
|
||||
is_update = true
|
||||
}
|
||||
p.ModList.Handbook.InitData()
|
||||
p.ModList.Order.InitData()
|
||||
p.ModList.Decorate.InitData()
|
||||
p.ModList.Card.InitData()
|
||||
p.ModList.Var.InitData()
|
||||
p.ModList.Guild.InitData()
|
||||
p.ModList.DailyTask.InitData()
|
||||
p.ModList.Face.InitData()
|
||||
p.ModList.Avatar.InitData()
|
||||
p.ModList.Base.InitData()
|
||||
p.ModList.SevenLogin.InitData()
|
||||
p.ModList.Activity.InitData()
|
||||
p.ModList.LimitedTimeEvent.InitData()
|
||||
p.ModList.Friend.InitData()
|
||||
p.ModList.Mail.InitData()
|
||||
p.ModList.Charge.InitData()
|
||||
p.ModList.Endless.InitData()
|
||||
|
||||
return is_update
|
||||
}
|
||||
|
||||
type PlayerMod struct {
|
||||
mod_list PlayerModList
|
||||
is_update bool
|
||||
}
|
||||
|
||||
func (p *PlayerMod) save() {
|
||||
p.is_update = true
|
||||
}
|
||||
|
||||
func (p *PlayerMod) ClearData(player *Player) {
|
||||
|
||||
if p.is_update {
|
||||
//序列化模块
|
||||
var buf bytes.Buffer
|
||||
encode := gob.NewEncoder(&buf)
|
||||
err := encode.Encode(p.mod_list)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
log.Debug("uid: %d, ClearData, playmod", player.M_DwUin)
|
||||
modData := &db.SqlModStruct{
|
||||
DwUin: player.M_DwUin,
|
||||
ModData: buf.Bytes(),
|
||||
UpdataTime: int32(time.Now().Unix()),
|
||||
}
|
||||
|
||||
db.SavePlayerModData(modData)
|
||||
p.is_update = false
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PlayerMod) BackUp(B *PlayerBackUp) {
|
||||
modString, _ := json.Marshal(p.mod_list)
|
||||
B.PlayMod = modString
|
||||
}
|
||||
|
||||
func (p *PlayerMod) Recover(B *PlayerBackUp) {
|
||||
if len(B.PlayMod) > 0 {
|
||||
json.Unmarshal(B.PlayMod, &p.mod_list)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getChessMod() *chess.ChessBorad {
|
||||
return &p.mod_list.Chess
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getBaseMod() *base.Base {
|
||||
return &p.mod_list.Base
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getHandbookMod() *handbook.Handbook {
|
||||
return &p.mod_list.Handbook
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getOrderMod() *order.OrderMod {
|
||||
return &p.mod_list.Order
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getDecorateMod() *decorate.Decorate {
|
||||
return &p.mod_list.Decorate
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getCardMod() *card.CardMod {
|
||||
return &p.mod_list.Card
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getVarMod() *Var.Var {
|
||||
return &p.mod_list.Var
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getGuildMod() *guild.Guild {
|
||||
return &p.mod_list.Guild
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getDailyTaskMod() *dailyTask.DailyTaskMod {
|
||||
return &p.mod_list.DailyTask
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getFaceMod() *face.FaceMod {
|
||||
return &p.mod_list.Face
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getAvatarMod() *avatar.AvatarMod {
|
||||
return &p.mod_list.Avatar
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getSevenLoginMod() *sevenLogin.SevenLoginMod {
|
||||
return &p.mod_list.SevenLogin
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getActivityMod() *activity.ActivityMod {
|
||||
return &p.mod_list.Activity
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getLimitedTimeEventMod() *limitedTimeEvent.LimitedTimeEventMod {
|
||||
return &p.mod_list.LimitedTimeEvent
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getFriendMod() *friend.FriendMod {
|
||||
return &p.mod_list.Friend
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getMailMod() *mail.MailMod {
|
||||
return &p.mod_list.Mail
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getChargeMod() *charge.ChargeMod {
|
||||
return &p.mod_list.Charge
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getEndlessMod() *endless.EndlessMod {
|
||||
return &p.mod_list.Endless
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getPiggyBankMod() *piggyBank.PiggyBankMod {
|
||||
return &p.mod_list.PiggyBank
|
||||
}
|
||||
|
||||
func (p *PlayerMod) getChampshipMod() *champship.ChampshipMod {
|
||||
return &p.mod_list.Champship
|
||||
}
|
||||
169
src/server/game/PlayerPigData.go
Normal file
169
src/server/game/PlayerPigData.go
Normal file
@ -0,0 +1,169 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"server/MergeConst"
|
||||
"server/db"
|
||||
"server/msg"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type PlayerPigData struct {
|
||||
*PlayerData
|
||||
Data msg.ResPigDetailInfo
|
||||
}
|
||||
|
||||
func (p *PlayerPigData) LoadDataFromDB(dwUin interface{}) bool {
|
||||
|
||||
sqlStr := "SELECT * FROM t_player_piginfo WHERE dwUin = ?"
|
||||
sqlStruck := db.SqlPigDetailInfoStruct{}
|
||||
sqlStruck.PigId = 0
|
||||
if err := db.SqlDb.Get(&sqlStruck, sqlStr, dwUin.(int32)); err != nil {
|
||||
fmt.Printf("get data failed, err:%v\n", err)
|
||||
p.IsHaveDataDb = false
|
||||
} else {
|
||||
p.IsHaveDataDb = true
|
||||
}
|
||||
p.Data.CurDiamonds = sqlStruck.CurDiamonds
|
||||
p.Data.DwUin = p.M_Player.M_DwUin
|
||||
p.Data.PigId = sqlStruck.PigId
|
||||
p.Data.PigType = sqlStruck.PigType
|
||||
p.Data.StartSvrTime = sqlStruck.StartSvrTime
|
||||
p.Data.EndSvrTime = sqlStruck.EndSvrTime
|
||||
p.Data.CurGetLv = sqlStruck.CurGetLv
|
||||
p.Reconnect(false)
|
||||
|
||||
return true
|
||||
}
|
||||
func (p *PlayerPigData) Reconnect(b bool) {
|
||||
|
||||
}
|
||||
|
||||
func (p *PlayerPigData) DeleteLastPigData(pigid int32) {
|
||||
sqlStr := "DELETE FROM " + "t_player_piginfo" + " WHERE PigId = ?"
|
||||
|
||||
db.SqlDb.Exec(sqlStr, pigid)
|
||||
p.Data.PigId = 0
|
||||
}
|
||||
|
||||
func (p *PlayerPigData) ClearData() bool {
|
||||
p.SaveDataFromDB("")
|
||||
|
||||
return true
|
||||
}
|
||||
func (p *PlayerPigData) SaveDataFromDB(Key interface{}) bool {
|
||||
|
||||
sqlStruck := db.SqlPigDetailInfoStruct{}
|
||||
sqlStruck.DwUin = p.M_Player.M_DwUin
|
||||
sqlStruck.CurDiamonds = p.Data.CurDiamonds
|
||||
sqlStruck.CurGetLv = p.Data.CurGetLv
|
||||
sqlStruck.CurSvrTime = 0
|
||||
sqlStruck.EndSvrTime = p.Data.EndSvrTime
|
||||
sqlStruck.StartSvrTime = p.Data.StartSvrTime
|
||||
sqlStruck.PigId = p.Data.PigId
|
||||
sqlStruck.PigType = p.Data.PigType
|
||||
|
||||
if p.IsHaveDataDb {
|
||||
if p.Data.PigId != 0 {
|
||||
db.FormatAllMemUpdateDb(&sqlStruck, "t_player_piginfo", "PigId")
|
||||
}
|
||||
} else {
|
||||
if p.Data.PigId != 0 {
|
||||
db.FormatAllMemInsertDb(&sqlStruck, "t_player_piginfo")
|
||||
}
|
||||
}
|
||||
p.IsHaveDataDb = true
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerPigData) ResOpenNewPig(player *Player) {
|
||||
res := &msg.ResOpenNewPig{}
|
||||
st := &db.SqlPigDetailInfoStruct{}
|
||||
st.DwUin = player.M_DwUin
|
||||
st.StartSvrTime = (int32)(time.Now().Unix())
|
||||
st.EndSvrTime = st.StartSvrTime + MergeConst.G_Pig_Limite
|
||||
st.PigType = 1
|
||||
st.CurDiamonds = 0
|
||||
st.CurSvrTime = 0
|
||||
st.CurGetLv = 1
|
||||
|
||||
PigId, _ := db.FormatAllMemInsertDb(st, "t_player_piginfo")
|
||||
res.PigId = (int32)(PigId)
|
||||
|
||||
p.Data.CurDiamonds = st.CurDiamonds
|
||||
p.Data.DwUin = p.M_Player.M_DwUin
|
||||
p.Data.PigId = int32(PigId)
|
||||
p.Data.PigType = st.PigType
|
||||
p.Data.StartSvrTime = st.StartSvrTime
|
||||
p.Data.EndSvrTime = st.EndSvrTime
|
||||
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResOpenNewPig", data)
|
||||
}
|
||||
|
||||
func (p *PlayerPigData) ResPigDetailInfo(player *Player) {
|
||||
// res := &msg.ReqPigDetailInfo{}
|
||||
p.Data.CurSvrTime = int32(time.Now().Unix())
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(&p.Data)
|
||||
G_getGameLogic().PackResInfo(agent, "ResPigDetailInfo", data)
|
||||
}
|
||||
|
||||
func (p *PlayerPigData) UpdateFinishOrderDiamond(buf []byte) {
|
||||
|
||||
update := &msg.UpdateFinishOrderDiamond{}
|
||||
proto.Unmarshal(buf, update)
|
||||
|
||||
p.Data.CurDiamonds = update.CurDiamonds
|
||||
p.SaveDataFromDB("")
|
||||
}
|
||||
|
||||
func (p *PlayerPigData) ResGetPigReward(buf []byte) {
|
||||
|
||||
req := &msg.ReqGetPigReward{}
|
||||
proto.Unmarshal(buf, req)
|
||||
|
||||
res := &msg.ResGetPigReward{}
|
||||
res.PigId = req.PigId
|
||||
|
||||
if req.PigId != p.Data.PigId {
|
||||
res.ResultCode = MergeConst.Protocol_PigID_No_Exsit
|
||||
} else {
|
||||
res.ResultCode = 0
|
||||
p.Data.CurGetLv = p.Data.CurGetLv + 1
|
||||
res.CurGetLv = p.Data.CurGetLv
|
||||
}
|
||||
res.CurDiamonds = p.Data.CurDiamonds
|
||||
|
||||
if MergeConst.G_PigIsOne {
|
||||
p.DeleteLastPigData(req.PigId)
|
||||
}
|
||||
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResGetPigReward", data)
|
||||
}
|
||||
|
||||
func (p *PlayerPigData) ResDropPigReward(buf []byte) {
|
||||
|
||||
req := &msg.ReqDropPigReward{}
|
||||
proto.Unmarshal(buf, req)
|
||||
|
||||
res := &msg.ResDropPigReward{}
|
||||
res.PigId = req.PigId
|
||||
|
||||
if req.PigId != p.Data.PigId {
|
||||
res.ResultCode = MergeConst.Protocol_PigID_No_Exsit
|
||||
} else {
|
||||
res.ResultCode = 0
|
||||
}
|
||||
|
||||
p.DeleteLastPigData(req.PigId)
|
||||
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResDropPigReward", data)
|
||||
}
|
||||
418
src/server/game/PlayerProfileDataManager.go
Normal file
418
src/server/game/PlayerProfileDataManager.go
Normal file
@ -0,0 +1,418 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"server/db"
|
||||
"server/game/internal"
|
||||
"server/msg"
|
||||
"strconv"
|
||||
|
||||
"server/pkg/github.com/name5566/leaf/gate"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type PlayerProfileManager struct {
|
||||
MsqlStrucks []db.SqlPlayerProfileStruct
|
||||
MapSql map[int32]*db.SqlPlayerProfileStruct
|
||||
}
|
||||
|
||||
func (p *PlayerProfileManager) LoadDataFromDB(dwUin interface{}) bool {
|
||||
|
||||
sqlStr := "SELECT * FROM t_player_Profile_Data"
|
||||
p.MsqlStrucks = []db.SqlPlayerProfileStruct{}
|
||||
p.MapSql = make(map[int32]*db.SqlPlayerProfileStruct)
|
||||
db.SqlDb.Select(&p.MsqlStrucks, sqlStr)
|
||||
|
||||
for i := 0; i < len(p.MsqlStrucks); i++ {
|
||||
item := p.MsqlStrucks[i]
|
||||
p.MapSql[item.DwUin] = &item
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerProfileManager) GetPlayerDecorate(dwUin int32) (int, int, string) {
|
||||
sqlStr := "SELECT * FROM t_player_baseinfo WHERE dwUin = ?"
|
||||
sqlStruck := db.ResPlayerBaseInfo{}
|
||||
decorate := 0
|
||||
ActiveTime := 0
|
||||
FaceBookId := ""
|
||||
if err := db.SqlDb.Get(&sqlStruck, sqlStr, dwUin); err != nil {
|
||||
|
||||
} else {
|
||||
Score := 0
|
||||
for i := 1; i < int(sqlStruck.Level); i++ {
|
||||
Score = Score + (i-1)*10 + 20
|
||||
}
|
||||
Score = Score + int(sqlStruck.Exp)
|
||||
decorate = Score / 10
|
||||
ActiveTime = int(math.Max(float64(sqlStruck.LoginTime), float64(sqlStruck.LogoutTime)))
|
||||
FaceBookId = sqlStruck.FaceBookId
|
||||
}
|
||||
return decorate, ActiveTime, FaceBookId
|
||||
}
|
||||
|
||||
func (p *PlayerProfileManager) InitManager() {
|
||||
p.LoadDataFromDB("")
|
||||
}
|
||||
|
||||
func (p *PlayerProfileManager) AddNewProfile(st *db.SqlPlayerProfileStruct) bool {
|
||||
if p.GetPlayerProfile(st.DwUin) == nil {
|
||||
p.MapSql[st.DwUin] = st
|
||||
db.FormatAllMemInsertDb(st, "t_player_Profile_Data")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerProfileManager) UpdateNewProfile(st *db.SqlPlayerProfileStruct) bool {
|
||||
if p.GetPlayerProfile(st.DwUin) != nil {
|
||||
p.MapSql[st.DwUin] = st
|
||||
db.FormatAllMemUpdateDb(st, "t_player_Profile_Data", "dwUin")
|
||||
} else {
|
||||
p.AddNewProfile(st)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerProfileManager) GetPlayerProfileByNick(nick string) []*db.SqlPlayerProfileStruct {
|
||||
ret := []*db.SqlPlayerProfileStruct{}
|
||||
// G_getGameLogic().Mlogger.Debug("p.MapSql" + strconv.Itoa(len(p.MapSql)))
|
||||
// G_getGameLogic().Mlogger.Debug("nick:" + nick)
|
||||
for k, v := range p.MapSql {
|
||||
if strconv.Itoa(int(k)) == nick {
|
||||
ret = append(ret, v)
|
||||
} else {
|
||||
// G_getGameLogic().Mlogger.Debug("v.NickName:" + v.NickName)
|
||||
if nick == v.NickName {
|
||||
ret = append(ret, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (p *PlayerProfileManager) GetPlayerProfile(id int32) *db.SqlPlayerProfileStruct {
|
||||
|
||||
st, ok := p.MapSql[id]
|
||||
if ok {
|
||||
return st
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (p *PlayerProfileManager) GetIsHavePlayerById(id int32) bool {
|
||||
sqlStr := "SELECT * FROM t_player_baseinfo WHERE dwUin = ?"
|
||||
sqlStruck := db.ResPlayerBaseInfo{}
|
||||
if err := db.SqlDb.Get(&sqlStruck, sqlStr, id); err != nil {
|
||||
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *PlayerProfileManager) ReqPlayerProfileData(args []interface{}) {
|
||||
a := args[0].(gate.Agent)
|
||||
play, _ := internal.Agents.Load(a)
|
||||
buf := args[1].([]byte)
|
||||
player := play.(*Player)
|
||||
|
||||
req := &msg.ReqPlayerProfileData{}
|
||||
res := &msg.ResPlayerProfileData{}
|
||||
proto.Unmarshal(buf, req)
|
||||
profile := p.GetPlayerProfile(player.M_DwUin)
|
||||
if profile != nil {
|
||||
res.DwUin = player.M_DwUin
|
||||
res.NickName = profile.NickName
|
||||
res.ImageFrame = profile.ImageFrame
|
||||
res.ImageIcon = profile.ImageIcon
|
||||
res.PicURL = profile.PicURL
|
||||
res.UnlockFrame = profile.UnlockFrame
|
||||
res.UnlockIcon = profile.UnlockIcon
|
||||
DecorateCnt, ActiveTime, _ := p.GetPlayerDecorate(player.M_DwUin)
|
||||
res.DecorateCnt = int32(DecorateCnt)
|
||||
res.ActiveTime = int32(ActiveTime)
|
||||
} else {
|
||||
res.DwUin = player.M_DwUin
|
||||
res.NickName = "Player" + strconv.Itoa(int(player.M_DwUin))
|
||||
res.ImageFrame = 1
|
||||
res.ImageIcon = 1
|
||||
res.UnlockFrame = ""
|
||||
res.UnlockIcon = ""
|
||||
res.PicURL = ""
|
||||
DecorateCnt, ActiveTime, _ := p.GetPlayerDecorate(player.M_DwUin)
|
||||
res.DecorateCnt = int32(DecorateCnt)
|
||||
res.ActiveTime = int32(ActiveTime)
|
||||
|
||||
st := db.SqlPlayerProfileStruct{}
|
||||
st.DwUin = player.M_DwUin
|
||||
st.ImageFrame = 1
|
||||
st.ImageIcon = 1
|
||||
st.UnlockFrame = ""
|
||||
st.UnlockIcon = ""
|
||||
st.PicURL = ""
|
||||
st.NickName = "Player" + strconv.Itoa(int(player.M_DwUin))
|
||||
p.UpdateNewProfile(&st)
|
||||
}
|
||||
agent := player.GetAgentByPlayer()
|
||||
data1, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResPlayerProfileData", data1)
|
||||
|
||||
}
|
||||
|
||||
func (p *PlayerProfileManager) ReqUpdatePlayerProfile(args []interface{}) {
|
||||
a := args[0].(gate.Agent)
|
||||
play, _ := internal.Agents.Load(a)
|
||||
buf := args[1].([]byte)
|
||||
player := play.(*Player)
|
||||
|
||||
req := &msg.ReqUpdatePlayerProfile{}
|
||||
res := &msg.ResUpdatePlayerProfile{}
|
||||
proto.Unmarshal(buf, req)
|
||||
profile := p.GetPlayerProfile(player.M_DwUin)
|
||||
if profile != nil {
|
||||
if req.Type == 1 {
|
||||
profile.NickName = req.Param
|
||||
}
|
||||
if req.Type == 2 {
|
||||
value, _ := strconv.Atoi(req.Param)
|
||||
profile.ImageFrame = int32(value)
|
||||
}
|
||||
if req.Type == 3 {
|
||||
value, _ := strconv.Atoi(req.Param)
|
||||
profile.ImageIcon = int32(value)
|
||||
}
|
||||
p.UpdateNewProfile(profile)
|
||||
} else {
|
||||
st := db.SqlPlayerProfileStruct{}
|
||||
st.DwUin = player.M_DwUin
|
||||
st.ImageFrame = 1
|
||||
st.ImageIcon = 1
|
||||
st.NickName = "Player" + strconv.Itoa(int(player.M_DwUin))
|
||||
if req.Type == 1 {
|
||||
st.NickName = req.Param
|
||||
}
|
||||
if req.Type == 2 {
|
||||
value, _ := strconv.Atoi(req.Param)
|
||||
st.ImageFrame = int32(value)
|
||||
}
|
||||
if req.Type == 3 {
|
||||
value, _ := strconv.Atoi(req.Param)
|
||||
st.ImageIcon = int32(value)
|
||||
}
|
||||
st.UnlockFrame = ""
|
||||
st.UnlockIcon = ""
|
||||
st.PicURL = ""
|
||||
p.UpdateNewProfile(&st)
|
||||
}
|
||||
res.DwUin = req.DwUin
|
||||
res.Type = req.Type
|
||||
res.Param = req.Param
|
||||
res.ResultCode = 0
|
||||
agent := player.GetAgentByPlayer()
|
||||
data1, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResUpdatePlayerProfile", data1)
|
||||
|
||||
}
|
||||
|
||||
func (p *PlayerProfileManager) HttpReqPlayerBriefProfileData(Id int32) *msg.ResPlayerBriefProfileData {
|
||||
profile := p.GetPlayerProfile(Id)
|
||||
res := &msg.ResPlayerBriefProfileData{}
|
||||
if profile != nil {
|
||||
res.DwUin = profile.DwUin
|
||||
res.NickName = profile.NickName
|
||||
res.ImageFrame = profile.ImageFrame
|
||||
res.ImageIcon = profile.ImageIcon
|
||||
DecorateCnt, ActiveTime, _ := p.GetPlayerDecorate(Id)
|
||||
res.DecorateCnt = int32(DecorateCnt)
|
||||
res.ActiveTime = int32(ActiveTime)
|
||||
res.PicURL = profile.PicURL
|
||||
} else {
|
||||
res.DwUin = Id
|
||||
res.NickName = "Player" + strconv.Itoa(int(Id))
|
||||
res.ImageFrame = 1
|
||||
res.ImageIcon = 1
|
||||
res.PicURL = ""
|
||||
DecorateCnt, ActiveTime, _ := p.GetPlayerDecorate(Id)
|
||||
res.DecorateCnt = int32(DecorateCnt)
|
||||
res.ActiveTime = int32(ActiveTime)
|
||||
|
||||
st := db.SqlPlayerProfileStruct{}
|
||||
st.DwUin = Id
|
||||
st.ImageFrame = 1
|
||||
st.ImageIcon = 1
|
||||
st.UnlockFrame = ""
|
||||
st.UnlockIcon = ""
|
||||
st.PicURL = ""
|
||||
st.NickName = "Player" + strconv.Itoa(int(Id))
|
||||
p.UpdateNewProfile(&st)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (p *PlayerProfileManager) ReqPlayerBriefProfileData(args []interface{}) {
|
||||
a := args[0].(gate.Agent)
|
||||
play, _ := internal.Agents.Load(a)
|
||||
buf := args[1].([]byte)
|
||||
player := play.(*Player)
|
||||
|
||||
req := &msg.ReqPlayerBriefProfileData{}
|
||||
res := &msg.ResPlayerBriefProfileData{}
|
||||
proto.Unmarshal(buf, req)
|
||||
profile := p.GetPlayerProfile(req.DwUin)
|
||||
if profile != nil {
|
||||
res.DwUin = profile.DwUin
|
||||
res.NickName = profile.NickName
|
||||
res.ImageFrame = profile.ImageFrame
|
||||
res.ImageIcon = profile.ImageIcon
|
||||
DecorateCnt, ActiveTime, _ := p.GetPlayerDecorate(req.DwUin)
|
||||
res.DecorateCnt = int32(DecorateCnt)
|
||||
res.ActiveTime = int32(ActiveTime)
|
||||
res.PicURL = profile.PicURL
|
||||
} else {
|
||||
res.DwUin = req.DwUin
|
||||
res.NickName = "Player" + strconv.Itoa(int(req.DwUin))
|
||||
res.ImageFrame = 1
|
||||
res.ImageIcon = 1
|
||||
res.PicURL = ""
|
||||
|
||||
DecorateCnt, ActiveTime, _ := p.GetPlayerDecorate(req.DwUin)
|
||||
res.DecorateCnt = int32(DecorateCnt)
|
||||
res.ActiveTime = int32(ActiveTime)
|
||||
|
||||
st := db.SqlPlayerProfileStruct{}
|
||||
st.DwUin = req.DwUin
|
||||
st.ImageFrame = 1
|
||||
st.ImageIcon = 1
|
||||
st.UnlockFrame = ""
|
||||
st.UnlockIcon = ""
|
||||
st.PicURL = ""
|
||||
st.NickName = "Player" + strconv.Itoa(int(req.DwUin))
|
||||
p.UpdateNewProfile(&st)
|
||||
}
|
||||
agent := player.GetAgentByPlayer()
|
||||
data1, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResPlayerBriefProfileData", data1)
|
||||
|
||||
}
|
||||
|
||||
func (p *PlayerProfileManager) RandomGetAnPlayer(origin int32) *db.SqlPlayerProfileStruct {
|
||||
idx := rand.Intn(len(p.MsqlStrucks))
|
||||
|
||||
for p.MsqlStrucks[idx].DwUin == origin {
|
||||
idx = rand.Intn(len(p.MsqlStrucks))
|
||||
}
|
||||
Profile := p.GetPlayerProfile(p.MsqlStrucks[idx].DwUin)
|
||||
|
||||
if Profile != nil {
|
||||
return Profile
|
||||
} else {
|
||||
sql := &db.SqlPlayerProfileStruct{}
|
||||
sql.DwUin = p.MsqlStrucks[idx].DwUin
|
||||
sql.ImageFrame = 1
|
||||
sql.ImageIcon = 1
|
||||
sql.NickName = "Player" + strconv.Itoa(int(p.MsqlStrucks[idx].DwUin))
|
||||
sql.PicURL = ""
|
||||
p.UpdateNewProfile(sql)
|
||||
return sql
|
||||
}
|
||||
}
|
||||
func (p *PlayerProfileManager) GetIsHaveAddFriendInfo(sender int32, receive int32) (bool, *db.SqlAddFriendStruct) {
|
||||
sqlStr := "SELECT * FROM t_player_Req_add_Friend WHERE SenderId = ? AND ReceiverId = ?"
|
||||
sqlStruck := db.SqlAddFriendStruct{}
|
||||
|
||||
if err := db.SqlDb.Get(&sqlStruck, sqlStr, sender, receive); err != nil {
|
||||
return false, nil
|
||||
} else {
|
||||
return true, &sqlStruck
|
||||
}
|
||||
// return false
|
||||
}
|
||||
func (p *PlayerProfileManager) RandomGetPlayers(Cnt int, originId int32, ExcludeList []int32) []*db.SqlPlayerProfileStruct {
|
||||
|
||||
var CurCnt int = 0
|
||||
ret := []*db.SqlPlayerProfileStruct{}
|
||||
var Loops int = 0
|
||||
for {
|
||||
Ids := G_GameLogicPtr.DisorderLuaTable(len(p.MsqlStrucks), int(math.Min(float64(len(p.MsqlStrucks)), float64(Cnt))))
|
||||
for i := 0; i < len(Ids); i++ {
|
||||
IsIll := true
|
||||
for j := 0; j < len(ExcludeList); j++ {
|
||||
if ExcludeList[j] == p.MsqlStrucks[Ids[i]].DwUin {
|
||||
IsIll = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if IsIll {
|
||||
isHave1, _ := p.GetIsHaveAddFriendInfo(originId, p.MsqlStrucks[Ids[i]].DwUin)
|
||||
isHave2, _ := p.GetIsHaveAddFriendInfo(p.MsqlStrucks[Ids[i]].DwUin, originId)
|
||||
|
||||
if !isHave1 && !isHave2 {
|
||||
CurCnt += 1
|
||||
ret = append(ret, &p.MsqlStrucks[Ids[i]])
|
||||
ExcludeList = append(ExcludeList, p.MsqlStrucks[Ids[i]].DwUin)
|
||||
if CurCnt == Cnt {
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Loops += 1
|
||||
if Loops == 3 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (p *PlayerProfileManager) ReqUpdateFBPicURL(args []interface{}) {
|
||||
a := args[0].(gate.Agent)
|
||||
play, _ := internal.Agents.Load(a)
|
||||
buf := args[1].([]byte)
|
||||
player := play.(*Player)
|
||||
|
||||
req := &msg.ReqUpdateFBPicURL{}
|
||||
res := &msg.ResUpdateFBPicURL{}
|
||||
proto.Unmarshal(buf, req)
|
||||
profile := p.GetPlayerProfile(player.M_DwUin)
|
||||
res.ResultCode = 0
|
||||
if profile != nil {
|
||||
profile.PicURL = req.URL
|
||||
p.UpdateNewProfile(profile)
|
||||
} else {
|
||||
st := db.SqlPlayerProfileStruct{}
|
||||
st.DwUin = player.M_DwUin
|
||||
st.ImageFrame = 1
|
||||
st.ImageIcon = 1
|
||||
st.UnlockFrame = ""
|
||||
st.UnlockIcon = ""
|
||||
st.PicURL = req.URL
|
||||
st.NickName = "Player" + strconv.Itoa(int(player.M_DwUin))
|
||||
p.UpdateNewProfile(&st)
|
||||
}
|
||||
agent := player.GetAgentByPlayer()
|
||||
data1, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(agent, "ResUpdateFBPicURL", data1)
|
||||
|
||||
}
|
||||
|
||||
func (p *PlayerProfileManager) NewGetPlayerProfile(DwUin int32) *db.SqlPlayerProfileStruct {
|
||||
profile := p.GetPlayerProfile(DwUin)
|
||||
if profile != nil {
|
||||
return profile
|
||||
} else {
|
||||
st := db.SqlPlayerProfileStruct{}
|
||||
st.DwUin = DwUin
|
||||
st.ImageFrame = 1
|
||||
st.ImageIcon = 1
|
||||
st.UnlockFrame = ""
|
||||
st.UnlockIcon = ""
|
||||
st.PicURL = ""
|
||||
st.NickName = "Player" + strconv.Itoa(int(DwUin))
|
||||
p.UpdateNewProfile(&st)
|
||||
return &st
|
||||
}
|
||||
}
|
||||
1236
src/server/game/PlayerShopData.go
Normal file
1236
src/server/game/PlayerShopData.go
Normal file
File diff suppressed because it is too large
Load Diff
227
src/server/game/PlayerUnlockingChestMod.go
Normal file
227
src/server/game/PlayerUnlockingChestMod.go
Normal file
@ -0,0 +1,227 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
mergeDataCfg "server/conf/mergeData"
|
||||
"server/db"
|
||||
"server/msg"
|
||||
"server/pkg/github.com/name5566/leaf/timer"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type PlayerUnlockingChestData struct {
|
||||
*PlayerData
|
||||
Data msg.ResUnlockingChestID
|
||||
MLeafTimer *timer.Timer
|
||||
Mdispatr *timer.Dispatcher
|
||||
}
|
||||
|
||||
func (p *PlayerUnlockingChestData) LoadDataFromDB(dwUin interface{}) bool {
|
||||
|
||||
sqlStr := "SELECT * FROM t_player_chest_data WHERE dwUin = ?"
|
||||
sqlStruck := db.SqlChestStruct{}
|
||||
p.Mdispatr = timer.NewDispatcher(1)
|
||||
if err := db.SqlDb.Get(&sqlStruck, sqlStr, dwUin.(int32)); err != nil {
|
||||
fmt.Printf("get data failed, err:%v\n", err)
|
||||
p.IsHaveDataDb = false
|
||||
} else {
|
||||
p.IsHaveDataDb = true
|
||||
}
|
||||
p.Data.DwUin = dwUin.(int32)
|
||||
p.Data.ChestID = sqlStruck.ChestID
|
||||
p.Data.UnlockStartTime = sqlStruck.UnlockStartTime
|
||||
p.Data.CurSvrTime = int32(time.Now().Unix())
|
||||
|
||||
p.Reconnect(false)
|
||||
return true
|
||||
}
|
||||
func (p *PlayerUnlockingChestData) Reconnect(b bool) {
|
||||
if p.Data.ChestID > 0 {
|
||||
chessKey := p.GetPlayer().GetIFGameData("PlayerChessData").(*PlayerChessData).GetKeyByEmitID(p.Data.ChestID)
|
||||
if chessKey == "" {
|
||||
p.Data.ChestID = 0
|
||||
p.Data.UnlockStartTime = 0
|
||||
return
|
||||
}
|
||||
MergeId := p.GetPlayer().GetIFGameData("PlayerChessData").(*PlayerChessData).GetValueByKey(chessKey)
|
||||
item, _ := mergeDataCfg.GetOne(int(MergeId))
|
||||
cool := item.CoolTime
|
||||
deltaTime := time.Now().Unix() - (int64)(p.Data.UnlockStartTime)
|
||||
if deltaTime >= (int64)(cool) { //注意后面读表
|
||||
if p.M_Player.GetGameData("PlayerChessData") == nil {
|
||||
data := &PlayerChessData{PlayerData: NewPlayerData("PlayerChessData", p.M_Player)}
|
||||
ok := data.LoadDataFromDB(p.M_Player.M_DwUin)
|
||||
if ok {
|
||||
p.M_Player.playerdata["PlayerChessData"] = data
|
||||
p.M_Player.playerdataIF["PlayerChessData"] = data
|
||||
}
|
||||
}
|
||||
|
||||
p.GetPlayer().GetIFGameData("PlayerChessData").(*PlayerChessData).SetValueByKey(chessKey)
|
||||
fmt.Println("chessKey:", chessKey)
|
||||
p.Data.ChestID = 0
|
||||
p.Data.UnlockStartTime = 0
|
||||
if b {
|
||||
p.NotifyUnlockingChestData()
|
||||
}
|
||||
} else {
|
||||
go func() {
|
||||
// 注释内容也可以使用
|
||||
t1 := (int64)(cool) - deltaTime
|
||||
|
||||
p.MLeafTimer = p.Mdispatr.AfterFunc(time.Duration(t1)*time.Second, func() {
|
||||
p.NotifyUnlockingChestData()
|
||||
p.MLeafTimer = nil
|
||||
})
|
||||
(<-p.Mdispatr.ChanTimer).Cb()
|
||||
}()
|
||||
}
|
||||
p.NotifyInitUnlockingChestID()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PlayerUnlockingChestData) RenewData() {
|
||||
if p.Data.ChestID > 0 {
|
||||
chessKey := p.GetPlayer().GetIFGameData("PlayerChessData").(*PlayerChessData).GetKeyByEmitID(p.Data.ChestID)
|
||||
MergeId := p.GetPlayer().GetIFGameData("PlayerChessData").(*PlayerChessData).GetValueByKey(chessKey)
|
||||
// MergeId := p.M_Player.GetIFGameData("PlayerEmitDetailData").(*PlayerEmitDetailData).GetMergeIDByChestid(p.Data.ChestID)
|
||||
item, _ := mergeDataCfg.GetOne(int(MergeId))
|
||||
cool := item.CoolTime
|
||||
deltaTime := time.Now().Unix() - (int64)(p.Data.UnlockStartTime)
|
||||
if p.MLeafTimer != nil {
|
||||
p.MLeafTimer.Disabled()
|
||||
p.Mdispatr.ChanTimer <- p.MLeafTimer
|
||||
p.MLeafTimer.Stop()
|
||||
p.MLeafTimer = nil
|
||||
}
|
||||
if deltaTime >= (int64)(cool) { //注意后面读表
|
||||
|
||||
p.GetPlayer().GetIFGameData("PlayerChessData").(*PlayerChessData).SetValueByKey(chessKey)
|
||||
|
||||
p.Data.ChestID = 0
|
||||
p.Data.UnlockStartTime = 0
|
||||
} else {
|
||||
go func() {
|
||||
// 注释内容也可以使用
|
||||
t1 := (int64)(cool) - deltaTime
|
||||
|
||||
p.MLeafTimer = p.Mdispatr.AfterFunc(time.Duration(t1)*time.Second, func() {
|
||||
p.NotifyUnlockingChestData()
|
||||
p.MLeafTimer = nil
|
||||
})
|
||||
(<-p.Mdispatr.ChanTimer).Cb()
|
||||
}()
|
||||
}
|
||||
p.NotifyInitUnlockingChestID()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PlayerUnlockingChestData) NotifyInitUnlockingChestID() {
|
||||
notify := &msg.NotifyInitUnlockingChestID{}
|
||||
notify.ChestID = p.Data.ChestID
|
||||
notify.UnlockStartTime = p.Data.UnlockStartTime
|
||||
notify.DwUin = p.M_Player.M_DwUin
|
||||
notify.CurSvrTime = int32(time.Now().Unix())
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(notify)
|
||||
G_GameLogicPtr.PackResInfo(agent, "NotifyInitUnlockingChestID", data)
|
||||
}
|
||||
|
||||
func (p *PlayerUnlockingChestData) ClearData() bool {
|
||||
p.SaveDataFromDB("")
|
||||
if p.MLeafTimer != nil {
|
||||
p.MLeafTimer.Disabled()
|
||||
p.Mdispatr.ChanTimer <- p.MLeafTimer
|
||||
p.MLeafTimer.Stop()
|
||||
p.MLeafTimer = nil
|
||||
}
|
||||
return true
|
||||
}
|
||||
func (p *PlayerUnlockingChestData) SaveDataFromDB(Key interface{}) bool {
|
||||
|
||||
sqlStruck := db.SqlChestStruct{}
|
||||
sqlStruck.DwUin = p.M_Player.M_DwUin
|
||||
sqlStruck.ChestID = p.Data.ChestID
|
||||
sqlStruck.UnlockStartTime = p.Data.UnlockStartTime
|
||||
|
||||
if p.IsHaveDataDb {
|
||||
db.FormatAllMemUpdateDb(&sqlStruck, "t_player_chest_data", "dwUin")
|
||||
} else {
|
||||
db.FormatAllMemInsertDb(&sqlStruck, "t_player_chest_data")
|
||||
}
|
||||
p.IsHaveDataDb = true
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PlayerUnlockingChestData) ResUnlockingChestID(buf []byte) {
|
||||
update := &msg.ReqUnlockingChestID{}
|
||||
proto.Unmarshal(buf, update)
|
||||
p.Data.ChestID = update.ChestID
|
||||
p.Data.UnlockStartTime = int32(time.Now().Unix())
|
||||
// G_GameLogicPtr.Mlogger.Debug("ResUnlockingChestID1:", p.Data.ChestID, update.MergeID)
|
||||
p.M_Player.GetIFGameData("PlayerEmitDetailData").(*PlayerEmitDetailData).SetMergeIDByChestid(update.ChestID, update.MergeID)
|
||||
// G_GameLogicPtr.Mlogger.Debug("ResUnlockingChestID2:", p.Data.ChestID, update.MergeID)
|
||||
p.RenewData()
|
||||
// G_GameLogicPtr.Mlogger.Debug("ResUnlockingChestID3:", p.Data.ChestID, update.MergeID)
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(&p.Data)
|
||||
G_GameLogicPtr.PackResInfo(agent, "ResUnlockingChestID", data)
|
||||
}
|
||||
|
||||
func (p *PlayerUnlockingChestData) ResChestUnlockCD(buf []byte) {
|
||||
update := &msg.ReqChestUnlockCD{}
|
||||
proto.Unmarshal(buf, update)
|
||||
|
||||
res := &msg.ResChestUnlockCD{}
|
||||
res.DwUin = p.GetPlayer().M_DwUin
|
||||
res.ChestID = update.ChestID
|
||||
res.Type = update.Type
|
||||
res.CurSvrTime = int32(time.Now().Unix())
|
||||
////ad
|
||||
if res.Type == 3 {
|
||||
p.Data.UnlockStartTime = p.Data.UnlockStartTime - 60*30
|
||||
res.UnlockStartTime = p.Data.UnlockStartTime
|
||||
p.RenewData()
|
||||
}
|
||||
///diamond
|
||||
if res.Type == 2 {
|
||||
p.Data.UnlockStartTime = 0
|
||||
p.RenewData()
|
||||
}
|
||||
|
||||
if res.Type == 1 {
|
||||
p.Data.ChestID = 0
|
||||
p.Data.UnlockStartTime = 0
|
||||
if p.MLeafTimer != nil {
|
||||
p.MLeafTimer.Disabled()
|
||||
p.Mdispatr.ChanTimer <- p.MLeafTimer
|
||||
p.MLeafTimer.Stop()
|
||||
p.MLeafTimer = nil
|
||||
}
|
||||
}
|
||||
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(res)
|
||||
G_GameLogicPtr.PackResInfo(agent, "ResChestUnlockCD", data)
|
||||
}
|
||||
|
||||
func (p *PlayerUnlockingChestData) NotifyUnlockingChestData() {
|
||||
|
||||
chessKey := p.GetPlayer().GetIFGameData("PlayerChessData").(*PlayerChessData).GetKeyByEmitID(p.Data.ChestID)
|
||||
p.GetPlayer().GetIFGameData("PlayerChessData").(*PlayerChessData).SetValueByKey(chessKey)
|
||||
|
||||
notify := &msg.NotifyUnlockingChestData{}
|
||||
notify.DwUin = p.GetPlayer().M_DwUin
|
||||
notify.ChestID = 0
|
||||
notify.UnlockStartTime = 0
|
||||
p.Data.ChestID = 0
|
||||
p.Data.UnlockStartTime = 0
|
||||
notify.CurSvrTime = int32(time.Now().Unix())
|
||||
|
||||
agent := p.GetPlayer().GetAgentByPlayer()
|
||||
data, _ := proto.Marshal(notify)
|
||||
G_GameLogicPtr.PackResInfo(agent, "NotifyUnlockingChestData", data)
|
||||
|
||||
}
|
||||
120
src/server/game/RankMgr.go
Normal file
120
src/server/game/RankMgr.go
Normal file
@ -0,0 +1,120 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"server/db"
|
||||
"server/game/mod/msg"
|
||||
"sort"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type RankMgr struct {
|
||||
*ServerMod
|
||||
}
|
||||
|
||||
type RankData struct {
|
||||
List map[int][]*Rank // 玩家排行榜
|
||||
BackData map[int][]*Rank // 玩家排行榜 备份
|
||||
}
|
||||
|
||||
const (
|
||||
RANK_TYPE_USER = 1 // 玩家排行榜
|
||||
RANK_TYPE_CHAMPSHIP = 2 // 锦标赛排行榜
|
||||
RANK_TYPE_GLOBAL = 3 // 全球排行榜
|
||||
|
||||
RANK_USER = "rank_user" // redis玩家排行榜
|
||||
)
|
||||
|
||||
type Rank struct {
|
||||
Uid int
|
||||
Score float64
|
||||
Time int64
|
||||
}
|
||||
|
||||
type RankMsg struct {
|
||||
Uid int
|
||||
Score float64
|
||||
RankType int
|
||||
}
|
||||
|
||||
func (r *RankMgr) Init() {
|
||||
r.key = RANK_MGR_KEY
|
||||
r.data = &RankData{
|
||||
List: make(map[int][]*Rank, 0),
|
||||
}
|
||||
// 注册处理函数
|
||||
r.init()
|
||||
r.RegisterHandler(msg.HANDLE_TYPE_RANK, r.inRank)
|
||||
r.RegisterHandler(msg.HANDLE_TYPE_RANK_INFO, r.getRankInfo)
|
||||
r.RegisterHandler(msg.SERVER_ZERO_UPDATE, r.ZeroUpdate)
|
||||
}
|
||||
|
||||
func (r *RankMgr) getData() *RankData {
|
||||
return r.data.(*RankData)
|
||||
}
|
||||
|
||||
// 零点更新 重置榜单
|
||||
func (r *RankMgr) ZeroUpdate(m *msg.Msg) (interface{}, error) {
|
||||
r.getData().BackData[RANK_TYPE_CHAMPSHIP] = r.getData().List[RANK_TYPE_CHAMPSHIP]
|
||||
r.getData().List[RANK_TYPE_CHAMPSHIP] = []*Rank{}
|
||||
r.update = true
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 获取榜单数据
|
||||
func (r *RankMgr) getRank(RankType int) []*Rank {
|
||||
if v, ok := r.getData().List[RankType]; ok {
|
||||
return v
|
||||
}
|
||||
return []*Rank{}
|
||||
}
|
||||
|
||||
// 设置榜单数据
|
||||
func (r *RankMgr) setRank(RankType int, data []*Rank) {
|
||||
r.getData().List[RankType] = data
|
||||
}
|
||||
|
||||
// 获取排行榜信息
|
||||
func (r *RankMgr) getRankInfo(m *msg.Msg) (interface{}, error) {
|
||||
data := m.Extra.(RankMsg)
|
||||
rankList := r.getRank(data.RankType)
|
||||
return rankList, nil
|
||||
}
|
||||
|
||||
// 进入排行榜
|
||||
func (r *RankMgr) inRank(m *msg.Msg) (interface{}, error) {
|
||||
data := m.Extra.(RankMsg)
|
||||
rankList := r.getRank(data.RankType)
|
||||
inRank := false
|
||||
for _, v := range rankList {
|
||||
if v.Uid == data.Uid {
|
||||
if v.Score < data.Score {
|
||||
v.Score = data.Score
|
||||
v.Time = m.SendT
|
||||
inRank = true
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
if !inRank {
|
||||
rankList = append(rankList, &Rank{Uid: data.Uid, Score: data.Score, Time: m.SendT})
|
||||
}
|
||||
sort.Slice(rankList, func(i, j int) bool { // 排序 从大到小 数值相等按时间排序
|
||||
if rankList[i].Score > rankList[j].Score {
|
||||
return true
|
||||
} else if rankList[i].Score == rankList[j].Score {
|
||||
return rankList[i].Time < rankList[j].Time
|
||||
}
|
||||
return false
|
||||
})
|
||||
// if len(rankList) >= 100 {
|
||||
// rankList = rankList[:100]
|
||||
// }
|
||||
r.setRank(data.RankType, rankList)
|
||||
if data.RankType == RANK_TYPE_USER {
|
||||
Uid := strconv.Itoa(data.Uid)
|
||||
db.RedisZAdd(RANK_USER, Uid, data.Score)
|
||||
}
|
||||
r.update = true
|
||||
return nil, nil
|
||||
}
|
||||
3455
src/server/game/RegisterNetworkFunc.go
Normal file
3455
src/server/game/RegisterNetworkFunc.go
Normal file
File diff suppressed because it is too large
Load Diff
166
src/server/game/ServerMod.go
Normal file
166
src/server/game/ServerMod.go
Normal file
@ -0,0 +1,166 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"server/GoUtil"
|
||||
"server/db"
|
||||
"server/game/mod/msg"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
"server/pkg/github.com/name5566/leaf/timer"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
FRIEND_MGR_KEY = "FRIEND_MGR"
|
||||
RANK_MGR_KEY = "RANK_MGR"
|
||||
MAIL_MGR_KEY = "MAIL_MGR"
|
||||
|
||||
PER_SAVE_TIME = 1
|
||||
)
|
||||
|
||||
type ServerMod struct {
|
||||
mDispatr *timer.Dispatcher
|
||||
lock sync.Mutex
|
||||
msgChan chan *msg.Msg
|
||||
key string
|
||||
handler map[int]interface{}
|
||||
timeout time.Duration
|
||||
update bool
|
||||
data interface{}
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (s *ServerMod) init() {
|
||||
s.msgChan = make(chan *msg.Msg, 10)
|
||||
s.mDispatr = timer.NewDispatcher(10)
|
||||
s.timeout = time.Duration(time.Second * 10)
|
||||
s.handler = make(map[int]interface{})
|
||||
s.update = false
|
||||
s.LoadData()
|
||||
s.mDispatr.AfterFunc(time.Duration(PER_SAVE_TIME), func() {
|
||||
s.SaveData()
|
||||
})
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Debug("FriendMgr panic: %s", r)
|
||||
s.lock.Unlock()
|
||||
}
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case msg := <-s.msgChan:
|
||||
s.lock.Lock()
|
||||
s.Handle(msg)
|
||||
s.lock.Unlock()
|
||||
case Cb := <-s.mDispatr.ChanTimer:
|
||||
s.lock.Lock()
|
||||
Cb.Cb()
|
||||
s.lock.Unlock()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// 处理消息
|
||||
func (s *ServerMod) Handle(m *msg.Msg) (interface{}, error) {
|
||||
if fun, ok := s.handler[m.Type]; ok {
|
||||
return fun.(func(*msg.Msg) (interface{}, error))(m)
|
||||
}
|
||||
log.Debug("server mod key:%s handle not exist handle type:%d", s.key, m.Type)
|
||||
return nil, fmt.Errorf("server mod handler err")
|
||||
}
|
||||
|
||||
// 注册处理器
|
||||
func (s *ServerMod) RegisterHandler(HandlerType int, fun interface{}) {
|
||||
switch fun.(type) {
|
||||
case func(*msg.Msg) (interface{}, error):
|
||||
default:
|
||||
log.Debug("RegisterHandler fun type err, key:%s, handler type :%d", s.key, HandlerType)
|
||||
}
|
||||
s.handler[HandlerType] = fun
|
||||
}
|
||||
|
||||
// 发送消息队列
|
||||
func (s *ServerMod) Send(msg *msg.Msg) {
|
||||
s.msgChan <- msg
|
||||
}
|
||||
|
||||
// 同步请求
|
||||
func (s *ServerMod) Call(m *msg.Msg) (interface{}, error) {
|
||||
responseChan := make(chan interface{})
|
||||
errorChan := make(chan error)
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
errorChan <- fmt.Errorf("panic: %v", r)
|
||||
}
|
||||
}()
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
result, err := s.Handle(m)
|
||||
if err != nil {
|
||||
errorChan <- err
|
||||
return
|
||||
}
|
||||
responseChan <- result
|
||||
}()
|
||||
|
||||
select {
|
||||
case res := <-responseChan:
|
||||
return res, nil
|
||||
case err := <-errorChan:
|
||||
log.Debug("handle call err. %v", err)
|
||||
return nil, err
|
||||
case <-time.After(s.timeout):
|
||||
log.Debug("handle call timeout")
|
||||
return nil, fmt.Errorf("timeout after %v", s.timeout)
|
||||
}
|
||||
}
|
||||
|
||||
// mysql 保存消息
|
||||
func (s *ServerMod) SaveData() {
|
||||
s.mDispatr.AfterFunc(time.Duration(PER_SAVE_TIME+GoUtil.RandNum(5, 10)), func() {
|
||||
s.SaveData()
|
||||
})
|
||||
if !s.update {
|
||||
return
|
||||
}
|
||||
DbData := db.SqlServerModStruct{}
|
||||
DbData.Key = s.key
|
||||
DbData.UpdataTime = GoUtil.Now()
|
||||
var err error
|
||||
DbData.ModData, err = GoUtil.GobMarshal(s.data)
|
||||
if err != nil {
|
||||
log.Debug("SaveData Marshal failed,Mod Key: %s err:%v", s.key, err)
|
||||
}
|
||||
err = db.SaveServerData(&DbData)
|
||||
if err != nil {
|
||||
log.Debug("SaveData sql exec ,Mod Key: %s err:%v", s.key, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *ServerMod) LoadData() {
|
||||
DbData := db.SqlServerModStruct{}
|
||||
err := db.GetServerData(&DbData, s.key)
|
||||
if err != nil {
|
||||
DbData.Key = s.key
|
||||
DbData.UpdataTime = GoUtil.Now()
|
||||
err = db.InsertServerData(&DbData)
|
||||
if err != nil {
|
||||
log.Debug("LoadData sql exec ,Mod Key: %s err:%v", s.key, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if len(DbData.ModData) == 0 {
|
||||
return
|
||||
}
|
||||
err = GoUtil.GobUnmarshal(DbData.ModData, s.data)
|
||||
if err != nil {
|
||||
log.Debug("LoadData Unmarshal failed,Mod Key: %s err:%v", s.key, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
42
src/server/game/UnitTest.go
Normal file
42
src/server/game/UnitTest.go
Normal file
@ -0,0 +1,42 @@
|
||||
package game
|
||||
|
||||
import "fmt"
|
||||
|
||||
func UnitEndlessReward(p *Player) error {
|
||||
EndlessMod := p.PlayMod.getEndlessMod()
|
||||
if EndlessMod == nil {
|
||||
return fmt.Errorf("EndlessMod is nil")
|
||||
}
|
||||
Item, err := EndlessMod.GetReward()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if Item == nil {
|
||||
return fmt.Errorf("item is nil")
|
||||
}
|
||||
err = p.HandleItem(Item, "Endless")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func UnitChessShop(p *Player) error {
|
||||
ChessMod := p.PlayMod.getChessMod()
|
||||
if ChessMod == nil {
|
||||
return fmt.Errorf("ChessMod is nil")
|
||||
}
|
||||
ChessMod.EmitList = make(map[int]int)
|
||||
ChessMod.EmitList[83] = 1
|
||||
ChessMod.EmitList[125] = 1
|
||||
ChargeMod := p.PlayMod.getChargeMod()
|
||||
if ChargeMod == nil {
|
||||
return fmt.Errorf("ChargeMod is nil")
|
||||
}
|
||||
p.PlayMod.save()
|
||||
p.PlayMod.ClearData(p)
|
||||
ChargeMod.TriggerChargeUnlock(4, ChessMod.GetEmitList())
|
||||
b := ChargeMod.BackData()
|
||||
fmt.Println(b)
|
||||
return nil
|
||||
}
|
||||
55
src/server/game/common.go
Normal file
55
src/server/game/common.go
Normal file
@ -0,0 +1,55 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"server/game/internal"
|
||||
"server/pkg/github.com/name5566/leaf/gate"
|
||||
"sort"
|
||||
)
|
||||
|
||||
const (
|
||||
PLAYER_BASE_DATA = "PlayerBaseData"
|
||||
BASE_MODULE = "base"
|
||||
CHESS_MODULE = "chess"
|
||||
)
|
||||
|
||||
// 解析参数
|
||||
func ParseArgs(args []interface{}) (gate.Agent, *Player, []byte) {
|
||||
a := args[0].(gate.Agent)
|
||||
p, _ := internal.Agents.Load(a)
|
||||
player := p.(*Player)
|
||||
buf := args[1].([]byte)
|
||||
return a, player, buf
|
||||
}
|
||||
|
||||
// 获取结构体名称
|
||||
func GetStructName(v interface{}) string {
|
||||
t := reflect.TypeOf(v)
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.Kind() == reflect.Struct {
|
||||
return t.Name()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 判断两个切片的元素是否一致
|
||||
func SlicesEqual(a, b []int) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 创建副本以避免修改原始切片
|
||||
aCopy := make([]int, len(a))
|
||||
bCopy := make([]int, len(b))
|
||||
copy(aCopy, a)
|
||||
copy(bCopy, b)
|
||||
|
||||
// 对切片进行排序
|
||||
sort.Ints(aCopy)
|
||||
sort.Ints(bCopy)
|
||||
|
||||
// 比较排序后的切片
|
||||
return reflect.DeepEqual(aCopy, bCopy)
|
||||
}
|
||||
179
src/server/game/external.go
Normal file
179
src/server/game/external.go
Normal file
@ -0,0 +1,179 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"server/GoUtil"
|
||||
"server/MergeConst"
|
||||
"server/game/internal"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"server/msg"
|
||||
|
||||
"server/pkg/github.com/name5566/leaf/gate"
|
||||
"server/pkg/github.com/name5566/leaf/log"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"server/db"
|
||||
)
|
||||
|
||||
var (
|
||||
Module = new(internal.Module)
|
||||
ChanRPC = internal.ChanRPC
|
||||
)
|
||||
|
||||
func handler(m interface{}, h interface{}) {
|
||||
Module.Skeleton.RegisterChanRPC(reflect.TypeOf(m), h)
|
||||
}
|
||||
|
||||
func RegisterHandlerRPC(param []interface{}) {
|
||||
handler(&msg.ClientReq{}, HandleClientReq)
|
||||
}
|
||||
|
||||
func init() {
|
||||
db.InitDB()
|
||||
db.InitRedis()
|
||||
// db.TestGetAllKey()
|
||||
GoUtil.RegisterEvent("GameModuleOnInit", RegisterHandlerRPC, nil)
|
||||
G_getGameLogic()
|
||||
}
|
||||
|
||||
func HandleClientReq(args []interface{}) {
|
||||
if G_GameLogicPtr.SeverInfo.Status == SERVER_STATUS_CLOSE || G_GameLogicPtr.SeverInfo.Status == SERVER_STATUS_MAINTAIN {
|
||||
return // 服务器关闭或者维护中,不处理任何消息
|
||||
}
|
||||
m := args[0].(*msg.ClientReq)
|
||||
// 消息的发送者
|
||||
a := args[1].(gate.Agent)
|
||||
buf := m.GetInfo()
|
||||
log.Debug("消息Func : %s", m.GetFunc())
|
||||
switch m.GetFunc() {
|
||||
case "ClientTick":
|
||||
case "ReqServerVersion":
|
||||
G_GameLogicPtr.SendServerVersion(a)
|
||||
case "ReqRegisterAccount":
|
||||
detail := &msg.ReqRegisterAccount{}
|
||||
proto.Unmarshal(buf, detail)
|
||||
gl := G_getGameLogic()
|
||||
if gl.IsExsitAccount(detail.UserName) {
|
||||
ResRegisterAccount := &msg.ResRegisterAccount{}
|
||||
ResRegisterAccount.ResultCode = MergeConst.Protocol_Error_Account_Exist
|
||||
data, _ := proto.Marshal(ResRegisterAccount)
|
||||
gl.PackResInfo(a, "ResRegisterAccount", data)
|
||||
break
|
||||
}
|
||||
if strings.Count(detail.UserName, "")-1 < 6 {
|
||||
ResRegisterAccount := &msg.ResRegisterAccount{}
|
||||
ResRegisterAccount.ResultCode = MergeConst.Protocol_Error_Account_OR_PWD_Short
|
||||
data, _ := proto.Marshal(ResRegisterAccount)
|
||||
gl.PackResInfo(a, "ResRegisterAccount", data)
|
||||
|
||||
break
|
||||
}
|
||||
gl.Db_AccountInfo.UserName = detail.UserName
|
||||
gl.Db_AccountInfo.UserPassword = detail.UserPwd
|
||||
if !gl.NewAccountInsertDataToDB() {
|
||||
ResRegisterAccount := &msg.ResRegisterAccount{}
|
||||
ResRegisterAccount.ResultCode = MergeConst.Protocol_Error_Account_Fail
|
||||
data, _ := proto.Marshal(ResRegisterAccount)
|
||||
gl.PackResInfo(a, "ResRegisterAccount", data)
|
||||
break
|
||||
}
|
||||
ResRegisterAccount := &msg.ResRegisterAccount{}
|
||||
ResRegisterAccount.ResultCode = 0
|
||||
data, _ := proto.Marshal(ResRegisterAccount)
|
||||
gl.PackResInfo(a, "ResRegisterAccount", data)
|
||||
case "ReqLogin":
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Debug("uid : %d, func : %s, fatal : %s", 0, m.GetFunc(), r)
|
||||
}
|
||||
}()
|
||||
detail := &msg.ReqLogin{}
|
||||
proto.Unmarshal(buf, detail)
|
||||
accountInfo := db.GetAccountInfoFromDb(detail.UserName)
|
||||
ResLogin := &msg.ResLogin{}
|
||||
if accountInfo != nil {
|
||||
if accountInfo.UserPassword == detail.UserPwd {
|
||||
playerbaseinfo := db.GetPlayerBaseInfoFromDbByName(detail.UserName)
|
||||
if playerbaseinfo != nil {
|
||||
ResLogin.ResultCode = 0
|
||||
ResLogin.DwUin = playerbaseinfo.DwUin
|
||||
ResLogin.FaceBookId = playerbaseinfo.FaceBookId
|
||||
ResLogin.UserName = playerbaseinfo.UserName
|
||||
} else {
|
||||
ResLogin.ResultCode = MergeConst.Protocol_Error_Account_NoExsit
|
||||
ResLogin.DwUin = 0
|
||||
}
|
||||
} else {
|
||||
ResLogin.ResultCode = MergeConst.Protocol_Error_Account_OR_PWD_ERROR
|
||||
ResLogin.DwUin = 0
|
||||
}
|
||||
} else {
|
||||
ResLogin.ResultCode = MergeConst.Protocol_Error_Account_OR_PWD_ERROR
|
||||
ResLogin.DwUin = 0
|
||||
resBuff, _ := proto.Marshal(ResLogin)
|
||||
G_GameLogicPtr.PackResInfo(a, "ResLogin", resBuff)
|
||||
return
|
||||
}
|
||||
if ResLogin.DwUin > 0 {
|
||||
if OldPlayer, ok := G_GameLogicPtr.M_Players[ResLogin.DwUin]; ok {
|
||||
G_GameLogicPtr.ReplaceExistPlayerAndAgent(a, OldPlayer)
|
||||
OldPlayer.PAMgr.InitActiveMgr(OldPlayer)
|
||||
} else {
|
||||
player := G_GameLogicPtr.FindOfflinePlayer(ResLogin.DwUin)
|
||||
if player != nil {
|
||||
G_GameLogicPtr.RebindPlayerAndAgent(a, player)
|
||||
player.PAMgr.InitActiveMgr(player)
|
||||
} else {
|
||||
G_GameLogicPtr.CreateNewPlayer(a, detail.UserName)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
p, _ := internal.Agents.Load(a)
|
||||
if p != nil {
|
||||
p.(*Player).PushClientRes(ResLogin)
|
||||
G_GameLogicPtr.AddLog(&Log{
|
||||
Uid: p.(*Player).M_DwUin,
|
||||
Type: Login_log,
|
||||
})
|
||||
}
|
||||
case "ReqServerTime": // 获取服务器时间
|
||||
detail := &msg.ReqServerTime{}
|
||||
proto.Unmarshal(buf, detail)
|
||||
res := &msg.ResServerTime{}
|
||||
res.ServerTime = (int32)(time.Now().Unix())
|
||||
data, _ := proto.Marshal(res)
|
||||
G_getGameLogic().PackResInfo(a, "ResServerTime", data)
|
||||
case "ReqOfflineReconnect": // 断线重连
|
||||
RunNetProcessByKey(m.GetFunc(), []interface{}{a, buf})
|
||||
default:
|
||||
p, ok := internal.Agents.Load(a)
|
||||
if ok && p != G_GameLogicPtr.NotInitPlayer {
|
||||
p.(*Player).lock.Lock() //加锁
|
||||
backup := p.(*Player).BackUp() // 备份当前的 Player 值
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Debug("uid : %d, func : %s, fatal : %s", p.(*Player).M_DwUin, m.GetFunc(), r)
|
||||
p.(*Player).Recover(backup) //还原Player的数据
|
||||
}
|
||||
p.(*Player).lock.Unlock() //解锁
|
||||
}()
|
||||
p.(*Player).args = make(map[string]interface{})
|
||||
err := RunNetProcessByKey(m.GetFunc(), []interface{}{a, buf})
|
||||
if err != nil {
|
||||
log.Debug("uid : %d, func : %s, err : %s", p.(*Player).M_DwUin, m.GetFunc(), err)
|
||||
p.(*Player).Recover(backup) //还原Player的数据
|
||||
return
|
||||
}
|
||||
p.(*Player).ProcessTrigger()
|
||||
}
|
||||
}
|
||||
p, b := internal.Agents.Load(a)
|
||||
if b {
|
||||
p.(*Player).SendClientRes()
|
||||
}
|
||||
|
||||
}
|
||||
35
src/server/game/internal/chanrpc.go
Normal file
35
src/server/game/internal/chanrpc.go
Normal file
@ -0,0 +1,35 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"server/GoUtil"
|
||||
"server/MergeConst"
|
||||
"sync"
|
||||
|
||||
"server/pkg/github.com/name5566/leaf/gate"
|
||||
)
|
||||
|
||||
var Agents = sync.Map{}
|
||||
|
||||
func init() {
|
||||
skeleton.RegisterChanRPC("NewAgent", rpcNewAgent)
|
||||
skeleton.RegisterChanRPC("CloseAgent", rpcCloseAgent)
|
||||
}
|
||||
|
||||
func rpcNewAgent(args []interface{}) {
|
||||
a := args[0].(gate.Agent)
|
||||
Agents.Store(a, struct{}{})
|
||||
GoUtil.CallEvent(MergeConst.Notify_Socket_Connect, []interface{}{a})
|
||||
}
|
||||
|
||||
func rpcCloseAgent(args []interface{}) {
|
||||
a := args[0].(gate.Agent)
|
||||
p, ok := Agents.Load(a)
|
||||
if ok {
|
||||
GoUtil.CallEvent(MergeConst.Notify_Socket_Closed, []interface{}{p})
|
||||
Agents.Delete(a)
|
||||
}
|
||||
}
|
||||
|
||||
func AsignPlayerToAgents(a gate.Agent, player interface{}) {
|
||||
Agents.Store(a, player)
|
||||
}
|
||||
5
src/server/game/internal/handler.go
Normal file
5
src/server/game/internal/handler.go
Normal file
@ -0,0 +1,5 @@
|
||||
package internal
|
||||
|
||||
func init() {}
|
||||
|
||||
func HandleClientReq(args []interface{}) {}
|
||||
27
src/server/game/internal/module.go
Normal file
27
src/server/game/internal/module.go
Normal file
@ -0,0 +1,27 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"server/GoUtil"
|
||||
"server/base"
|
||||
|
||||
"server/pkg/github.com/name5566/leaf/module"
|
||||
)
|
||||
|
||||
var (
|
||||
skeleton = base.NewSkeleton()
|
||||
ChanRPC = skeleton.ChanRPCServer
|
||||
)
|
||||
|
||||
type Module struct {
|
||||
*module.Skeleton
|
||||
}
|
||||
|
||||
func (m *Module) OnInit() {
|
||||
m.Skeleton = skeleton
|
||||
var a1 = []interface{}{}
|
||||
GoUtil.CallEvent("GameModuleOnInit", a1)
|
||||
}
|
||||
|
||||
func (m *Module) OnDestroy() {
|
||||
|
||||
}
|
||||
62
src/server/game/mod/activity/Activity.go
Normal file
62
src/server/game/mod/activity/Activity.go
Normal file
@ -0,0 +1,62 @@
|
||||
package activity
|
||||
|
||||
import (
|
||||
activityCfg "server/conf/activity"
|
||||
"server/msg"
|
||||
)
|
||||
|
||||
type ActivityMod struct {
|
||||
ActivityList []*ActivityInfo
|
||||
HHH []int
|
||||
}
|
||||
|
||||
type ActivityInfo struct {
|
||||
StartT int64
|
||||
EndT int64
|
||||
Id int
|
||||
Type int
|
||||
Title string
|
||||
Name string
|
||||
Info interface{}
|
||||
}
|
||||
|
||||
const ()
|
||||
|
||||
func (a *ActivityMod) InitData() {
|
||||
ActiveList := activityCfg.GetActivityList()
|
||||
var List []*ActivityInfo
|
||||
for _, v := range ActiveList {
|
||||
Info := &ActivityInfo{
|
||||
StartT: v.StartTime,
|
||||
EndT: v.EndTime,
|
||||
Id: v.Id,
|
||||
Type: v.Type,
|
||||
Title: v.Title,
|
||||
Name: v.Name,
|
||||
Info: nil,
|
||||
}
|
||||
List = append(List, Info)
|
||||
}
|
||||
a.ActivityList = List
|
||||
}
|
||||
|
||||
func (a *ActivityMod) GetActivityList() []*ActivityInfo {
|
||||
return a.ActivityList
|
||||
}
|
||||
|
||||
func (a *ActivityMod) BackData() *msg.ResAcitive {
|
||||
ActiveList := a.GetActivityList()
|
||||
ActivityList := make([]*msg.ActiveInfo, 0)
|
||||
for _, v := range ActiveList {
|
||||
ActivityList = append(ActivityList, &msg.ActiveInfo{
|
||||
Id: int32(v.Id),
|
||||
Type: int32(v.Type),
|
||||
StartTime: int32(v.StartT),
|
||||
EndTime: int32(v.EndT),
|
||||
Title: v.Title,
|
||||
})
|
||||
}
|
||||
return &msg.ResAcitive{
|
||||
ActiveList: ActivityList,
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user