package core import ( "anvil/shared" "errors" "net" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" ) /* func (gs *AeGameServer) LobbyCheckIn(ip net.IP, inSocketPort int32) { gs.lock.Lock() defer gs.lock.Unlock() gs.LobbyIp = ip gs.LobbyPort = inSocketPort } func (gs *AeGameServer) GetUrlLobbyChekedIn() string { gs.lock.Lock() defer gs.lock.Unlock() if len(gs.LobbyIp) != 0 { return fmt.Sprintf("%s:%d", gs.LobbyIp.String(), gs.LobbyPort) } else { return "" } } func (gs *AeGameServer) WorldCheckIn(ip net.IP, inSocketPort int32) { gs.lock.Lock() defer gs.lock.Unlock() gs.WorldIp = ip gs.WorldPort = inSocketPort } func (gs *AeGameServer) GetUrlWorldChekedIn() string { gs.lock.Lock() defer gs.lock.Unlock() if len(gs.WorldIp) != 0 { return fmt.Sprintf("%s:%d", gs.WorldIp.String(), gs.LobbyPort) } else { return "" } } */ func (gs *AeGameServer) FindDsCheckedIn(Type int32, Version string) string { gs.lock.Lock() defer gs.lock.Unlock() var priority float32 = 0 url := "" for _, s := range gs.sockets { if s.IsCompatible(Type, Version) { if tmpUrl := s.GetUrlChekedIn(); tmpUrl != "" { tmpPriority := s.GetPriority() if tmpPriority >= priority { url = tmpUrl priority = tmpPriority } } } } return url } func (tx *transaction) Hello() shared.RPCReturnType { tx.gs.Logger.Println("hello, too") return shared.MakeRPCReturn("hello, too.", nil) } func externalIP() (net.IP, error) { ifaces, err := net.Interfaces() if err != nil { return nil, err } for _, iface := range ifaces { if iface.Flags&net.FlagUp == 0 { continue // interface down } if iface.Flags&net.FlagLoopback != 0 { continue // loopback interface } addrs, err := iface.Addrs() if err != nil { return nil, err } for _, addr := range addrs { var ip net.IP switch v := addr.(type) { case *net.IPNet: ip = v.IP case *net.IPAddr: ip = v.IP } if ip == nil || ip.IsLoopback() { continue } ip = ip.To4() if ip == nil { continue // not an ipv4 address } return ip, nil } } return nil, errors.New("are you connected to the network?") } /* func (tx *transaction) LobbyCheckIn(inSocketPort int32) shared.RPCReturnType { // list.Append(test) tx.gs.Logger.Printf("remoteaddr %s : %d", tx.r.RemoteAddr, inSocketPort) ip, _, err := net.SplitHostPort(tx.r.RemoteAddr) if err != nil { tx.gs.Logger.Printf("userip: %q is not IP:port", tx.r.RemoteAddr) return shared.MakeRPCReturn(nil, errors.New("IP invalid")) } userIP := net.ParseIP(ip) if userIP == nil { tx.gs.Logger.Printf("userip: %q is not IP:port", tx.r.RemoteAddr) return shared.MakeRPCReturn(nil, errors.New("IP invalid")) } if userIP.IsLoopback() { if tmpIp, err := externalIP(); err == nil { userIP = tmpIp } else { return shared.MakeRPCReturn(nil, errors.New("IP invalid")) } } tx.gs.LobbyCheckIn(userIP, inSocketPort) return shared.MakeRPCReturn("lobby checked in.", nil) } func (tx *transaction) WorldCheckIn(inSocketPort int32) shared.RPCReturnType { // list.Append(test) tx.gs.Logger.Printf("remoteaddr %s : %d", tx.r.RemoteAddr, inSocketPort) ip, _, err := net.SplitHostPort(tx.r.RemoteAddr) if err != nil { tx.gs.Logger.Printf("userip: %q is not IP:port", tx.r.RemoteAddr) return shared.MakeRPCReturn(nil, errors.New("IP invalid")) } userIP := net.ParseIP(ip) if userIP == nil { tx.gs.Logger.Printf("userip: %q is not IP:port", tx.r.RemoteAddr) return shared.MakeRPCReturn(nil, errors.New("IP invalid")) } if userIP.IsLoopback() { if tmpIp, err := externalIP(); err == nil { userIP = tmpIp } else { return shared.MakeRPCReturn(nil, errors.New("IP invalid")) } } tx.gs.WorldCheckIn(userIP, inSocketPort) return shared.MakeRPCReturn("world checked in.", nil) } */ func (tx *transaction) GetCheckedIn(Type int32, Version string) shared.RPCReturnType { // url := tx.gs.GetUrlLobbyChekedIn() url := tx.gs.FindDsCheckedIn(Type, Version) tx.gs.Logger.Println("lobby url checked in : ", url) if url == "" { return shared.MakeRPCReturn(nil, errors.New("no url")) } else { return shared.MakeRPCReturn(url, nil) } } // func (tx *transaction) GetLobbyCheckedIn() shared.RPCReturnType { // // url := tx.gs.GetUrlLobbyChekedIn() // url := tx.gs.FindDsCheckedIn(2) // tx.gs.Logger.Println("lobby url checked in : ", url) // if url == "" { // return shared.MakeRPCReturn(nil, errors.New("no url")) // } else { // return shared.MakeRPCReturn(url, nil) // } // } // func (tx *transaction) GetWorldCheckedIn() shared.RPCReturnType { // // url := tx.gs.GetUrlWorldChekedIn() // url := tx.gs.FindDsCheckedIn(1) // tx.gs.Logger.Println("world url checked in : ", url) // if url == "" { // return shared.MakeRPCReturn(nil, errors.New("no url")) // } else { // return shared.MakeRPCReturn(url, nil) // } // } func (tx *transaction) ReadDB(collection string, _id interface{}) shared.RPCReturnType { raw, err := tx.gs.mongoClient.FindOneAndUpdate(shared.CollectionName(collection), bson.M{"_id": _id}, bson.M{ "$setOnInsert": bson.M{"_id": _id}, }, options.FindOneAndUpdate().SetProjection(bson.M{"_id": 0, "_ts": 0}), options.FindOneAndUpdate().SetReturnDocument(options.After), options.FindOneAndUpdate().SetUpsert(true)) tx.gs.Logger.Println("db read : ", _id, raw) return shared.MakeRPCReturn(raw, err) } func (tx *transaction) ReadMany(collection string, in []interface{}) shared.RPCReturnType { raw, err := tx.gs.mongoClient.FindAll(shared.CollectionName(collection), bson.M{"_id": bson.M{"$in": in}}, options.Find().SetProjection(bson.M{"_ts": 0})) tx.gs.Logger.Println("db read : ", raw) return shared.MakeRPCReturn(raw, err) } func (tx *transaction) WriteDB(collection string, raw map[string]interface{}) shared.RPCReturnType { tx.gs.Logger.Println("db access in collection : ", collection, raw) _, _, err := tx.gs.mongoClient.Update(shared.CollectionName(collection), bson.M{"_id": raw["_id"]}, bson.M{ "$currentDate": bson.M{"_ts": true}, "$set": raw, }, options.Update().SetUpsert(true)) return shared.MakeRPCReturn(nil, err) } func (tx *transaction) WriteMany(collection string, rawArray []interface{}) shared.RPCReturnType { for _, raw := range rawArray { parsed := raw.(map[string]interface{}) _, _, err := tx.gs.mongoClient.Update(shared.CollectionName(collection), bson.M{"_id": parsed["_id"]}, bson.M{ "$currentDate": bson.M{"_ts": true}, "$set": parsed, }, options.Update().SetUpsert(true)) if err != nil { shared.MakeRPCReturn(nil, err) } } return shared.MakeRPCReturn(nil, nil) } func (tx *transaction) RemoveDB(collection string, keys []interface{}) shared.RPCReturnType { count, err := tx.gs.mongoClient.DeleteMany(shared.CollectionName(collection), bson.M{"_id": bson.M{"$in": keys}}) return shared.MakeRPCReturn(count, err) } // Player info/Character info func (tx *transaction) GetAllCharInfo() shared.RPCReturnType { var playerid string if v, ok := tx.r.Header["Player-Id"]; ok && len(v) > 0 { playerid = v[0] } else { return shared.MakeRPCReturn(nil, errors.New("no player id")) } q, err := tx.gs.mongoClient.FindOne("PlayerInfo", bson.M{"_id": playerid}, options.FindOne().SetProjection(bson.M{"_id": 0, "_ts": 0})) if err == nil { tx.gs.Logger.Println("charInfo dump : ", q) return shared.MakeRPCReturn(q, err) } else { return shared.MakeRPCReturn(nil, errors.New("invalid body")) } } func (tx *transaction) RemoveCharInfo(charSlotId int32) shared.RPCReturnType { var playerid string if v, ok := tx.r.Header["Player-Id"]; ok && len(v) > 0 { playerid = v[0] } else { return shared.MakeRPCReturn(nil, errors.New("no player id")) } _, err := tx.gs.mongoClient.FindOneAndUpdate( "PlayerInfo", bson.M{"_id": playerid}, bson.M{"$pull": bson.M{"charInfo": bson.M{"slotId": charSlotId}}}, ) if err == nil { _, err = tx.gs.mongoClient.FindOneAndUpdate( "Inventory", bson.M{"_id": playerid}, bson.M{"$pull": bson.M{"inven": bson.M{"charSlotId": charSlotId}}}, ) } if err == nil { return shared.MakeRPCReturn("update success", err) } else { return shared.MakeRPCReturn(nil, errors.New("invalid body")) } } func (tx *transaction) UpdateCharInfo(charSlotId int32, raw map[string]interface{}) shared.RPCReturnType { var playerid string if v, ok := tx.r.Header["Player-Id"]; ok && len(v) > 0 { playerid = v[0] } else { return shared.MakeRPCReturn(nil, errors.New("no player id")) } tx.gs.Logger.Println("db write : ", playerid, raw) q, err := tx.gs.mongoClient.FindOne("PlayerInfo", bson.M{"_id": playerid, "charInfo.slotId": charSlotId}, options.FindOne().SetProjection(bson.M{"charInfo.$": 1})) var info map[string]interface{} if q == nil { info = raw info["slotId"] = charSlotId _, _, err = tx.gs.mongoClient.Update("PlayerInfo", bson.M{"_id": playerid}, bson.M{ "$currentDate": bson.M{"_ts": true}, "$addToSet": bson.M{"charInfo": info}, }, options.Update().SetUpsert(true)) } else { info = q["charInfo"].(bson.A)[0].(map[string]interface{}) tx.gs.Logger.Println("current info", info) for k, v := range raw { if k == "slotId" { continue } info[k] = v } _, _, err = tx.gs.mongoClient.Update("PlayerInfo", bson.M{"_id": playerid, "charInfo.slotId": charSlotId}, bson.M{ "$currentDate": bson.M{"_ts": true}, "$set": bson.M{"charInfo.$": info}, }) } tx.gs.Logger.Println("new info", info) // _, _, err := tx.gs.mongoClient.Update("PlayerInfo", // bson.M{"_id": playerid}, // bson.M{ // "$currentDate": bson.M{"_ts": true}, // "$set": raw, // }, options.Update().SetUpsert(true)) if err == nil { return shared.MakeRPCReturn(info, err) } else { return shared.MakeRPCReturn(nil, errors.New("invalid body")) } } func (tx *transaction) GetCharInfo(charSlotId int32) shared.RPCReturnType { var playerid string if v, ok := tx.r.Header["Player-Id"]; ok && len(v) > 0 { playerid = v[0] } else { return shared.MakeRPCReturn(nil, errors.New("no player id")) } raw, err := tx.gs.mongoClient.FindOne("PlayerInfo", bson.M{"_id": playerid, "charInfo.slotId": charSlotId}, options.FindOne().SetProjection(bson.M{"charInfo": bson.M{"$elemMatch": bson.M{"slotId": charSlotId}}})) // 계정 정보가 아예 없을 때 if raw == nil { _, err = tx.GetCurrentCharSlotIdImpl(playerid) // 다시 찾음 if err == nil { raw, err = tx.gs.mongoClient.FindOne("PlayerInfo", bson.M{"_id": playerid, "charInfo.slotId": charSlotId}, options.FindOne().SetProjection(bson.M{"charInfo": bson.M{"$elemMatch": bson.M{"slotId": charSlotId}}})) } } // raw, err := tx.gs.mongoClient.FindOneAndUpdate("PlayerInfo", // bson.M{"_id": playerid}, // bson.M{ // "$setOnInsert": bson.M{"_id": playerid, "charId": 101}, // }, // options.FindOneAndUpdate().SetProjection(bson.M{"_id": 0, "_ts": 0}), // options.FindOneAndUpdate().SetReturnDocument(options.After), // options.FindOneAndUpdate().SetUpsert(true)) if err == nil { tx.gs.Logger.Println("character info :", playerid, charSlotId, raw["charInfo"].(bson.A)[0]) return shared.MakeRPCReturn(raw["charInfo"].(bson.A)[0], err) } else { return shared.MakeRPCReturn(nil, errors.New("not matched")) } } func (tx *transaction) GetCurrentCharInfo() shared.RPCReturnType { var playerid string if v, ok := tx.r.Header["Player-Id"]; ok && len(v) > 0 { playerid = v[0] } else { return shared.MakeRPCReturn(nil, errors.New("no player id")) } retval, err := tx.GetCurrentCharSlotIdImpl(playerid) if err == nil { tx.gs.Logger.Println("current character slot id : ", retval) rt := tx.GetCharInfo(retval) if rt.Error() == nil { return shared.MakeRPCReturn(rt.Value(), nil) } else { return shared.MakeRPCReturn(nil, errors.New("not matched")) } } else { return shared.MakeRPCReturn(nil, err) } } func (tx *transaction) UpdateCurrentCharInfo(raw map[string]interface{}) shared.RPCReturnType { var playerid string if v, ok := tx.r.Header["Player-Id"]; ok && len(v) > 0 { playerid = v[0] } else { return shared.MakeRPCReturn(nil, errors.New("no player id")) } retval, err := tx.GetCurrentCharSlotIdImpl(playerid) if err == nil { return tx.UpdateCharInfo(retval, raw) } else { return shared.MakeRPCReturn(nil, err) } } func (tx *transaction) GetCurrentCharSlotIdImpl(playerid string) (int32, error) { initialSlotId := 1 initialCharId := 1002 raw, err := tx.gs.mongoClient.FindOneAndUpdate("PlayerInfo", bson.M{"_id": playerid}, bson.M{ "$setOnInsert": bson.M{ "_id": playerid, "currentSlotId": initialSlotId, "charInfo": bson.A{bson.M{"slotId": initialSlotId, "charId": initialCharId}}}, }, options.FindOneAndUpdate().SetReturnDocument(options.After), options.FindOneAndUpdate().SetUpsert(true)) if err == nil { return raw["currentSlotId"].(int32), nil } else { return 0, err } } func (tx *transaction) SetCurrentCharSlotId(charSlotId int32) shared.RPCReturnType { var playerid string if v, ok := tx.r.Header["Player-Id"]; ok && len(v) > 0 { playerid = v[0] } else { return shared.MakeRPCReturn(nil, errors.New("no player id")) } q, err := tx.gs.mongoClient.FindOneAndUpdate("PlayerInfo", bson.M{"_id": playerid, "charInfo.slotId": charSlotId}, bson.M{"$set": bson.M{"currentSlotId": charSlotId}}, options.FindOneAndUpdate().SetProjection(bson.M{"_id": 0, "currentSlotId": 1, "charInfo": bson.M{"$elemMatch": bson.M{"slotId": charSlotId}}}), ) if err == nil { tx.gs.Logger.Println("current character slot :", q["charInfo"].(bson.A)[0]) return shared.MakeRPCReturn(q["charInfo"].(bson.A)[0], nil) } else { return shared.MakeRPCReturn(nil, errors.New("not matched")) } } func (tx *transaction) GetCurrentCharSlotId() shared.RPCReturnType { var playerid string if v, ok := tx.r.Header["Player-Id"]; ok && len(v) > 0 { playerid = v[0] } else { return shared.MakeRPCReturn(nil, errors.New("no player id")) } slotId, err := tx.GetCurrentCharSlotIdImpl(playerid) if err == nil { return shared.MakeRPCReturn(slotId, err) } else { return shared.MakeRPCReturn(nil, errors.New("not matched")) } } // inventory func (tx *transaction) UpdateInventory(charSlotId int32, raw map[string]interface{}) shared.RPCReturnType { var playerid string if v, ok := tx.r.Header["Player-Id"]; ok && len(v) > 0 { playerid = v[0] } else { return shared.MakeRPCReturn(nil, errors.New("no player id")) } tx.gs.Logger.Println("inventory write : ", playerid, raw) var err error q, _ := tx.gs.mongoClient.FindOne("Inventory", bson.M{"_id": playerid, "inven.charSlotId": charSlotId}, options.FindOne().SetProjection(bson.M{"inven.$": 1})) if q == nil { _, _, err = tx.gs.mongoClient.Update("Inventory", bson.M{"_id": playerid}, bson.M{ "$currentDate": bson.M{"_ts": true}, "$addToSet": bson.M{"inven": bson.M{"charSlotId": charSlotId, "slots": raw}}, }, options.Update().SetUpsert(true)) } else { // _, _, err = tx.gs.mongoClient.Update("Inventory", // bson.M{"_id": playerid}, // bson.M{ // "$currentDate": bson.M{"_ts": true}, // "$set": bson.M{"inven.$[x].slots": raw}, // }, // options.Update().SetArrayFilters(options.ArrayFilters{Filters: bson.A{bson.M{"x.charId": charId}}}), // options.Update().SetUpsert(true)) slots := q["inven"].(bson.A)[0].(map[string]interface{})["slots"].(map[string]interface{}) tx.gs.Logger.Println("current inventory", slots) for k, v := range raw { slots[k] = v } tx.gs.Logger.Println("new inventory", slots) _, _, err = tx.gs.mongoClient.Update("Inventory", bson.M{"_id": playerid, "inven.charSlotId": charSlotId}, bson.M{ "$currentDate": bson.M{"_ts": true}, "$set": bson.M{"inven.$.slots": slots}, }) } if err == nil { tx.gs.Logger.Println("inventory write success") return shared.MakeRPCReturn(raw, err) } else { return shared.MakeRPCReturn(nil, errors.New("invalid body")) } } func (tx *transaction) GetInventory(charSlotId int32) shared.RPCReturnType { var playerid string if v, ok := tx.r.Header["Player-Id"]; ok && len(v) > 0 { playerid = v[0] } else { return shared.MakeRPCReturn(nil, errors.New("no player id")) } raw, err := tx.gs.mongoClient.FindOne("Inventory", bson.M{"_id": playerid, "inven.charSlotId": charSlotId}, options.FindOne().SetProjection(bson.M{"inven.$": 1})) if raw == nil { _, err = tx.gs.mongoClient.FindOneAndUpdate("Inventory", bson.M{"_id": playerid}, bson.M{ "$setOnInsert": bson.M{"_id": playerid, "inven": bson.A{}}, }, options.FindOneAndUpdate().SetUpsert(true)) raw, err = tx.gs.mongoClient.FindOneAndUpdate("Inventory", bson.M{"_id": playerid}, bson.M{ "$currentDate": bson.M{"_ts": true}, "$addToSet": bson.M{"inven": bson.M{"charSlotId": charSlotId, "slots": bson.M{}}}, }, options.FindOneAndUpdate().SetProjection(bson.M{"inven": bson.M{"$elemMatch": bson.M{"charSlotId": charSlotId}}}), options.FindOneAndUpdate().SetReturnDocument(options.After), options.FindOneAndUpdate().SetUpsert(true)) } // raw, err := tx.gs.mongoClient.FindOneAndUpdate("Inventory", // bson.M{"_id": playerid, "inven.charId": charId}, // bson.M{ // "$setOnInsert": bson.M{"_id": playerid, "inven": bson.A{bson.M{"charId": charId, "slots": bson.M{}}}}, // }, // options.FindOneAndUpdate().SetProjection(bson.M{"inven.$": 1}), // options.FindOneAndUpdate().SetReturnDocument(options.After), // options.FindOneAndUpdate().SetUpsert(true)) if err == nil { slots := raw["inven"].(bson.A)[0].(map[string]interface{})["slots"] tx.gs.Logger.Println("inventory :", playerid, charSlotId, slots) return shared.MakeRPCReturn(slots, err) } else { return shared.MakeRPCReturn(nil, errors.New("not matched")) } }