public void PackageAction(PlayerAction action)
		{
			PackagedActions.Enqueue(action);

			RecentActions.Add(action);

			IEntity temp = (IEntity)this.Clone();
			this.Clone(NoCorrections);
			ExecuteAction(action.Type);
			NoCorrections = (IEntity)Match.CurrentState.GetEntity(ID).Clone();
			this.Clone(temp);
			ExecuteAction(action.Type);
		}
示例#2
0
		static void DoAction(MatchState match, ICharacter champion, PlayerAction action)
		{
			switch (action.Type) {
				case PlayerActionType.MoveLeft:
					match.Move(champion.ID, HorizontalDirection.Left);
					champion.FacingLeft = true;
					break;
				case PlayerActionType.MoveRight:
					match.Move(champion.ID, HorizontalDirection.Right);
					champion.FacingLeft = false;
					break;

				case PlayerActionType.Jump:
					match.Jump(champion.ID);
					break;

					// Ignore the actions that are not related to movement
				case PlayerActionType.Idle:
				case PlayerActionType.Spell1:
				case PlayerActionType.Spell2:
				case PlayerActionType.Spell3:
				case PlayerActionType.Spell4:
					break;

				default:
					Debug.Fail("Invalid player action.");
					ILogger.Log("Invalid player action passed in a package: " + action.Type.ToString(), LogPriority.Warning);
					break;
			}
		}
示例#3
0
		void OnActionPackage(NetIncomingMessage message)
		{
			Debug.Assert(Clients.ContainsKey(message.SenderConnection));

			try {
				while (message.Position < message.LengthBits) {
					ulong id = message.ReadUInt64();
					float time = message.ReadFloat();
					PlayerActionType type = (PlayerActionType)message.ReadByte();
					Vec2 position = new Vec2(message.ReadFloat(), message.ReadFloat());
					Vec2 target = ActionTypeHelper.IsSpell(type) ? new Vec2(message.ReadFloat(), message.ReadFloat()) : null;

					PlayerAction action = new PlayerAction(id, type, time, position, target);

					Clients[message.SenderConnection].ActionsPackage.Add(action);
				}
			} catch (Exception e) {
				ILogger.Log("Action package badly formatted: " + e.ToString(), LogPriority.Error);
			}
		}
示例#4
0
		static Vec2 ValidateActionPosition(IEntity player, PlayerAction action)
		{
			Vec2 position = action.Position;
			// If the position provided by the client seems legit, we take it. Otherwise, we ignore it
			// and log it (might be a hacker).
			if (Vec2.DistanceSquared(player.Position, position) >= MAX_TOLERATED_OFF_DISTANCE * MAX_TOLERATED_OFF_DISTANCE) {
				position = player.Position;
			}

			return position;
		}
示例#5
0
		static double ValidateActionTime(PlayerAction action, double currentTime)
		{
			double time = action.Time;

			// action time is too old? might be a hacker/extreme lag. Log it, keep it but clamp it
			double oldestAcceptedTime = currentTime - HISTORY_MAX_TIME_KEPT.TotalSeconds;
			if (action.Time < oldestAcceptedTime) {
				time = oldestAcceptedTime;
				ILogger.Log(String.Format("Action {0} seems a bit late. Accepting it, but might be a hacker/extreme lag. Given time: {1}, server time: {2}",
				                          action.ID, action.Time, currentTime), 
				            LogPriority.Warning);
			}

			// action time seems too recent? might be a hacker/time error. Log it, keep it but clamp it
			if (action.Time > currentTime + MAX_TIME_AHEAD) {
				time = currentTime;
				ILogger.Log(String.Format("Action {0} seems a bit too new. Accepting it, but might be a hacker/time error. Given time: {1}, server time: {2}",
				                          action.ID, action.Time, currentTime),
				            LogPriority.Warning);
			}

			return time;
		}
示例#6
0
		void HandleMovementAction(ulong id, PlayerAction action)
		{
			double now = Server.Instance.GetTime().TotalSeconds;
			double time = action.Time;

			// Make sure we're not using weird times
			time = ValidateActionTime(action, now);

			// Go to the given action time if we have a state history
			if (!StateHistory.IsEmpty()) {
				// Go to the game snapshot before the action that we're simulating
				KeyValuePair<double, MatchState> stateBefore = StateHistory.GetSnapshotBefore(time);
				KeyValuePair<double, MatchState> state = new KeyValuePair<double, MatchState>(
					stateBefore.Key,
					stateBefore.Value.Clone() as MatchState);

				// Simulate from our previous snapshot to our current action to be up-to-date
				if (state.Value.ContainsEntity(id)) {
					var player = (ICharacter)state.Value.GetEntity(id);
					float deltaT = (float)(time - state.Key);
					if (deltaT > 0f) { // if we have something to simulate...
						state.Value.ApplyPhysicsUpdate(id, deltaT);
					}

					// Make sure we're not using hacked positions
					player.Position = ValidateActionPosition(player, action);

					// Actually execute the action on our currently simulated state
					DoAction(state.Value, player, action);

					// Store our intermediate state at the action time.
					state = StateHistory.AddSnapshot(state.Value, time);
				}



				// Resimulate all the states up to now so that they are affected
				// by the player's action.
				var nextState = StateHistory.GetNext(state);
				while (nextState.HasValue) {
					// get how much time we have to simulate for next state
					float timeUntilNextState = (float)(nextState.Value.Key - time);
					Debug.Assert(timeUntilNextState >= 0f);

					// simulate the next state
					if (nextState.Value.Value.ContainsEntity(id)) {
						nextState.Value.Value.GetEntity(id).Clone(state.Value.GetEntity(id));
						if (timeUntilNextState > 0f) {
							nextState.Value.Value.ApplyPhysicsUpdate(id, timeUntilNextState);
						}
					}

					// switch to the next state
					state = nextState.Value;
                    time = state.Key;
                    nextState = StateHistory.GetNext(state);
				}

				// Modify our current game state to apply our simulation modifications.
				var last = StateHistory.GetLast();
				if (Match.CurrentState.ContainsEntity(id) && last.Value.ContainsEntity(id)) {
					Match.CurrentState.GetEntity(id).Clone(last.Value.GetEntity(id));
				}
			}
		}
示例#7
0
		const double RADIANS_BETWEEN_PROJECTILES = Math.PI / 36.0; // ~5 degrees
		void CastChampionSpell(ICharacter champ, PlayerAction action)
		{
			Debug.Assert(action.Target != null);

			// aim in the direction of the spell
			champ.FacingLeft = action.Target.X < champ.Position.X + champ.CollisionWidth / 2f;

			SpellTypes type = ChampionTypesHelper.GetSpellFromAction(champ.Type, action.Type);
			int projectiles = SpellsHelper.Info(type).Projectiles;
			Vec2 spawn = champ.GetHandsPosition();

			double angle = 0.0;
			if (action.Target != null) {
				Vec2 dir = action.Target - spawn;
				angle = Math.Atan2(dir.Y, dir.X); // current angle
				double completeArc = RADIANS_BETWEEN_PROJECTILES * (projectiles - 1); // complete arc that we'll cover
				angle -= completeArc / 2f; // start from the lowest angle
			}

			for (int i = 0; i < projectiles; ++i) {
				Vec2 dir = Vec2.Zero;
				if (action.Target != null) {
					double current = angle + i * RADIANS_BETWEEN_PROJECTILES;
					dir = new Vec2((float)Math.Cos(current), (float)Math.Sin(current));
				}

				LinearSpell spell = new LinearSpell(
					                   IDGenerator.GenerateID(),
					                   champ.Team,
									   spawn,
									   spawn + dir,
					                   type,
					                   champ);

				CastSpell(spell, action.Target);
			}
		}
示例#8
0
		void HandleAction(ServerClient client, PlayerAction action)
		{
			if (ActionTypeHelper.IsSpell(action.Type)) {
				var spell = ChampionTypesHelper.GetSpellFromAction(client.Champion.Type, action.Type);
				if (client.ChampStats.Alive &&
				    !client.ChampStats.IsOnCooldown(spell)) { // we're not dead and the spell is not on cooldown

					CastChampionSpell(client.Champion, action);
					client.ChampStats.UsedSpell(spell);
				}
			} else if (action.Type != PlayerActionType.Idle) {
				ILogger.Log("Unknown player action type: " + action.Type);
			}
		}