Ejemplo n.º 1
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)
			}
		}
	})
}
Ejemplo n.º 2
0
// Ensure that there is only one delta per entity in the deltas list.
// Warning: some information is lost, for instance if an entity is created then
// deleted, an empty delta is added to the list.
func flattenDeltas(deltas *delta.List) []*Delta {
	m := make(map[message.EntityId]*Delta)

	for e := deltas.First(); e != nil; e = e.Next() {
		d := e.Value.(*Delta)

		if current, ok := m[d.EntityId]; ok {
			// TODO: check that current.To and d.From are compatible

			if d.Diff != nil && current.To != nil {
				current.To.ApplyDiff(d.Diff, d.To)
			} else {
				// Deep copy To since it can be modified by this loop
				current.To = d.To
				if current.To != nil {
					current.To = current.To.Copy()
				}
			}
		} else {
			// Deep copy To since it can be modified by this loop
			to := d.To
			if to != nil {
				to = to.Copy()
			}

			m[d.EntityId] = &Delta{
				EntityId: d.EntityId,
				Diff:     message.NewEntityDiff(),
				From:     d.From,
				To:       to,
			}
		}

		if d.Diff != nil {
			m[d.EntityId].Diff.Merge(d.Diff)
		}
	}

	l := make([]*Delta, len(m))
	i := 0
	for _, d := range m {
		l[i] = d
		i++
	}

	return l
}
Ejemplo n.º 3
0
func (e *Engine) moveEntities(t message.AbsoluteTick) {
	for _, ent := range e.entity.List() {
		req, collidesWith := e.mover.UpdateEntity(ent, t)

		// [GAME-SPECIFIC] Destroy balls when they collide
		if collidesWith != nil && ent.Type == game.BallEntity {
			req := entity.NewDeleteRequest(t, ent.Id)
			if err := e.entity.AcceptRequest(req); err != nil {
				panic(err) // This shouldn't happen
			}

			// If the ball collides with a player, decrease his health
			if collidesWith, ok := collidesWith.(*message.Entity); ok && collidesWith.Type == game.PlayerEntity {
				sender := ent.Attributes[game.SenderAttr].(message.EntityId)
				if sender != collidesWith.Id {
					health := collidesWith.Attributes[game.HealthAttr].(game.Health)

					updated := entity.New()
					updated.Attributes[game.HealthAttr] = health - 1
					diff := message.NewEntityDiff()
					diff.Attributes = true
					req := entity.NewUpdateRequest(t, updated, diff)
					if err := e.entity.AcceptRequest(req); err != nil {
						panic(err) // This shouldn't happen
					}
				}
			}
			continue
		}

		if req != nil {
			// Let's assume mover already did all security checks
			if err := e.entity.AcceptRequest(req); err != nil {
				// This should not fail
				panic(err)
			}
		}
	}
}