diff --git a/awesomeProject/.idea/.gitignore b/awesomeProject/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/awesomeProject/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/awesomeProject/.idea/awesomeProject.iml b/awesomeProject/.idea/awesomeProject.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/awesomeProject/.idea/awesomeProject.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/awesomeProject/.idea/inspectionProfiles/Project_Default.xml b/awesomeProject/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..8d66637 --- /dev/null +++ b/awesomeProject/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/awesomeProject/.idea/modules.xml b/awesomeProject/.idea/modules.xml new file mode 100644 index 0000000..cc47053 --- /dev/null +++ b/awesomeProject/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/awesomeProject/.idea/vcs.xml b/awesomeProject/.idea/vcs.xml new file mode 100644 index 0000000..d843f34 --- /dev/null +++ b/awesomeProject/.idea/vcs.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/awesomeProject/awesomeProject/.idea/.gitignore b/awesomeProject/awesomeProject/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/awesomeProject/awesomeProject/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/awesomeProject/awesomeProject/.idea/awesomeProject.iml b/awesomeProject/awesomeProject/.idea/awesomeProject.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/awesomeProject/awesomeProject/.idea/awesomeProject.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/awesomeProject/awesomeProject/.idea/modules.xml b/awesomeProject/awesomeProject/.idea/modules.xml new file mode 100644 index 0000000..cc47053 --- /dev/null +++ b/awesomeProject/awesomeProject/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/awesomeProject/awesomeProject/go.mod b/awesomeProject/awesomeProject/go.mod new file mode 100644 index 0000000..71dc7b7 --- /dev/null +++ b/awesomeProject/awesomeProject/go.mod @@ -0,0 +1,7 @@ +module awesomeProject + +go 1.23.1 + +require github.com/go-sql-driver/mysql v1.8.1 + +require filippo.io/edwards25519 v1.1.0 // indirect diff --git a/awesomeProject/awesomeProject/go.sum b/awesomeProject/awesomeProject/go.sum new file mode 100644 index 0000000..19dbcec --- /dev/null +++ b/awesomeProject/awesomeProject/go.sum @@ -0,0 +1,4 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= diff --git a/awesomeProject/awesomeProject/leves/uploaded_level_file.txt b/awesomeProject/awesomeProject/leves/uploaded_level_file.txt new file mode 100644 index 0000000..8710910 --- /dev/null +++ b/awesomeProject/awesomeProject/leves/uploaded_level_file.txt @@ -0,0 +1,12 @@ +{ + "level_name": "第一关", + "difficulty": "easy", + "enemies": [ + {"type": "goblin", "count": 10}, + {"type": "troll", "count": 2} + ], + "boss": { + "type": "dragon", + "health": 5000 + } +} diff --git a/awesomeProject/awesomeProject/leves/xxxxsss b/awesomeProject/awesomeProject/leves/xxxxsss new file mode 100644 index 0000000..8710910 --- /dev/null +++ b/awesomeProject/awesomeProject/leves/xxxxsss @@ -0,0 +1,12 @@ +{ + "level_name": "第一关", + "difficulty": "easy", + "enemies": [ + {"type": "goblin", "count": 10}, + {"type": "troll", "count": 2} + ], + "boss": { + "type": "dragon", + "health": 5000 + } +} diff --git a/awesomeProject/awesomeProject/main.go b/awesomeProject/awesomeProject/main.go new file mode 100644 index 0000000..13f4c26 --- /dev/null +++ b/awesomeProject/awesomeProject/main.go @@ -0,0 +1,24 @@ +package main + +import ( + "database/sql" + _ "github.com/go-sql-driver/mysql" +) + +var db *sql.DB + +func main() { + openFileDate() + initweb() +} + +//var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890") + +//func randStr(n int) string { +// b := make([]rune, n) +// for i := range b { +// b[i] = letters[rand.Intn(len(letters))] +// } +// return string(b) +// +//} diff --git a/awesomeProject/awesomeProject/playerInfo.json b/awesomeProject/awesomeProject/playerInfo.json new file mode 100644 index 0000000..591c8d0 --- /dev/null +++ b/awesomeProject/awesomeProject/playerInfo.json @@ -0,0 +1,5 @@ +{ + "InviteGiftOpen": [false, false, false, false, false, false], + "RushGiftOpen": [false, false, false, false, false, false, false,false,false], + "OnlineGiftOpen": [false, false, false, false, false, false] +} \ No newline at end of file diff --git a/awesomeProject/awesomeProject/register.go b/awesomeProject/awesomeProject/register.go new file mode 100644 index 0000000..06ab7d0 --- /dev/null +++ b/awesomeProject/awesomeProject/register.go @@ -0,0 +1 @@ +package main diff --git a/awesomeProject/awesomeProject/web.go b/awesomeProject/awesomeProject/web.go new file mode 100644 index 0000000..adb4377 --- /dev/null +++ b/awesomeProject/awesomeProject/web.go @@ -0,0 +1,1039 @@ +package main + +import ( + "database/sql" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "log" + "math/rand" + "net/http" + "os" + "time" +) + +func initweb() { + var err error + db, err = sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/test") + if err != nil { + log.Fatal("数据库连接失败: ", err) + } + defer db.Close() + + err = db.Ping() + if err != nil { + log.Fatal("数据库连接不可用: ", err) + } + log.Println("数据库连接") + mux := http.NewServeMux() + //mux.HandleFunc("/login", login) + mux.HandleFunc("/register", register) + mux.HandleFunc("/get_user_Scends", get_user_Scends) + mux.HandleFunc("/change_player_data", change_player_data) + mux.HandleFunc("/getAllLevelNamesHandler", getAllLevelNamesHandler) + mux.HandleFunc("/uploadScore", uploadScore) + mux.HandleFunc("/fh", fh) + mux.HandleFunc("/get_allrank_Scends", get_allrank_Scends) + mux.HandleFunc("/uploadGoldRealRecord", uploadGoldRealRecord) + mux.HandleFunc("/uploadLevData", uploadLevData) + mux.HandleFunc("/getAnnouncement", getAnnouncement) + mux.HandleFunc("/getGoldRealRecord", getGoldRealRecord) + mux.HandleFunc("/getLevDataById", getLevDataById) + + mux.HandleFunc("/get_allLev_name", get_allLev_name) + log.Println("服务器启动,监听端口: 8080") + err = http.ListenAndServe(":8080", mux) + if err != nil { + log.Fatal("ListenAndServe: ", err) + } +} + +// 关卡物体数据 +type LevelItem struct { + Id string `json:"id"` + X float32 `json:"post_x"` + Y float32 `json:"post_y"` +} + +// 关卡数据 +type Level struct { + Id int `json:"id"` + LevelList []LevelItem `json:"LevelList"` + Name string `json:"name"` +} + +// 关卡名字全部数据 +type LevelList struct { + Name []string +} + +// 玩家数据 +type User struct { + Id int `json:"id"` + OpenId string `json:"openId"` + Username string `json:"username"` + Gold int `json:"gold"` + RandCode string `json:"randCode"` + WeekScore int `json:"weekScore"` + CustomLev int `json:"customLev"` + Invite int `json:"invite"` + InviteGiftOpen []bool `json:"inviteGiftOpen"` + RushGiftOpen []bool `json:"rushGiftOpen"` + OnlineGiftOpen []bool `json:"onlineGiftOpen"` + EveryLevRush []int `json:"everyLevRush"` + WeekGoldReal int `json:"weekGoldReal"` + PicUrl string `json:"picUrl"` +} + +var person Person + +// 本地json文件 +type Person struct { + InviteGiftOpen []bool `json:"InviteGiftOpen"` + RushGiftOpen []bool `json:"RushGiftOpen"` + OnlineGiftOpen []bool `json:"OnlineGiftOpen"` +} + +// 打开json文件函数 +func openFileDate() { + // 打开 JSON 文件 + jsonFile, err := os.Open("playerInfo.json") + if err != nil { + log.Fatalf("无法打开文件: %v", err) + } + defer jsonFile.Close() + + // 读取文件的内容 + byteValue, _ := ioutil.ReadAll(jsonFile) + + // 解析 JSON 数据到结构体 + err = json.Unmarshal(byteValue, &person) + if err != nil { + log.Fatalf("解析 JSON 数据失败: %v", err) + } +} + +// 用户登录信息 +type LoginMsg struct { + OpenId string `json:"openId"` + Username string `json:"username"` + PicUrl string `json:"picUrl"` +} + +// 用户列表 +type UserList struct { + UserList []User +} + +// 添加用户到 users +func (u *UserList) AddUser(user User) { + u.UserList = append(u.UserList, user) +} + +// 老板定义的返回数据,有待研究 +type Result struct { + Msg string `json:"msg"` + MsgCode int `json:"msgCode"` + Data interface{} `json:"data,omitempty"` +} + +// 初始化用户 +func initUser(loginMsg LoginMsg) (User, error) { + + return User{ + Id: 0, + OpenId: loginMsg.OpenId, + Username: loginMsg.Username, + PicUrl: loginMsg.PicUrl, // 初始化 PicUrl + Gold: 0, + RandCode: randStr(16), + WeekScore: 0, + CustomLev: 1, + Invite: 0, + InviteGiftOpen: person.InviteGiftOpen, + RushGiftOpen: person.RushGiftOpen, + OnlineGiftOpen: person.OnlineGiftOpen, + EveryLevRush: []int{}, + WeekGoldReal: 100000, + }, nil +} + +// 用户模板 +func fh(w http.ResponseWriter, r *http.Request) { + res := User{ + Id: 0, + OpenId: "", + Username: "", + PicUrl: "", // 初始化 PicUrl + Gold: 0, + RandCode: randStr(16), + WeekScore: 0, + CustomLev: 0, + Invite: 0, + InviteGiftOpen: person.InviteGiftOpen, + RushGiftOpen: person.RushGiftOpen, + OnlineGiftOpen: person.OnlineGiftOpen, + EveryLevRush: []int{}, + WeekGoldReal: 0, + } + json.NewEncoder(w).Encode(res) +} + +// 随机字符串生成函数 +func randStr(length int) string { + const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) + b := make([]byte, length) + for i := range b { + b[i] = charset[seededRand.Intn(len(charset))] + } + return string(b) +} + +// 用户注册处理函数 +func register(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + if r.Method != http.MethodPost { + http.Error(w, "只支持POST请求", http.StatusBadRequest) + return + } + + // 读取请求体 + body, err := io.ReadAll(r.Body) // 使用 io.ReadAll 替代 ioutil.ReadAll + if err != nil { + log.Println("读取请求体失败:", err) + http.Error(w, "读取请求体失败", http.StatusBadRequest) + return + } + + // 打印请求体内容 + //log.Println("请求体:", string(body)) + + //解析请求体 + var loginMsg LoginMsg + err = json.Unmarshal(body, &loginMsg) + if err != nil { + log.Println(r.Body) + log.Println("请求体解析失败:", err) + http.Error(w, "请求体解析失败", http.StatusBadRequest) + return + } + + //判断数据库里面是否有这条数据,有就返回这条数据 + var user User + var inviteGiftOpen, rushGiftOpen, onlineGiftOpen []byte + var everyLevRushJSON []byte + err = db.QueryRow("SELECT id, openId, username, gold, randCode, weekScore, customLev, invite, inviteGiftOpen, rushGiftOpen, onlineGiftOpen, everyLevRush, weekGoldReal FROM user WHERE openId = ?", loginMsg.OpenId). + Scan(&user.Id, &user.OpenId, &user.Username, &user.Gold, &user.RandCode, &user.WeekScore, &user.CustomLev, &user.Invite, &inviteGiftOpen, &rushGiftOpen, &onlineGiftOpen, &everyLevRushJSON, &user.WeekGoldReal) + if err == sql.ErrNoRows { + user, _ := initUser(loginMsg) + //数据库没有这个条消息,在数据库里面插入一条默认消息 + // 将复杂类型(如 []bool 和 map[int]int)序列化为 JSON 字符串 + inviteGiftOpenStr, _ := json.Marshal(user.InviteGiftOpen) + rushGiftOpenStr, _ := json.Marshal(user.RushGiftOpen) + onlineGiftOpenStr, _ := json.Marshal(user.OnlineGiftOpen) + everyLevRushStr, _ := json.Marshal(user.EveryLevRush) + insertQuery := "INSERT INTO user (id,openId, username, gold, randCode, weekScore, customLev, invite, inviteGiftOpen, rushGiftOpen, onlineGiftOpen, everyLevRush, weekGoldReal, picUrl) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)" + //stmt, _ := db.Prepare(insertQuery) + db.Exec(insertQuery, user.Id, user.OpenId, user.Username, user.Gold, user.RandCode, user.WeekScore, user.CustomLev, user.Invite, inviteGiftOpenStr, rushGiftOpenStr, onlineGiftOpenStr, everyLevRushStr, user.WeekGoldReal, user.PicUrl) + json.NewEncoder(w).Encode(user) + //defer stmt.Close() + return + } else if err != nil { + return + } else { + // 处理数据库中的 JSON 字符串并解析成 Go 中的类型 + json.Unmarshal(inviteGiftOpen, &user.InviteGiftOpen) + json.Unmarshal(rushGiftOpen, &user.RushGiftOpen) + json.Unmarshal(onlineGiftOpen, &user.OnlineGiftOpen) + json.Unmarshal(everyLevRushJSON, &user.EveryLevRush) + user.RandCode = randStr(16) + json.NewEncoder(w).Encode(user) + } +} + +/********************************************************************玩家数据改变请求服务器*********************************************************************************/ +// 用户改变用户数据函数 +func change_player_data(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + if r.Method != http.MethodPost { + http.Error(w, "只支持POST请求", http.StatusBadRequest) + return + } + + // 读取请求体 + body, err := io.ReadAll(r.Body) // 使用 io.ReadAll 替代 ioutil.ReadAll + if err != nil { + log.Println("读取请求体失败:", err) + http.Error(w, "读取请求体失败", http.StatusBadRequest) + return + } + + // 打印请求体内容 + log.Println("请求体:", string(body)) + + //解析请求体 + var user User + err = json.Unmarshal(body, &user) + if err != nil { + log.Println(r.Body) + log.Println("请求体解析失败:", err) + http.Error(w, "请求体解析失败", http.StatusBadRequest) + return + } + + //var userExists bool + //err = db.QueryRow("SELECT EXISTS(SELECT 1 FROM user WHERE openId = ?)", user.OpenId).Scan(&userExists) + + //数据库没有这个条消息,在数据库里面插入一条默认消息 + // 将复杂类型(如 []bool 和 map[int]int)序列化为 JSON 字符串 + inviteGiftOpenStr, _ := json.Marshal(user.InviteGiftOpen) + rushGiftOpenStr, _ := json.Marshal(user.RushGiftOpen) + onlineGiftOpenStr, _ := json.Marshal(user.OnlineGiftOpen) + everyLevRushStr, _ := json.Marshal(user.EveryLevRush) + insertQuery := "UPDATE user SET username=?, gold=?, customLev=?, invite=?, inviteGiftOpen=?, rushGiftOpen=?, onlineGiftOpen=?, everyLevRush=?,weekGoldReal=?, picUrl=? WHERE openId = ?" + exec, err := db.Exec(insertQuery, user.Username, user.Gold, user.CustomLev, user.Invite, inviteGiftOpenStr, rushGiftOpenStr, onlineGiftOpenStr, everyLevRushStr, user.WeekGoldReal, user.PicUrl, user.OpenId) + if err != nil { + fmt.Println(err, exec) + return + } + json.NewEncoder(w).Encode(user) + return + +} + +/***************************************************************************关卡排行榜数据获取****************************************************************************/ + +type liveMsg struct { + Id int `json:"id"` + OpenId string `json:"openId"` +} + +// 获取所有关卡名字 +func getAllLevelNamesHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + if r.Method != http.MethodPost { + http.Error(w, "只支持 POST 请求", http.StatusMethodNotAllowed) + return + } + + // 查询数据库获取所有关卡名称 + rows, err := db.Query("SELECT name FROM level") + if err != nil { + log.Println(err) + res := map[string]string{"message": "数据库查询失败", "status": "failure"} + w.WriteHeader(http.StatusInternalServerError) + json.NewEncoder(w).Encode(res) + return + } + defer rows.Close() + + // 存储关卡名称的切片 + var levelNames []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + log.Println(err) + res := map[string]string{"message": "数据读取失败", "status": "failure"} + w.WriteHeader(http.StatusInternalServerError) + json.NewEncoder(w).Encode(res) + return + } + levelNames = append(levelNames, name) + } + + // 检查是否有错误 + if err := rows.Err(); err != nil { + log.Println(err) + res := map[string]string{"message": "结果集读取失败", "status": "failure"} + w.WriteHeader(http.StatusInternalServerError) + json.NewEncoder(w).Encode(res) + return + } + + // 直接返回关卡名称数组 + json.NewEncoder(w).Encode(levelNames) +} + +// 获取关卡分数排行榜名次 +func get_user_Scends(w http.ResponseWriter, r *http.Request) { + //SELECT id,name FROM levdata WHERE id = 2 + log.Println("=====") + if r.Method != http.MethodPost { + http.Error(w, "只支持 POST 请求", http.StatusMethodNotAllowed) + return + } + + // 创建一个 RequestData 实例,用于存储解析后的数据 + var requestData liveMsg + + // 解析 JSON 数据 + err := json.NewDecoder(r.Body).Decode(&requestData) + if err != nil { + http.Error(w, "解析 JSON 数据失败", http.StatusBadRequest) + return + } + levename := "" + id := 0 + err = db.QueryRow("SELECT id,name FROM levdata WHERE id = ?", requestData.Id).Scan(&id, &levename) + log.Println(err) + rows, err := db.Query("SELECT * FROM " + levename + " ORDER BY score DESC LIMIT 3;") + if err != nil { + log.Println(err) + return + } + + var userlist UserList + for rows.Next() { + var user User + var unusedField1, unusedField2 interface{} + err := rows.Scan(&unusedField1, &user.OpenId, &user.WeekScore, &unusedField2) + if err != nil { + log.Println(err) + return + } + userlist.AddUser(user) + } + log.Println(userlist) + json.NewEncoder(w).Encode(userlist) +} + +/*********************************************************************上传分数********************************************************************************************/ + +// LevRankMsg 请求排行榜数据结构 +type ScoreUploadMsg struct { + OpenId string `json:"openId"` + Name string `json:"name"` // LevelName 是字符串 + Score int `json:"score"` +} + +type BackRankInt struct { + RankInt int `json:"rankInt"` +} + +// 确保 levdata 表中存在关卡记录 +func ensureLevelDataExists(levelName string) error { + var count int + // 查询 levdata 表中是否已经存在对应的关卡名称 + err := db.QueryRow("SELECT COUNT(*) FROM levdata WHERE name = ?", levelName).Scan(&count) + if err != nil { + return err + } + + // 如果不存在该关卡名称,则插入新的记录 + if count == 0 { + insertLevelDataQuery := "INSERT INTO levdata (name) VALUES (?)" + _, err = db.Exec(insertLevelDataQuery, levelName) + if err != nil { + return err + } + log.Printf("新关卡已插入到 levdata 表: %s", levelName) + } + return nil +} + +// 上传分数到关卡并创建的处理函数 +func uploadScore(w http.ResponseWriter, r *http.Request) { + log.Println("=====") + if r.Method != http.MethodPost { + http.Error(w, "只支持 POST 请求", http.StatusMethodNotAllowed) + return + } + + // 解析请求体中的 JSON 数据 + var scoreUploadMsg ScoreUploadMsg + err := json.NewDecoder(r.Body).Decode(&scoreUploadMsg) + if err != nil { + log.Println("解析 JSON 数据失败:", err) + http.Error(w, "请求体解析失败", http.StatusBadRequest) + return + } + + // 检查是否提供了 OpenId 和 LevelName + if scoreUploadMsg.OpenId == "" || scoreUploadMsg.Name == "" { + http.Error(w, "OpenId 和 LevelName 不能为空", http.StatusBadRequest) + return + } + + // 确保 levdata 表中有该关卡名称 + err = ensureLevelDataExists(scoreUploadMsg.Name) + if err != nil { + log.Println("检查或插入关卡失败:", err) + http.Error(w, "检查或插入关卡失败", http.StatusInternalServerError) + return + } + + // 使用 LevelName 作为表名 + levelTable := scoreUploadMsg.Name + + // 动态创建关卡表的 SQL 语句,移除 openid 作为主键,使用 id 作为自增主键 + createTableQuery := fmt.Sprintf(` + CREATE TABLE IF NOT EXISTS %s ( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + openId VARCHAR(255) NOT NULL, + score INT NOT NULL, + createtime TIMESTAMP DEFAULT CURRENT_TIMESTAMP + )`, levelTable) + + // 执行创建表的 SQL 语句 + _, err = db.Exec(createTableQuery) + if err != nil { + log.Println("关卡表创建失败:", err) + http.Error(w, "关卡表创建失败", http.StatusInternalServerError) + return + } + + // 插入新分数的 SQL 语句,每次插入新记录 + insertScoreQuery := fmt.Sprintf(` + INSERT INTO %s (openId, score) + VALUES (?, ?) + `, levelTable) + + // 执行插入操作 + _, err = db.Exec(insertScoreQuery, scoreUploadMsg.OpenId, scoreUploadMsg.Score) + if err != nil { + log.Println("插入分数失败:", err) + http.Error(w, "插入分数失败", http.StatusInternalServerError) + return + } + + // 2. 查询表2中玩家在该关卡的最高分 + // 获取当前时间 + now := time.Now() + // 加载中国时区 (CST, UTC+8) + location, err := time.LoadLocation("Asia/Shanghai") + if err != nil { + fmt.Println("加载时区失败:", err) + return + } + // 将当前时间转换为中国时区时间 + localTime := now.In(location) + // 转换为 UTC 时间 + utcTime := localTime.UTC() + + // 打印转换后的本地时间 + fmt.Println("当前时间 (中国标准时间 CST):", localTime) + + var currentHighScore sql.NullInt64 + query := ` + SELECT score + FROM weekopenidlev + WHERE openId = ? AND levelName = ? AND YEARWEEK(createtime, 1) = YEARWEEK(?, 1)` + err = db.QueryRow(query, scoreUploadMsg.OpenId, levelTable, utcTime).Scan(¤tHighScore) + if err != nil && err != sql.ErrNoRows { + log.Println("查询表2中的当前最高分失败:", err) + http.Error(w, "查询表2中的当前最高分失败", http.StatusInternalServerError) + return + } + + // 判断表2中是否为空,或者新分数大于表2中的最高分 + if !currentHighScore.Valid || scoreUploadMsg.Score > int(currentHighScore.Int64) { + // 如果表2为空或者新分数大于当前最高分,则更新表2 + updateWeeklyHighScoreQuery := ` + INSERT INTO weekopenidlev (openId, levelName, score, createtime) + VALUES (?, ?, ?, ?) + ON DUPLICATE KEY UPDATE score = GREATEST(score, ?)` + _, err = db.Exec(updateWeeklyHighScoreQuery, scoreUploadMsg.OpenId, levelTable, scoreUploadMsg.Score, utcTime, scoreUploadMsg.Score) + if err != nil { + log.Println("更新表2失败:", err) + http.Error(w, "更新表2失败", http.StatusInternalServerError) + return + } + + // 更新表3,如果表3中没有openId的记录,插入一条新记录,否则更新总分 + updateWeeklyTotalQuery := ` + INSERT INTO weekscore (openId, totalScore, createtime) + VALUES (?, (SELECT SUM(score) FROM weekopenidlev WHERE openId = ? AND YEARWEEK(createtime, 1) = YEARWEEK(?, 1)), ?) + ON DUPLICATE KEY UPDATE totalScore = (SELECT SUM(score) FROM weekopenidlev WHERE openId = ? AND YEARWEEK(createtime, 1) = YEARWEEK(?, 1))` + _, err = db.Exec(updateWeeklyTotalQuery, scoreUploadMsg.OpenId, scoreUploadMsg.OpenId, utcTime, utcTime, scoreUploadMsg.OpenId, utcTime) + if err != nil { + log.Println("更新表3失败:", err) + http.Error(w, "更新表3失败", http.StatusInternalServerError) + return + } + + log.Println("玩家的最高分和总分已更新") + } else { + log.Println("玩家的分数未超过当前最高分,无需更新") + } + + // 查询玩家的排名 + rankQuery := fmt.Sprintf(` + SELECT COUNT(*) + 1 AS `+"`rank`"+` + FROM %s + WHERE score > ?`, levelTable) + + var backRankInt BackRankInt + err = db.QueryRow(rankQuery, scoreUploadMsg.Score).Scan(&backRankInt.RankInt) + if err != nil { + log.Println("查询排名失败:", err) + http.Error(w, "查询排名失败", http.StatusInternalServerError) + return + } + json.NewEncoder(w).Encode(backRankInt) +} + +/************************************************************************************提现记录*******************************************************************************/ +type GoldRealMsg struct { + OpenId string `json:"openId"` + RealRecord map[string]string `json:"realRecord"` + Money int `json:"money"` + State int `json:"state"` +} + +// 上传提现记录的处理函数 +func uploadGoldRealRecord(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "只支持 POST 请求", http.StatusMethodNotAllowed) + return + } + + // 解析请求体的 JSON 数据 + var goldRealMsg GoldRealMsg + err := json.NewDecoder(r.Body).Decode(&goldRealMsg) + if err != nil { + log.Println("请求体解析失败:", err) + http.Error(w, "请求体解析失败", http.StatusBadRequest) + return + } + + // 将 RealRecord 转换为 JSON 格式字符串 + realRecordJSON, err := json.Marshal(goldRealMsg.RealRecord) + if err != nil { + log.Println("RealRecord 转换为 JSON 失败:", err) + http.Error(w, "数据转换失败", http.StatusInternalServerError) + return + } + + // 插入或更新 GoldReal 表的 SQL 语句 + insertOrUpdateQuery := ` + INSERT INTO goldreal (openId, realRecord, money, state) + VALUES (?, ?, ?, ?) + ON DUPLICATE KEY UPDATE + realRecord = VALUES(realRecord), + money = VALUES(money), + state = VALUES(state)` + + // 执行插入或更新操作 + _, err = db.Exec(insertOrUpdateQuery, goldRealMsg.OpenId, string(realRecordJSON), goldRealMsg.Money, goldRealMsg.State) + if err != nil { + log.Println("插入或更新记录失败:", err) + http.Error(w, "插入或更新记录失败", http.StatusInternalServerError) + return + } + + // 返回成功消息 + //response := map[string]string{"message": "提现记录上传成功"} + json.NewEncoder(w).Encode(nil) +} + +// 获取提现记录 +func getGoldRealRecord(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "只支持 POST 请求", http.StatusMethodNotAllowed) + return + } + + // 解析请求体的 JSON 数据 + var goldRealMsg GoldRealMsg + err := json.NewDecoder(r.Body).Decode(&goldRealMsg) + if err != nil { + log.Println("请求体解析失败:", err) + http.Error(w, "请求体解析失败", http.StatusBadRequest) + return + } + + // 查询数据库,state 必须为 0 + query := "SELECT openId, realRecord, money, state FROM GoldReal WHERE openId = ? AND state = 0" + rows, err := db.Query(query, goldRealMsg.OpenId) + if err != nil { + log.Println("数据库查询失败:", err) + http.Error(w, "数据库查询失败", http.StatusInternalServerError) + return + } + defer rows.Close() + + // 构建返回的记录列表 + var records []GoldRealMsg + for rows.Next() { + var record GoldRealMsg + var realRecordStr string + + err := rows.Scan(&record.OpenId, &realRecordStr, &record.Money, &record.State) + if err != nil { + log.Println("扫描数据库记录失败:", err) + http.Error(w, "数据扫描失败", http.StatusInternalServerError) + return + } + + // 将 realRecord 字符串反序列化为 map[string]string + err = json.Unmarshal([]byte(realRecordStr), &record.RealRecord) + if err != nil { + log.Println("反序列化 realRecord 失败:", err) + http.Error(w, "数据解析失败", http.StatusInternalServerError) + return + } + + records = append(records, record) + } + + // 如果没有找到记录,返回空数组 + if len(records) == 0 { + records = []GoldRealMsg{} + } + + // 返回查询到的记录 + json.NewEncoder(w).Encode(records) +} + +/********************************************************************上传关卡萌宠信息数据到数据库的处理函数***************************************************************************/ +type PetInfo struct { + Res string `json:"res"` // 萌宠预设体 + Post_x float32 `json:"post_x"` // X 位置z + Post_y float32 `json:"post_y"` // Y 位置 +} + +// 关卡信息 +type LevData struct { + Id int `json:"id"` // 关卡 ID + Name string `json:"name"` // 关卡名称 + PetInfoList []PetInfo `json:"petInfoList"` // 关卡中的萌宠信息 +} + +// 关卡信息 +type IsSuccess struct { + Msg string `json:"msg"` + Success bool `json:"success"` +} + +// 上传关卡萌宠信息数据到数据库的处理函数 +func uploadLevData(w http.ResponseWriter, r *http.Request) { + // 确保只接受 POST 请求 + if r.Method != http.MethodPost { + http.Error(w, "只支持 POST 请求", http.StatusMethodNotAllowed) + return + } + + // 解析请求体中的 JSON 数据 + var levData LevData + err := json.NewDecoder(r.Body).Decode(&levData) + if err != nil { + log.Println("解析 JSON 数据失败:", err) + http.Error(w, "请求体解析失败", http.StatusBadRequest) + return + } + + // 验证输入数据 + if levData.Name == "" { + log.Println("关卡名称不能为空") + http.Error(w, "关卡名称不能为空", http.StatusBadRequest) + return + } + + // 使用 id 来判断关卡号 + levelNumber := levData.Id + if levelNumber <= 0 { + log.Println("关卡 ID 不合法") + http.Error(w, "关卡 ID 不合法", http.StatusBadRequest) + return + } + + var isSuccess IsSuccess + // 判断前面所有关卡是否都已经创建 + for i := 1; i < levelNumber; i++ { + checkLevelQuery := `SELECT COUNT(*) FROM levdata WHERE id = ?` + var count int + err = db.QueryRow(checkLevelQuery, i).Scan(&count) + if err != nil { + log.Println("查询关卡信息失败:", err) + http.Error(w, "查询关卡信息失败", http.StatusInternalServerError) + return + } + + if count == 0 { + // 如果第 i 关不存在,返回错误信息 + isSuccess.Msg = fmt.Sprintf("第%d关还没有创建", i) + isSuccess.Success = false + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(isSuccess) + return + } + } + + // 将 PetInfoList 序列化为 JSON 格式字符串 + petInfoListJSON, err := json.Marshal(levData.PetInfoList) + if err != nil { + log.Println("PetInfoList 转换为 JSON 失败:", err) + http.Error(w, "数据转换失败", http.StatusInternalServerError) + return + } + + // 检查数据库中是否已有相同的 id + checkIdQuery := `SELECT COUNT(*) FROM levdata WHERE id = ?` + var count int + err = db.QueryRow(checkIdQuery, levData.Id).Scan(&count) + if err != nil { + log.Println("查询关卡信息失败:", err) + http.Error(w, "查询关卡信息失败", http.StatusInternalServerError) + return + } + + if count > 0 { + // 如果 id 存在,更新现有记录 + updateLevDataQuery := ` + UPDATE levdata SET name = ?, petInfoList = ? WHERE id = ?` + _, err = db.Exec(updateLevDataQuery, levData.Name, string(petInfoListJSON), levData.Id) + if err != nil { + log.Println("更新关卡信息失败:", err) + http.Error(w, "更新关卡信息失败", http.StatusInternalServerError) + return + } + // 如果第 i 关不存在,返回错误信息 + isSuccess.Msg = fmt.Sprintf("%s更新萌宠信息成功", levData.Name) + isSuccess.Success = true + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(isSuccess) + log.Println("关卡信息更新成功") + } else { + // 如果 id 不存在,插入新的记录 + insertLevDataQuery := ` + INSERT INTO levdata (id, name, petInfoList) + VALUES (?, ?, ?)` + _, err = db.Exec(insertLevDataQuery, levData.Id, levData.Name, string(petInfoListJSON)) + if err != nil { + log.Println("插入关卡信息失败:", err) + http.Error(w, "插入关卡信息失败", http.StatusInternalServerError) + return + } + log.Println("关卡信息插入成功") + } + + // 返回成功消息 + isSuccess.Msg = fmt.Sprintf("%s关卡上传成功", levData.Name) + isSuccess.Success = true + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(isSuccess) +} + +// 根据关卡 id 获取关卡信息的处理函数 +func getLevDataById(w http.ResponseWriter, r *http.Request) { + // 确保只接受 POST 请求 + if r.Method != http.MethodPost { + http.Error(w, "只支持 POST 请求", http.StatusMethodNotAllowed) + return + } + + // 解析请求体中的 JSON 数据 + var loginMsg liveMsg + err := json.NewDecoder(r.Body).Decode(&loginMsg) + if err != nil { + log.Println("请求体解析失败:", err) + http.Error(w, "请求体解析失败", http.StatusBadRequest) + return + } + + // 查询数据库,获取对应 id 的关卡信息 + query := `SELECT id, name, petInfoList FROM levdata WHERE id = ?` + var levData LevData + var petInfoListJSON string + + err = db.QueryRow(query, loginMsg.Id).Scan(&levData.Id, &levData.Name, &petInfoListJSON) + if err != nil { + if err == sql.ErrNoRows { + log.Println("未找到关卡信息") + http.Error(w, "关卡信息未找到", http.StatusNotFound) + } else { + log.Println("查询关卡信息失败:", err) + http.Error(w, "查询关卡信息失败", http.StatusInternalServerError) + } + return + } + + // 将 petInfoList 从 JSON 字符串反序列化为结构体 + err = json.Unmarshal([]byte(petInfoListJSON), &levData.PetInfoList) + if err != nil { + log.Println("PetInfoList 反序列化失败:", err) + http.Error(w, "PetInfoList 数据解析失败", http.StatusInternalServerError) + return + } + + // 将关卡信息返回给客户端 + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(levData) +} + +//获取所有关卡id和关卡名字 +/*************************************************************************获取所有关卡的id和name*****************************************************************************************/ + +// Level 结构体包含关卡的 ID 和 Name +type LevelData struct { + LevID int `json:"levId"` + LevName string `json:"levName"` +} + +// 数据响应格式,键为关卡的 ID,值为 Level 结构体 +type LevelResponse []LevelData + +// 从数据库获取关卡信息 +func getLevelsFromDB() (LevelResponse, error) { + // 查询关卡的 id 和 name + query := "SELECT id, name FROM levdata" + rows, err := db.Query(query) + if err != nil { + return nil, err + } + defer rows.Close() + + // 保存查询到的关卡信息 + var levels LevelResponse + + // 迭代查询结果 + for rows.Next() { + var levelData LevelData + err := rows.Scan(&levelData.LevID, &levelData.LevName) + if err != nil { + return nil, err + } + // 将查询到的 LevelData 添加到切片中 + levels = append(levels, levelData) + } + + // 检查是否有查询错误 + if err = rows.Err(); err != nil { + return nil, err + } + + return levels, nil +} + +// 处理客户端请求,返回 JSON 格式的关卡信息 +func get_allLev_name(w http.ResponseWriter, r *http.Request) { + levels, err := getLevelsFromDB() + if err != nil { + http.Error(w, "Error fetching levels from database", http.StatusInternalServerError) + return + } + + // 设置响应头,告知客户端返回的数据是 JSON 格式 + w.Header().Set("Content-Type", "application/json") + + // 将 LevelResponse 序列化为 JSON 并写入响应 + if err := json.NewEncoder(w).Encode(levels); err != nil { + http.Error(w, "Error encoding JSON", http.StatusInternalServerError) + return + } +} + +/*************************************************************************公告信息**********************************************************************************************************/ + +// Announcement 公告结构体 +type Announcement struct { + Title string `json:"title"` + Content string `json:"content"` + Date string `json:"date"` +} + +// 获取公告的处理函数 +func getAnnouncement(w http.ResponseWriter, r *http.Request) { + // 解析公告信息 + query := "SELECT title, content, date FROM announce ORDER BY date DESC LIMIT 1" + row := db.QueryRow(query) + + // 解析公告信息 + var announcement Announcement + err := row.Scan(&announcement.Title, &announcement.Content, &announcement.Date) + if err != nil { + if err == sql.ErrNoRows { + http.Error(w, "没有找到公告", http.StatusNotFound) + log.Println("没有找到公告") + } else { + log.Println("查询公告失败:", err) + http.Error(w, "查询公告失败", http.StatusInternalServerError) + } + return + } + + // 返回公告信息给客户端 + w.Header().Set("Content-Type", "application/json") + err = json.NewEncoder(w).Encode(announcement) + if err != nil { + log.Println("返回公告信息失败:", err) + http.Error(w, "返回公告信息失败", http.StatusInternalServerError) + } else { + log.Println("公告成功返回给客户端") + } +} + +/**************************************************************************邮件****************************************************************************************************************/ +// 邮件结构体 +type Mail struct { + OpenID string `json:"open_id"` // 用户的 openId + SendGold string `json:"send_gold"` // 奖励内容 + SendAt string `json:"send_at"` // 发送时间 + SendEnd string `json:"send_end"` // 结束时间 + IsRead bool `json:"is_read"` // 是否已读 +} + +// 处理发送邮件请求 +func sendMailHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "只支持 POST 请求", http.StatusMethodNotAllowed) + return + } + + var mail Mail + // 解析客户端发来的 JSON 数据 + err := json.NewDecoder(r.Body).Decode(&mail) + if err != nil { + http.Error(w, "无效的请求数据", http.StatusBadRequest) + return + } + + // 获取当前时间,设置邮件的发送时间和过期时间(例如7天后) + mail.SendAt = time.Now().Format("2006-01-02 15:04:05") + mail.SendEnd = time.Now().AddDate(0, 0, 7).Format("2006-01-02 15:04:05") + mail.IsRead = false // 初始邮件未读 + + // 插入邮件到数据库 + query := "INSERT INTO mails (openId, send_gold, send_at, send_end, is_read) VALUES (?, ?, ?, ?, false)" + _, err = db.Exec(query, mail.OpenID, mail.SendGold, mail.SendAt, mail.SendEnd) + if err != nil { + log.Printf("邮件发送失败: %v", err) + http.Error(w, "邮件发送失败", http.StatusInternalServerError) + return + } + + // 返回给客户端发送成功的消息 + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(map[string]string{"message": "邮件发送成功"}) +} + +/****************************************************************************总分数排行榜*************************************************************************************************/ + +// 获取关卡分数排行榜名次 +func get_allrank_Scends(w http.ResponseWriter, r *http.Request) { + + query := `SELECT openId, totalScore FROM weekscore ORDER BY totalScore DESC LIMIT 10` + rows, err := db.Query(query) + if err != nil { + http.Error(w, "查询排行榜数据失败", http.StatusInternalServerError) + log.Println("查询排行榜数据失败:", err) + return + } + + var userlist UserList + for rows.Next() { + var user User + err := rows.Scan(&user.OpenId, &user.WeekScore) + if err != nil { + log.Println(err) + return + } + userlist.AddUser(user) + } + log.Println(userlist) + json.NewEncoder(w).Encode(userlist) +}