/// <inheritdoc /> protected override Vector3 InternalUpdate(GameObject entity, long currentTime) { ProjectVersionStage.AssertAlpha(); for (int i = 0; i < MovementData.MovementPath.Count - 1; i++) { Debug.DrawLine(MovementData.MovementPath[i], MovementData.MovementPath[i + 1], Color.red, 0.1f); } //Knowing the two points is enough to linerally interpolate between them. long timeSinceSegementState = currentTime - State.TimePathStateCreated; float lerpRatio = (float)timeSinceSegementState / State.PathSegementDuration; entity.transform.position = Vector3.Lerp(MovementData.MovementPath[State.PathIndex], MovementData.MovementPath[State.PathIndex + 1], lerpRatio); if (lerpRatio >= 1.0f) { if (State.PathIndex + 2 >= MovementData.MovementPath.Count) { State = new PathState(MovementData.MovementPath.Count - 1, currentTime, 0); StopGenerator(); } else { State = new PathState(State.PathIndex + 1, currentTime, CalculateDistanceLengthInTicks((MovementData.MovementPath[State.PathIndex + 2] - MovementData.MovementPath[State.PathIndex + 1]).magnitude, 1.0f)); } } return(entity.transform.position); }
protected override void HandleEvent(ActionBarButtonStateChangedEventArgs args) { //TODO: Check actionbar index and handle multiple rows. if (ActionBarRow.ContainsKey(args.Index)) { IUIActionBarButton barButton = ActionBarRow[args.Index]; if (args.ActionType == ActionBarIndexType.Empty) { barButton.SetElementActive(false); } else { barButton.SetElementActive(true); //TODO: Refactor for spell/item if (args.ActionType == ActionBarIndexType.Spell) { //TODO: Abstract the icon content loading //TODO: Don't assume we have the content icon. Throw/log better exception SpellDefinitionDataModel definition = SpellDataCollection.GetSpellDefinition(args.ActionId); ContentIconInstanceModel icon = ContentIconCollection[definition.SpellIconId]; ProjectVersionStage.AssertAlpha(); //TODO: Load async Texture2D iconTexture = Resources.Load <Texture2D>(Path.Combine("Icon", Path.GetFileNameWithoutExtension(icon.IconPathName))); barButton.ActionBarImageIcon.SetSpriteTexture(iconTexture); } else { throw new InvalidOperationException($"TODO: Implement empty/item action bar support"); } } } }
//[AuthorizeJwt(GuardianApplicationRole.ZoneServer)] //only zone servers should EVER be able to release the active session. They should also likely only be able to release an active session if it's on them. public async Task<IActionResult> ReleaseActiveSession([FromRoute(Name = "id")] int characterId) { //We NEED to AUTH for zoneserver JWT. ProjectVersionStage.AssertAlpha(); //If an active session does NOT exist we have a BIG problem. if(!await CharacterSessionRepository.CharacterHasActiveSession(characterId)) { if(Logger.IsEnabled(LogLevel.Error)) Logger.LogError($"ZoneServer requested ActiveSession for Player: {characterId} be removed. Session DOES NOT EXIST. This should NOT HAPPEN."); return NotFound(); } //We should try to remove the active sesison. //One this active session is revoked the character/account is free to claim any existing session //including the same one that was just freed. if(!await CharacterSessionRepository.TryDeleteClaimedSession(characterId)) { if(Logger.IsEnabled(LogLevel.Error)) Logger.LogError($"ZoneServer requested ActiveSession for Player: {characterId} be removed. Session DOES NOT EXIST. This should NOT HAPPEN."); return BadRequest(); } else { if(Logger.IsEnabled(LogLevel.Information)) Logger.LogInformation($"Removed ActiveSession for Player: {characterId}"); return Ok(); } }
protected override void OnThreadUnSafeEventFired(object source, CharacterSessionDataChangedEventArgs args) { if (Logger.IsInfoEnabled) { Logger.Info($"Starting process to download world."); } UnityAsyncHelper.UnityMainThreadContext.PostAsync(async() => { long worldId = 0; try { //TODO: Handle failure ProjectVersionStage.AssertAlpha(); //TODO: Handle throwing/error //We need to know the world the zone is it, so we can request a download URL for it. var worldConfig = await ZoneDataService.GetZoneWorldConfigurationAsync(args.ZoneIdentifier) .ConfigureAwaitFalse(); if (!worldConfig.isSuccessful) { throw new InvalidOperationException($"Failed to query World Configuration for ZoneId: {args.ZoneIdentifier}"); } worldId = worldConfig.Result.WorldId; //With the worldid we can get the download URL. ContentDownloadURLResponse urlDownloadResponse = await ContentService.RequestWorldDownloadUrl(worldId) .ConfigureAwaitFalse(); if (Logger.IsInfoEnabled) { Logger.Info($"World Download Url: {urlDownloadResponse.DownloadURL}"); } //Can't do web request not on the main thread, sadly. await new UnityYieldAwaitable(); WorldDownloader downloader = new WorldDownloader(Logger); await downloader.DownloadAsync(urlDownloadResponse.DownloadURL, urlDownloadResponse.Version, o => { OnWorldDownloadBegins?.Invoke(this, new WorldDownloadBeginEventArgs(o)); }); } catch (Exception e) { if (Logger.IsErrorEnabled) { Logger.Error($"Failed to query for Download URL for ZoneId: {args.ZoneIdentifier} WorldId: {worldId} (0 if never succeeded request). Error: {e.Message}"); } throw; } }); }
/// <inheritdoc /> protected override Task HandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, PlayerModelChangeRequestPayload payload, NetworkEntityGuid guid) { //At this point, the player wants to change his model. //However we really can't be sure it's a valid model //so we validate it before setting the model id. //TODO: Validate the model id. ProjectVersionStage.AssertAlpha(); IEntityDataFieldContainer entityDataFieldContainer = EntityFieldMap.RetrieveEntity(guid); //This change will be broadcast to anyone interested. entityDataFieldContainer.SetFieldValue(BaseObjectField.UNIT_FIELD_DISPLAYID, payload.ModelId); return(Task.CompletedTask); }
/// <inheritdoc /> public DefaultLoadableContentResourceManager( [NotNull] ILog logger, UserContentType contentType) { if (!Enum.IsDefined(typeof(UserContentType), contentType)) { throw new InvalidEnumArgumentException(nameof(contentType), (int)contentType, typeof(UserContentType)); } //TODO: We haven't implemented the refcounted cleanup. We ref count, but don't yet dispose. ProjectVersionStage.AssertAlpha(); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); ContentType = contentType; ResourceHandleCache = new Dictionary <long, ReferenceCountedPrefabContentResourceHandle>(); ReleaseUnmanagedResources(); }
public async Task<IActionResult> TryClaimSession([FromBody] ZoneServerTryClaimSessionRequest request) { //TODO: Renable auth for session claiming ProjectVersionStage.AssertAlpha(); if(!this.ModelState.IsValid) return BadRequest(); //TODO: Send JSON back too. //TODO: We should validate a lot things. One, that the character has a session on this zoneserver. //We should also validate that the account owns the character. We need a new auth process for entering users. //We have to do this validation, somehow. Or malicious players could spoof this. ProjectVersionStage.AssertAlpha(); //TODO: Verify that the zone id is correct. Right now we aren't providing it and the query doesn't enforce it. //We don't validate characterid/accountid association manually. It is implemented in the tryclaim SQL instead. //It additionally also checks the zone relation for the session so it will fail if it's invalid for the provided zone. //Therefore we don't need to make 3/4 database calls/queries to claim a session. Just one stored procedure call. //This is preferable. A result code will be used to indicate the exact error in the future. For now it just fails if it fails. bool sessionClaimed = await CharacterSessionRepository.TryClaimUnclaimedSession(request.PlayerAccountId, request.CharacterId); return Ok(new ZoneServerTryClaimSessionResponse(sessionClaimed ? ZoneServerTryClaimSessionResponseCode.Success : ZoneServerTryClaimSessionResponseCode.GeneralServerError)); //TODO }
/// <inheritdoc /> public async Task <HubOnConnectionState> OnConnected(Hub hubConnectedTo) { //TODO: Verify that the character they requested is owned by them. ProjectVersionStage.AssertAlpha(); NetworkEntityGuid guid = new NetworkEntityGuidBuilder() .WithId(int.Parse(hubConnectedTo.Context.UserIdentifier)) .WithType(EntityType.Player) .Build(); HubOnConnectionState state = await TryRequestCharacterGuildStatus(guid, hubConnectedTo.Context.UserIdentifier) .ConfigureAwaitFalse(); if (state == HubOnConnectionState.Success) { await RegisterGuildOnExistingResponse(guid, hubConnectedTo.Groups, hubConnectedTo.Context.ConnectionId) .ConfigureAwaitFalseVoid(); return(HubOnConnectionState.Success); } //Just error, we don't need to abort. Something didn't work right though. return(HubOnConnectionState.Error); }
/// <inheritdoc /> public override async Task HandleMessage(IPeerSessionMessageContext <GameServerPacketPayload> context, ClientSessionClaimRequestPayload payload) { //TODO: We need better validation/authorization for clients trying to claim a session. Right now it's open to malicious attack ZoneServerTryClaimSessionResponse zoneServerTryClaimSessionResponse = null; try { ProjectVersionStage.AssertAlpha(); zoneServerTryClaimSessionResponse = await GameServerClient.TryClaimSession(new ZoneServerTryClaimSessionRequest(await GameServerClient.GetAccountIdFromToken(payload.JWT), payload.CharacterId)) .ConfigureAwaitFalse(); } catch (Exception e) //we could get an unauthorized response { Logger.Error($"Failed to Query for AccountId: {e.Message}. AuthToken provided was: {payload.JWT}"); throw; } if (!zoneServerTryClaimSessionResponse.isSuccessful) { if (Logger.IsWarnEnabled) { Logger.Warn($"Client attempted to claim session for Character: {payload.CharacterId} but was denied."); } //TODO: Better error code await context.PayloadSendService.SendMessage(new ClientSessionClaimResponsePayload(ClientSessionClaimResponseCode.SessionUnavailable)) .ConfigureAwaitFalse(); return; } NetworkEntityGuid entityGuid = new NetworkEntityGuidBuilder() .WithId(payload.CharacterId) .WithType(EntityType.Player) .Build(); //TODO: We assume they are authenticated, we don't check at the moment but we WILL and SHOULD. Just load their location. ZoneServerCharacterLocationResponse locationResponse = await GameServerClient.GetCharacterLocation(payload.CharacterId) .ConfigureAwaitFalse(); Vector3 position = locationResponse.isSuccessful ? locationResponse.Position : SpawnPointProvider.GetSpawnPoint().WorldPosition; SpawnPointData pointData = new SpawnPointData(position, Quaternion.identity); if (Logger.IsDebugEnabled) { Logger.Debug($"Recieved player location: {pointData.WorldPosition} from {(locationResponse.isSuccessful ? "Database" : "Spawnpoint")}"); } //TODO: We need a cleaner/better way to load initial player data. ResponseModel <CharacterDataInstance, CharacterDataQueryReponseCode> characterData = await CharacterService.GetCharacterData(payload.CharacterId); //TODO: Check success. InitialCharacterDataMappable.AddObject(entityGuid, characterData.Result); //Just broadcast successful claim, let listeners figure out what to do with this information. OnSuccessfulSessionClaimed?.Invoke(this, new PlayerSessionClaimedEventArgs(entityGuid, pointData.WorldPosition, new PlayerEntitySessionContext(context.PayloadSendService, context.Details.ConnectionId, context.ConnectionService))); await context.PayloadSendService.SendMessage(new ClientSessionClaimResponsePayload(ClientSessionClaimResponseCode.Success)) .ConfigureAwaitFalse(); }
void Start() { //TODO: Camera.main is SLOW. ProjectVersionStage.AssertAlpha(); LookTransform = Camera.main.transform; }
/// <inheritdoc /> public Task <bool> CanUserAccessWorldContet(int userId, long worldId) { //TODO: When this project leaves alpha, we should probably handle the download authorization validator. ProjectVersionStage.AssertAlpha(); return(Task.FromResult <bool>(true)); }