private async void ExecuteAsync(PlayerDetails playerDetails)
        {
            try
            {
                int charId = playerDetails.CharId;
                if (charId < 0)
                {
                    throw new Exception("char. ID not set!");
                }

                CharacterData charData = await _charInfo.GetCharacterByIdTaskStart(charId);

                if (charData.IsOnWorldMap)
                {
                    _charActionManager.SwitchCharacterMovementType(charId);
                }
                else
                {
                    int wmId           = charData.WmId;
                    int parentObjectId = charData.ParentObjectId;

                    Point3 <int> pointFrom = new Point3 <int>
                                             (
                        Convert.ToInt32(charData.CurrentLoc.X),
                        Convert.ToInt32(charData.CurrentLoc.Y),
                        Convert.ToInt32(charData.CurrentLoc.Z) - 1
                                             );

                    Point3 <int> pointTo = new Point3 <int>
                                           (
                        Convert.ToInt32(charData.CurrentLoc.X),
                        Convert.ToInt32(charData.CurrentLoc.Y),
                        Convert.ToInt32(charData.CurrentLoc.Z) + 1
                                           );

                    using (BoxedData boxedGeoData = await _geoDataInfo.GetLocalGeoDataTaskStart(wmId, parentObjectId, pointFrom, pointTo))
                    {
                        List <GeoDataElement> geoDataElementList = (List <GeoDataElement>)boxedGeoData.Data;
                        if (!String.IsNullOrEmpty(boxedGeoData.Msg))
                        {
                            _logger.UpdateLog(boxedGeoData.Msg);
                        }

                        bool exitFound = false;
                        int  collisionMinX, collisionMaxX, collisionMinY, collisionMaxY, collisionMinZ, collisionMaxZ;

                        foreach (GeoDataElement geoElement in geoDataElementList)
                        {
                            if (!geoElement.IsExit)
                            {
                                continue;
                            }

                            GeoDataValidator.GetColliderPosition(geoElement, out collisionMinX, out collisionMaxX, out collisionMinY, out collisionMaxY, out collisionMinZ, out collisionMaxZ);

                            //_logger.UpdateLog($"exit col. x [{collisionMinX}-{collisionMaxX}] y [{collisionMinY}-{collisionMaxY}] z [{collisionMinZ}-{collisionMaxZ}]");
                            //_logger.UpdateLog($"current [{charData.CurrentLoc.X}; {charData.CurrentLoc.Y}; {charData.CurrentLoc.Z}]");

                            if
                            (
                                charData.CurrentLoc.X >= collisionMinX && charData.CurrentLoc.X <= collisionMaxX + 1 &&
                                charData.CurrentLoc.Y >= collisionMinY && charData.CurrentLoc.Y <= collisionMaxY + 1 &&
                                charData.CurrentLoc.Z >= collisionMinZ && charData.CurrentLoc.Z <= collisionMaxZ + 2
                            )
                            {
                                exitFound = true;
                                break;
                            }
                        }

                        if (exitFound)
                        {
                            _charActionManager.SwitchCharacterMovementType(charId);
                        }
                        else
                        {
                            CommandHandler.Send(new InfoCmdBuilder("You're not at exit point!"), playerDetails);
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                _logger.UpdateLog($"Switch place command execution error: {exception.Message}");
            }
        }
예제 #2
0
        private async void HandleCharactersMovementAsync()
        {
            if (_movementHandlingInProgress)
            {
                _logger.UpdateLog("Character movement handling already started!");
                return;
            }

            _movementHandlingInProgress = true;
            _logger.UpdateLog("Game state handler - character movement handling started!");

            try
            {
                List <CharacterMovementDetails> movementDetailsListTemp = new List <CharacterMovementDetails>();
                CharacterData                  characterData;
                List <GeoDataElement>          geoDataList           = new List <GeoDataElement>();
                CharacterPositionUpdateDetails positionDetailsToSend = null;
                int count = 0;

                int  wmId;
                int  parentObjectId;
                bool isOnWorldMap;

                GeoDataValidationDetails geoDataValidationDetails = null;
                bool            geoMovementValid        = false;
                Point3 <double> lastValidMovementPoint  = new Point3 <double>(0, 0, 0);
                bool            exitPointFound          = false;
                Point3 <double> exitPosition            = null;
                double          lastTParamValue         = 0;
                int             timeArrivalMsIncomplete = 0;
                bool            worldMovingValid        = false;

                do
                {
                    #region Main list item removal
                    //MAIN LIST ITEM REMOVAL
                    lock (_movementDetailsLock)
                    {
                        count = _movementDetailsList.Count;

                        if (count > 0)
                        {
                            movementDetailsListTemp = _movementDetailsList.Clone();
                            foreach (CharacterMovementDetails item in _movementDetailsList)
                            {
                                item.Dispose();
                            }

                            _movementDetailsList.Clear();
                        }
                    }

                    #endregion

                    #region Interval handling
                    //INTERVAL HANDLING
                    if (count == 0)
                    {
                        await Task.Factory.StartNew(() => Thread.Sleep(GameStateHandler._movementHandlingTickMs));

                        continue;
                    }

                    #endregion

                    #region Movement details handling
                    //MOV. DETAILS HANDLING
                    foreach (CharacterMovementDetails movementDetails in movementDetailsListTemp)
                    {
                        if (geoDataList.Count > 0)
                        {
                            geoDataList.Clear();
                        }

                        if (movementDetails.CharId < 0)
                        {
                            _logger.UpdateLog("Movement details handling warning - character's ID less than 0!");
                            continue;
                        }

                        //characterData = await _characterInfo.GetCharacterByNameTaskStart(movementDetails.CharName);
                        characterData = await _characterInfo.GetCharacterByIdTaskStart(movementDetails.CharId);

                        if (characterData == null)
                        {
                            _logger.UpdateLog($"Movement details handling warning - character's ID [{movementDetails.CharId}] not found!");
                            continue;
                        }

                        wmId           = characterData.WmId;
                        parentObjectId = characterData.ParentObjectId;
                        isOnWorldMap   = characterData.IsOnWorldMap;

                        switch (movementDetails.Type)
                        {
                        case CharacterMovementDetails.MovementType.SwitchMovementType:
                        {
                            #region Local enter/exit point veryfication
                            //LOCAL ENTER/EXIT POINT VERYFICATION
                            exitPointFound = false;

                            if (characterData.IsOnWorldMap)
                            {
                                using (BoxedData geoBoxedData = await _geoDataInfo.GetLocalGeoDataOfExitElementsTaskStart(wmId, parentObjectId))
                                {
                                    geoDataList = (List <GeoDataElement>)geoBoxedData.Data;
                                    if (!String.IsNullOrEmpty(geoBoxedData.Msg))
                                    {
                                        _logger.UpdateLog(geoBoxedData.Msg);
                                    }
                                }

                                exitPosition = GeoDataValidator.GetRandomExitPosition(geoDataList);

                                if (exitPosition != null)
                                {
                                    exitPointFound = true;

                                    //PLACING CHARACTER ON ENTRY POINT
                                    characterData.MoveCharacterLocal
                                    (
                                        exitPosition.Copy(),
                                        exitPosition.Copy(),
                                        0
                                    );
                                }
                            }

                            #endregion

                            #region State change section
                            //STATE CHANGE SECTION

                            if (!exitPointFound && characterData.IsOnWorldMap)
                            {
                                _logger.UpdateLog($"Cannot find location exit point for character's ID [{movementDetails.CharId}] wm_id [{wmId}] parent object ID [{parentObjectId}]");
                                SendMessageToPlayer(movementDetails.CharId, "Error: cannot find entry point!");
                            }
                            else
                            {
                                characterData.IsOnWorldMap = !isOnWorldMap;
                                _logger.UpdateLog($"Movement type switched for character's ID [{movementDetails.CharId}] to {(characterData.IsOnWorldMap ? "world" : "local")} state");

                                positionDetailsToSend = new CharacterPositionUpdateDetails()
                                {
                                    MovementType       = (characterData.IsOnWorldMap ? "switchmap" : "switchlocal"),
                                    CharId             = movementDetails.CharId,
                                    OldLocationLocal   = characterData.CurrentLoc.Copy(),
                                    NewLocationLocal   = characterData.CurrentLoc.Copy(),
                                    TimeArrivalMsLocal = 0,
                                    OldLocationWorld   = characterData.CurrentWorldLoc.Copy(),
                                    NewLocationWorld   = characterData.CurrentWorldLoc.Copy()
                                };

                                if (characterData.IsOnWorldMap)
                                {
                                    SendMovementDetailsToCurrentPlayerAsync(positionDetailsToSend, movementDetails.CharId);
                                }

                                SendMovementDetailsToPlayersInLocationAsync(positionDetailsToSend, wmId, false, parentObjectId);
                            }

                            #endregion
                        }
                        break;

                        case CharacterMovementDetails.MovementType.Local:
                        {
                            #region Local movement handling
                            //LOCAL MOVEMENT HANDLING
                            if (isOnWorldMap)
                            {
                                _logger.UpdateLog($"Movement details handling warning - local movement cancelled for character's ID [{movementDetails.CharId}], reason: world map state");
                            }
                            else
                            {
                                #region Geo data validation
                                //GEO DATA VALIDATION
                                using
                                (
                                    BoxedData geoBoxedData = await _geoDataInfo.GetLocalGeoDataTaskStart
                                                             (
                                        wmId,
                                        parentObjectId,
                                        PointConverter.Point3DoubleToInt(movementDetails.OldLocationLocal),
                                        PointConverter.Point3DoubleToInt(movementDetails.NewLocationLocal)
                                                             )
                                )
                                {
                                    geoDataList = (List <GeoDataElement>)geoBoxedData.Data;
                                    if (!String.IsNullOrEmpty(geoBoxedData.Msg))
                                    {
                                        _logger.UpdateLog(geoBoxedData.Msg);
                                    }
                                }

                                using (BoxedData geoValidationBoxedData = await GeoDataValidator.ValidateMovementTaskStart(geoDataList, movementDetails))
                                {
                                    geoDataValidationDetails = (GeoDataValidationDetails)geoValidationBoxedData.Data;
                                    if (!String.IsNullOrEmpty(geoValidationBoxedData.Msg))
                                    {
                                        _logger.UpdateLog(geoValidationBoxedData.Msg);
                                    }

                                    geoMovementValid       = geoDataValidationDetails.Valid;
                                    lastValidMovementPoint = geoDataValidationDetails.LastValidMovementPoint;
                                    lastTParamValue        = geoDataValidationDetails.LastTParamValue;

                                    geoDataValidationDetails.Dispose();
                                    geoDataValidationDetails = null;
                                }
                                #endregion

                                //_logger.UpdateLog($"GEO VALID [{geoMovementValid}]");
                                //geoMovementValid = true; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

                                //CHARACTER MOVING
                                if (geoMovementValid)
                                {
                                    characterData.MoveCharacterLocal
                                    (
                                        movementDetails.OldLocationLocal.Copy(),
                                        movementDetails.NewLocationLocal.Copy(),
                                        movementDetails.TimeArrivalMsLocal
                                    );

                                    positionDetailsToSend = new CharacterPositionUpdateDetails()
                                    {
                                        MovementType       = "movelocal",
                                        CharId             = movementDetails.CharId,
                                        OldLocationLocal   = movementDetails.OldLocationLocal.Copy(),
                                        NewLocationLocal   = movementDetails.NewLocationLocal.Copy(),
                                        TimeArrivalMsLocal = movementDetails.TimeArrivalMsLocal,
                                        OldLocationWorld   = new Point2 <int>(0, 0),
                                        NewLocationWorld   = new Point2 <int>(0, 0)
                                    };

                                    SendMovementDetailsToPlayersInLocationAsync(positionDetailsToSend, wmId, isOnWorldMap, parentObjectId);
                                }
                                else
                                {
                                    timeArrivalMsIncomplete = Convert.ToInt32(Convert.ToDouble(movementDetails.TimeArrivalMsLocal) * lastTParamValue);

                                    characterData.MoveCharacterLocal
                                    (
                                        movementDetails.OldLocationLocal.Copy(),
                                        lastValidMovementPoint.Copy(),
                                        timeArrivalMsIncomplete
                                    );

                                    positionDetailsToSend = new CharacterPositionUpdateDetails()
                                    {
                                        MovementType       = "movelocal",
                                        CharId             = movementDetails.CharId,
                                        OldLocationLocal   = movementDetails.OldLocationLocal.Copy(),
                                        NewLocationLocal   = lastValidMovementPoint.Copy(),
                                        TimeArrivalMsLocal = timeArrivalMsIncomplete,
                                        OldLocationWorld   = new Point2 <int>(0, 0),
                                        NewLocationWorld   = new Point2 <int>(0, 0)
                                    };

                                    SendMovementDetailsToPlayersInLocationAsync(positionDetailsToSend, wmId, isOnWorldMap, parentObjectId);
                                }
                            }

                            #endregion
                        }
                        break;

                        case CharacterMovementDetails.MovementType.World:
                        {
                            #region World map movement handling
                            //WORLD MAP MOVEMENT HANDLING
                            if (!isOnWorldMap)
                            {
                                _logger.UpdateLog($"Movement details handling warning - world map movement cancelled for character's ID [{movementDetails.CharId}], reason: local movement state");
                            }
                            else
                            {
                                Point2 <int> oldLocWorld = movementDetails.OldLocationWorld.Copy();
                                Point2 <int> newLocWorld = movementDetails.NewLocationWorld.Copy();

                                //WORLD MOVEMENT VALIDATION
                                worldMovingValid = true;

                                int distanceX = Math.Abs(oldLocWorld.X - newLocWorld.X);
                                int distanceY = Math.Abs(oldLocWorld.Y - newLocWorld.Y);

                                if
                                (
                                    oldLocWorld.X != characterData.CurrentWorldLoc.X || oldLocWorld.Y != characterData.CurrentWorldLoc.Y ||
                                    distanceX > 2 || distanceY > 2
                                )
                                {
                                    worldMovingValid = false;
                                    //_logger.UpdateLog($"Movement details handling warning - world map movement cancelled for character's ID [{movementDetails.CharId}]");
                                }

                                //CHARACTER MOVING
                                if (worldMovingValid)
                                {
                                    WorldPlaceDataDetails worldPlaceDetails = _geoDataInfo.GetWorldPlaceDataDetails(newLocWorld.X, newLocWorld.Y);
                                    int newWmId = (worldPlaceDetails != null ? worldPlaceDetails.WmId : -1);

                                    characterData.MoveCharacterWorld(newLocWorld);

                                    positionDetailsToSend = new CharacterPositionUpdateDetails()
                                    {
                                        MovementType       = "moveworld",
                                        CharId             = movementDetails.CharId,
                                        OldLocationLocal   = new Point3 <double>(0, 0, 0),
                                        NewLocationLocal   = new Point3 <double>(0, 0, 0),
                                        TimeArrivalMsLocal = 0,
                                        OldLocationWorld   = oldLocWorld,
                                        NewLocationWorld   = newLocWorld
                                    };

                                    SendMovementDetailsToPlayersInLocationAsync(positionDetailsToSend, wmId, isOnWorldMap, parentObjectId);
                                    ChangeWmIdAsync(characterData, newWmId);
                                }
                                else
                                {
                                    SendMessageToPlayer(movementDetails.CharId, "You're moving too far");
                                }
                            }

                            #endregion
                        }
                        break;

                        default:
                            throw new Exception($"unknown movement type [{movementDetails.Type.ToString()}]!");
                        }
                    }

                    #endregion

                    #region Temp. list disposal
                    //TEMP. LIST DISPOSAL
                    foreach (CharacterMovementDetails item in movementDetailsListTemp)
                    {
                        item.Dispose();
                    }

                    movementDetailsListTemp.Clear();

                    #endregion
                }while (_movementHandlingInProgress);
            }
            catch (Exception exception)
            {
                _logger.UpdateLog($"Character movement handling error: {exception.Message}");
            }
            finally
            {
                _movementHandlingInProgress = false;
                _logger.UpdateLog("Game state handler - character movement handling stopped!");
            }
        }