Beispiel #1
0
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)
	}
}
Beispiel #2
0
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)
			}
		}
	})
}
Beispiel #3
0
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)
		}
	})
}
Beispiel #4
0
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]
}
Beispiel #5
0
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
}
Beispiel #6
0
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()
}