func getPlayerKick(login, message string) (*Player, error) { filename := loginToFilename(login) f, err := os.Open(filename) if err != nil { return nil, err } defer f.Close() g, err := gzip.NewReader(f) if err != nil { panic(err) } defer g.Close() var data interface{} err = gob.NewDecoder(g).Decode(&data) if err != nil { panic(err) } p := world.LoadConvert(data).(*Player) if o, ok := onlinePlayers[p.login]; ok { p = o savePlayer(p) p.Kick(message) delete(onlinePlayers, p.login) } return p, nil }
func (p *Player) Impersonate(o world.Visible) { if o == nil || o == p { if pos := p.Position(); pos != nil { pos.Zone().Impersonate(p, nil) } p.mtx.Lock() if p.impersonating != nil { p.impersonating = nil p.mtx.Unlock() if pos := p.Position(); pos != nil { pos.Zone().Update(pos, p) } } else { p.mtx.Unlock() } return } if other, ok := o.(*Player); ok { h := other.Hero o = &h } // copy the object o = world.LoadConvert(world.SaveConvert(o)).(world.Visible) if pos := p.Position(); pos != nil { pos.Zone().Impersonate(p, o) } p.mtx.Lock() p.impersonating = o p.mtx.Unlock() if pos := p.Position(); pos != nil { pos.Zone().Update(pos, p) } }
// Login returns a non-nil player and an empty error string OR a nil player // and an error to show to the user. func Login(addr string, packet *LoginPacket) (*Player, string) { login := strings.TrimSpace(packet.Login) if login == "" { return nil, "A username is required." } pass := []byte(packet.Pass) if len(pass) <= 2 { return nil, "A password is required." } filename := loginToFilename(login) loginLock.Lock() defer loginLock.Unlock() loginAttempts[addr]++ if loginAttempts[addr] == 5 { loginAttempts[addr] += 60 } if loginAttempts[addr] > 5 { return nil, fmt.Sprintf("Too many login attempts. Come back in %d minutes.", loginAttempts[addr]-5) } f, err := os.Open(filename) if err != nil { hashedPass, err := bcrypt.GenerateFromPassword(pass, CryptoCost) if err != nil { panic(err) } p := &Player{ Hero: *GenerateHero(rand.New(rand.NewSource(rand.Int63()))), characterCreation: true, tileX: 127, tileY: 127, login: login, password: hashedPass, firstAddr: addr, registered: time.Now().UTC(), lastAddr: addr, lastLogin: time.Now().UTC(), } world.InitObject(p) for _, e := range p.Hero.equipped { e.wearer = p } savePlayer(p) onlinePlayers[login] = p return p, "" } defer f.Close() g, err := gzip.NewReader(f) if err != nil { panic(err) } defer g.Close() var data interface{} err = gob.NewDecoder(g).Decode(&data) if err != nil { panic(err) } p := world.LoadConvert(data).(*Player) if bcrypt.CompareHashAndPassword(p.password, pass) != nil { return nil, "Username or password incorrect." } loginAttempts[addr]-- if other, ok := onlinePlayers[p.login]; ok { savePlayer(other) other.Kick("Logged in from a different location.") _, err = f.Seek(0, 0) if err != nil { panic(err) } g, err = gzip.NewReader(f) if err != nil { panic(err) } defer g.Close() data = nil err = gob.NewDecoder(g).Decode(&data) if err != nil { panic(err) } p = world.LoadConvert(data).(*Player) } cost, err := bcrypt.Cost(p.password) if err != nil { panic(err) } if cost != CryptoCost { p.password, err = bcrypt.GenerateFromPassword(pass, CryptoCost) if err != nil { panic(err) } savePlayer(p) } onlinePlayers[p.login] = p return p, "" }