protected override void OnGuildStatusChanged(GuildStatusChangedEventModel changeArgs) { //Don't need to get the guild list if we're guildless. if (changeArgs.IsGuildless) { return; } UnityAsyncHelper.UnityMainThreadContext.PostAsync(async() => { var rosterResponseModel = await SocialService.GetGuildListAsync(); if (!rosterResponseModel.isSuccessful) { if (Logger.IsWarnEnabled) { Logger.Warn($"Failed to query guild roster. Reason: {rosterResponseModel.ResultCode}"); } return; } //Now we can publish the roster. foreach (int rosterCharacterId in rosterResponseModel.Result.GuildedCharacterIds) { NetworkEntityGuid characterGuid = NetworkEntityGuidBuilder.New() .WithType(EntityType.Player) .WithId(rosterCharacterId) .Build(); //This is a hidden join, or the alerts would be spammed. GuildJoinEventPublisher.PublishEvent(this, new CharacterJoinedGuildEventArgs(characterGuid, true)); } }); }
private void OnChatMessageRecieved(ChatChannelType channelType, [NotNull] IChannelTextMessage args) { if (args == null) { throw new ArgumentNullException(nameof(args)); } if (!Enum.IsDefined(typeof(ChatChannelType), channelType)) { throw new InvalidEnumArgumentException(nameof(channelType), (int)channelType, typeof(ChatChannelType)); } AccountId id = args.Sender; int characterId = int.Parse(id.Name); //TODO: We need to translate the guid to a name. NetworkEntityGuid guid = NetworkEntityGuidBuilder.New() .WithType(EntityType.Player) .WithId(characterId) .Build(); if (NameQueryService.Exists(guid)) { PublishTextData(channelType, args, guid, NameQueryService.Retrieve(guid)); } else { UnityAsyncHelper.UnityMainThreadContext.PostAsync(async() => { string queryResponse = await NameQueryService.RetrieveAsync(guid) .ConfigureAwaitFalse(); PublishTextData(channelType, args, guid, queryResponse); }); } }
private void AddGameObjectInstances <TInstanceModelType>([NotNull] IReadOnlyCollection <TInstanceModelType> resultEntries) where TInstanceModelType : IGameObjectLinkable { if (resultEntries == null) { throw new ArgumentNullException(nameof(resultEntries)); } BehaviourInstanceDataMappable.Add(typeof(TInstanceModelType), new InstanceStaticEntityDataCollection <object>()); foreach (var instance in resultEntries) { if (Logger.IsInfoEnabled) { Logger.Info($"Processing {typeof(TInstanceModelType).Name} Data Instance: {instance.LinkedGameObjectId}"); } NetworkEntityGuid guid = new NetworkEntityGuidBuilder() .WithEntryId(instance.LinkedGameObjectId) .WithType(EntityType.GameObject) .Build(); BehaviourInstanceDataMappable[typeof(TInstanceModelType)].Add(guid, instance); } }
public NetworkEntityGuid Create(GameObjectInstanceModel context) { if (!context.Guid.isTemplateGuid) { throw new InvalidOperationException($"Cannot create instance {nameof(NetworkEntityGuid)} from non-Template {nameof(NetworkEntityGuid)}."); } NetworkEntityGuidBuilder builder = new NetworkEntityGuidBuilder(); return(builder.WithId(Interlocked.Increment(ref GameObjectCount)) .WithType(EntityType.GameObject) .WithEntryId(context.Guid.EntryId) .Build()); }
public CreatureInstanceModel Convert([NotNull] CreatureEntryModel fromObject) { if (fromObject == null) { throw new ArgumentNullException(nameof(fromObject)); } NetworkEntityGuid guid = new NetworkEntityGuidBuilder() .WithId(0) //0 means that it's not an instance. .WithType(EntityType.Creature) .WithEntryId(fromObject.CreatureEntryId) .Build(); //TODO: better handle position crap return(new CreatureInstanceModel(guid, fromObject.CreatureTemplateId, new Vector3(fromObject.SpawnPosition.X, fromObject.SpawnPosition.Y, fromObject.SpawnPosition.Z), fromObject.InitialOrientation)); }
//We don't currently use this. It was a good idea but may not be supported as usernames for vivox. private unsafe string ComputeCharacterString(int contextCharacterId) { NetworkEntityGuid playerGuid = new NetworkEntityGuidBuilder() .WithType(EntityType.Player) .WithId(contextCharacterId) .Build(); //Access raw memory of the guid. ulong playerRawGuid = playerGuid.RawGuidValue; byte *rawValue = (byte *)&playerRawGuid; //The idea here is we use the player's 64bit guid value directly //as the string character value. That way it can be moved to and from //the player guid efficiently. return(Encoding.ASCII.GetString(rawValue, sizeof(ulong))); }
/// <inheritdoc /> public async Task OnGameInitialized() { try { CharacterListResponse listResponse = await CharacterServiceQueryable.GetCharacters() .ConfigureAwaitFalse(); //TODO: Handle errors foreach (var character in listResponse.CharacterIds) { var entityGuid = new NetworkEntityGuidBuilder() .WithId(character) .WithType(EntityType.Player) .Build(); //TODO: Optimize below awaits. //Do a namequery so it's in the cache for when anything tries to get entities name. await EntityNameQueryable.RetrieveAsync(entityGuid) .ConfigureAwaitFalse(); var appearanceResponse = await CharacterServiceQueryable.GetCharacterAppearance(entityGuid.EntityId) .ConfigureAwaitFalse(); var characterData = await CharacterServiceQueryable.GetCharacterData(entityGuid.EntityId) .ConfigureAwaitFalse(); //Don't throw, because we actually don't want to stop the //character screen from working just because we can't visually display some stuff. if (!appearanceResponse.isSuccessful) { Logger.Error($"Failed to query for Character: {entityGuid.EntityId} appearance. Reason: {appearanceResponse.ResultCode}"); } //TODO: Handle errors. CharacterAppearanceMappable.AddObject(entityGuid, appearanceResponse.Result); InitialCharacterDataInstance.AddObject(entityGuid, characterData.Result); OnCharacterSelectionEntryChanged?.Invoke(this, new CharacterSelectionEntryDataChangeEventArgs(entityGuid)); } } catch (Exception e) { Logger.Error($"Encountered Error: {e.Message}"); throw; } }
protected override void OnEventFired(object source, EventArgs args) { UnityAsyncHelper.UnityMainThreadContext.PostAsync(async() => { CharacterFriendListResponseModel friendsResponse = await SocialService.GetCharacterListAsync(); foreach (int characterId in friendsResponse.CharacterFriendsId) { NetworkEntityGuid entityGuid = NetworkEntityGuidBuilder.New() .WithType(EntityType.Player) .WithId(characterId) .Build(); FriendAddedPublisher.PublishEvent(this, new CharacterFriendAddedEventArgs(entityGuid)); } }); }
/// <inheritdoc /> public override async Task OnDisconnectedAsync(Exception exception) { NetworkEntityGuid guid = new NetworkEntityGuidBuilder() .WithId(int.Parse(Context.UserIdentifier)) .WithType(EntityType.Player) .Build(); if (Logger.IsEnabled(LogLevel.Information)) { Logger.LogInformation($"About to attempt final cleanup for Entity: {guid}"); } foreach (var c in EntityRemovable) { c.RemoveEntityEntry(guid); } await base.OnDisconnectedAsync(exception); }
public async Task <IActionResult> ReverseNameQuery([FromRoute(Name = "name")][JetBrains.Annotations.NotNull] string characterPlayerName) { if (string.IsNullOrWhiteSpace(characterPlayerName)) { return(BuildFailedResponseModel(NameQueryResponseCode.UnknownIdError)); } bool knownId = await CharacterRepository.ContainsAsync(characterPlayerName); //TODO: JSON Response if (!knownId) { return(BuildFailedResponseModel(NameQueryResponseCode.UnknownIdError)); } //Else if it is a known id we should grab the name of the character CharacterEntryModel characterModel = await CharacterRepository.RetrieveAsync(characterPlayerName); return(BuildSuccessfulResponseModel(NetworkEntityGuidBuilder.New().WithType(EntityType.Player).WithId(characterModel.CharacterId).Build())); }
/// <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(); }