func TestService_Rewind(t *testing.T) { s := entity.NewService() f := s.Frontend() // Accept all requests go (func() { for { var req entity.Request select { case req = <-f.Creates: case req = <-f.Updates: case req = <-f.Deletes: } s.AcceptRequest(req) } })() t0 := message.AbsoluteTick(1) // Create a new entity ent := message.NewEntity() ent.Position.X = 10 ent.Position.Y = 15 req := f.Add(ent, t0) req.Wait() created := req.(*entity.CreateRequest) id := created.Entity.Id if id == 0 { t.Fatal("Entity doesn't have an id after being added") } ent0 := s.Get(id) t1 := t0 + 5 // Update the entity update := message.NewEntity() update.Id = id update.Position.X = 33 update.Position.Y = 15 diff := &message.EntityDiff{Position: true} req = f.Update(update, diff, t1) req.Wait() // Rewind err := s.Rewind(s.GetTick() - t0) if err != nil { t.Fatal(err) } rewindEnt := s.Get(id) if rewindEnt.Position.X != ent0.Position.X { t.Fatal("Invalid rewind, expected position", ent0.Position.X, "but got", rewindEnt.Position.X) } }
func TestEntitiesUpdate(t *testing.T) { tick := message.Tick(42) entity1 := message.NewEntity() entity1.Id = 69 entity1.Position.X = 22 entity1.Position.Y = 65 diff1 := message.NewEntityDiff() diff1.Position = true entity2 := message.NewEntity() entity2.Id = 76 entity2.Speed.Angle = 67 entity2.Speed.Norm = 43 diff2 := message.NewEntityDiff() diff2.SpeedAngle = true diff2.SpeedNorm = true entities := []*message.Entity{entity1, entity2} diffs := []*message.EntityDiff{diff1, diff2} testMessage(t, message.Types["entities_update"], func(w io.Writer) error { return builder.SendEntitiesUpdate(w, tick, entities, diffs) }, func(conn *message.Conn, t *testing.T) { rt, rentities, rdiffs := handler.ReadEntitiesUpdate(conn) if rt != tick { t.Fatal("Sent tick", tick, "but received", rt) } if len(entities) != len(rentities) { t.Fatal("Sent", len(entities), "entities but received", len(rentities)) } for i, entity := range entities { diff := diffs[i] rentity := rentities[i] rdiff := rdiffs[i] if !diff.Equals(rdiff) { t.Fatal("Sent diff", diff, " at offset", i, "but received", rdiff) } if !entity.EqualsWithDiff(rentity, diff) { t.Fatal("Sent entity", entity, " at offset", i, "with diff", diff, "but received", rentity) } } }) }
func TestEntityCreate(t *testing.T) { tick := message.Tick(42) entity := message.NewEntity() entity.Id = 69 entity.Position.X = 22 entity.Position.Y = 67 entity.Speed.Angle = 67 entity.Speed.Norm = 78 entity.Sprite = 12 // TODO: populate other attributes testMessage(t, message.Types["entity_create"], func(w io.Writer) error { return builder.SendEntityCreate(w, tick, entity) }, func(conn *message.Conn, t *testing.T) { rt, e := handler.ReadEntityCreate(conn) if rt != tick { t.Fatal("Sent tick", tick, "but received", rt) } if !entity.Equals(e) { t.Fatal("Sent entity", entity, "but received", e) } }) }
func (s *Service) Login(id int, username string, password string) message.LoginResponseCode { code := "unknown_pseudo" for _, user := range s.users { if username != user.Username { continue } session := s.getSessionByUsername(username) if session != nil { code = "already_connected" break } if user.VerifyPassword(password) { code = "ok" } else { code = "wrong_password" } break } if code == "ok" { session := &message.Session{ Id: id, Username: username, Entity: message.NewEntity(), } if s.LoginCallback != nil { s.LoginCallback(session) } s.sessions[id] = session } return message.LoginResponseCodes[code] }
func ReadEntity(r io.Reader) (*message.Entity, *message.EntityDiff) { entity := message.NewEntity() var bitfield uint8 Read(r, &entity.Id, &bitfield) diff := message.NewEntityDiffFromBitfield(bitfield) if diff.Position { Read(r, &entity.Position.BX, &entity.Position.BY) Read(r, &entity.Position.X, &entity.Position.Y) } if diff.SpeedAngle { Read(r, &entity.Speed.Angle) } if diff.SpeedNorm { Read(r, &entity.Speed.Norm) } if diff.Type { Read(r, &entity.Type) } if diff.Sprite { Read(r, &entity.Sprite) } if diff.Attributes { var size uint16 Read(r, &size) // TODO: move this somewhere else for i := 0; i < int(size); i++ { var attrId message.EntityAttrId Read(r, &attrId) // TODO: do something of the data var attrVal interface{} switch attrId { case 0: var ticksLeft uint16 Read(r, &ticksLeft) attrVal = ticksLeft case 1: var health uint16 Read(r, &health) attrVal = health case 2: var sender message.EntityId Read(r, &sender) attrVal = sender case 30000: var cooldownOne uint16 Read(r, &cooldownOne) attrVal = cooldownOne default: attrVal = nil } if attrVal != nil { entity.Attributes[attrId] = attrVal } } } return entity, diff }
func TestEngine(t *testing.T) { e := engine.NewServerless() ctx := e.Context() go e.Start() time.Sleep(5 * clock.TickDuration) // Create a new entity createdAt := ctx.Clock.GetAbsoluteTick() t.Log("Adding new entity at tick", createdAt) ent := message.NewEntity() ent.Id = 1 ent.Position.X = 10 ent.Position.Y = 15 req := ctx.Entity.Add(ent, createdAt) if err := req.Wait(); err != nil { t.Fatal("Cannot create entity:", err) } time.Sleep(5 * clock.TickDuration) // Update the entity updatedAt := ctx.Clock.GetAbsoluteTick() t.Log("Updating the entity at tick", updatedAt) update := message.NewEntity() update.Id = ent.Id update.Speed.Norm = 10 diff := &message.EntityDiff{SpeedNorm: true} req = ctx.Entity.Update(update, diff, updatedAt) if err := req.Wait(); err != nil { t.Fatal("Cannot update entity:", err) } time.Sleep(2 * clock.TickDuration) // Update the entity a second time, in the past reupdatedAt := ctx.Clock.GetAbsoluteTick() - 5 t.Log("Updating the entity a second time at tick", reupdatedAt) update = message.NewEntity() update.Id = ent.Id update.Speed.Norm = 20 req = ctx.Entity.Update(update, diff, reupdatedAt) if err := req.Wait(); err != nil { t.Fatal("Cannot update entity:", err) } time.Sleep(clock.TickDuration) pool := ctx.Entity.Flush() if len(pool.Created) != 1 { t.Fatal("Created an entity, but it isn't in the diff pool") } if len(pool.Updated) != 0 { t.Fatal("Updated an entity, but it shouldn't be in the diff pool since it just has been created") } if len(pool.Deleted) != 0 { t.Fatal("No entity deleted, but there is one in the diff pool") } if pool.Created[0].Id != ent.Id { t.Fatal("The entity in the diff pool has a wrong id") } if pool.Created[0].Speed.Norm != 10 { t.Fatal("The entity in the diff pool has a wrong speed norm, got", pool.Created[0].Speed.Norm, "instead of", 10) } // Update the entity another time update = message.NewEntity() update.Id = ent.Id update.Speed.Norm = 15 ctx.Entity.Update(update, diff, ctx.Clock.GetAbsoluteTick()) time.Sleep(clock.TickDuration) pool = ctx.Entity.Flush() if len(pool.Created) != 0 { t.Fatal("No entity created, but there is one in the diff pool") } if len(pool.Updated) != 1 { t.Fatal("Updated an entity, but it isn't in the diff pool") } if len(pool.Deleted) != 0 { t.Fatal("No entity deleted, but there is one in the diff pool") } for updated, diff := range pool.Updated { if updated.Id != ent.Id { t.Fatal("The entity in the diff pool has a wrong id") } if updated.Speed.Norm != 15 { t.Fatal("The entity in the diff pool has a wrong speed norm") } if !diff.SpeedNorm { t.Fatal("The diff doesn't mark the speed norm as outdated, but it has just been updated") } } e.Stop() }