public async Task StepAsync(CancellationToken cancellationToken) { try { if (player != null) { var builder = new FlatBufferBuilder(1); lock (world.Bodies) // wrong kind of lock but might do for now { // First try to focus camera on the player if they have // a fleet alive; var followFleet = player?.Fleet; // if the player doesn't have a fleet alive if (followFleet == null) { // check to see if they are spectating a fleet that's alive if (SpectatingFleet != null && SpectatingFleet.Exists) { followFleet = SpectatingFleet; } } if (followFleet == null) { // find someone else to watch followFleet = Player.GetWorldPlayers(world) .ToList() .Where(p => p.IsAlive) .OrderByDescending(p => p.Score * 10000 + (10000 - p.Fleet?.ID ?? 0)) .FirstOrDefault() ?.Fleet; } Body followBody = null; // if we're watching a fleet, watch the center of their fleet if (followFleet != null) { if (world.Hook.FollowFirstShip) { followBody = followFleet.Ships.FirstOrDefault(); } else { var center = FleetMath.FleetCenterNaive(followFleet.Ships); followBody = new Body { DefinitionTime = world.Time, OriginalPosition = center, Position = center, Momentum = followFleet.FleetMomentum }; } } // we've found someone to spectate, record it if (followFleet != player?.Fleet && followFleet != SpectatingFleet) { SpectatingFleet = followFleet; } // if we haven't found anything to watch yet, watch the first ship we find if (followBody == null) { followBody = player?.World.Bodies.OfType <Ship>().FirstOrDefault(); } // if we haven't found anything to watch yet, watch anything if (followBody == null) { followBody = player?.World.Bodies.FirstOrDefault(); } if (followBody != null) { var size = 6000; var viewportHeight = size * 2; var viewportWidth = size * 2; var playerViewport = new Envelope( followBody.Position.X - viewportWidth / 2, followBody.Position.Y - viewportHeight / 2, followBody.Position.X + viewportWidth / 2, followBody.Position.Y + viewportHeight / 2 ); BodyCache.Update( world.BodiesNear(playerViewport).ToList(), world.Time ); var updates = BodyCache.BodiesByError(); var updateBodies = updates.Take((int)this.Bandwidth); float VELOCITY_SCALE_FACTOR = 5000; var updatedGroups = BodyCache.GroupsByError().ToList(); var groupsVector = NetWorldView.CreateGroupsVector(builder, updatedGroups.Select(b => { var serverGroup = b.GroupUpdated; var caption = builder.CreateString(serverGroup.Caption ?? " "); var color = builder.CreateString(serverGroup.Color ?? ""); var customData = builder.CreateString(serverGroup.CustomData ?? ""); var group = NetGroup.CreateNetGroup(builder, group: serverGroup.ID, type: (byte)serverGroup.GroupType, captionOffset: caption, zindex: serverGroup.ZIndex, owner: serverGroup.OwnerID, colorOffset: color, customDataOffset: customData ); return(group); }).ToArray()); foreach (var update in updatedGroups) { update.GroupClient = update.GroupUpdated.Clone(); } var groupDeletesVector = NetWorldView.CreateGroupDeletesVector(builder, BodyCache.CollectStaleGroups().Select(b => b.GroupUpdated.ID ).ToArray()); NetWorldView.StartUpdatesVector(builder, updateBodies.Count()); foreach (var b in updateBodies) { var serverBody = b.BodyUpdated; var body = NetBody.CreateNetBody(builder, Id: serverBody.ID, DefinitionTime: serverBody.DefinitionTime, originalPosition_X: (short)serverBody.OriginalPosition.X, originalPosition_Y: (short)serverBody.OriginalPosition.Y, velocity_X: (short)(serverBody.Momentum.X * VELOCITY_SCALE_FACTOR), velocity_Y: (short)(serverBody.Momentum.Y * VELOCITY_SCALE_FACTOR), OriginalAngle: (sbyte)(serverBody.OriginalAngle / MathF.PI * 127), AngularVelocity: (sbyte)(serverBody.AngularVelocity * 10000), Size: (byte)(serverBody.Size / 5), Sprite: (ushort)serverBody.Sprite, Mode: serverBody.Mode, Group: serverBody.Group?.ID ?? 0); } var updatesVector = builder.EndVector(); foreach (var update in updateBodies) { update.BodyClient = update.BodyUpdated.Clone(); } var deletesVector = NetWorldView.CreateDeletesVector(builder, BodyCache.CollectStaleBuckets().Select(b => b.BodyUpdated.ID ).ToArray()); var messages = player.GetMessages(); VectorOffset announcementsVector = new VectorOffset(); if (messages != null && messages.Any()) { announcementsVector = NetWorldView.CreateAnnouncementsVector(builder, messages.Select(e => { var stringType = builder.CreateString(e.Type); var stringMessage = builder.CreateString(e.Message); var stringExtraData = e.ExtraData != null ? builder.CreateString(JsonConvert.SerializeObject(e.ExtraData)) : new StringOffset(); NetAnnouncement.StartNetAnnouncement(builder); NetAnnouncement.AddType(builder, stringType); NetAnnouncement.AddText(builder, stringMessage); if (e.ExtraData != null) { NetAnnouncement.AddExtraData(builder, stringExtraData); } NetAnnouncement.AddPointsDelta(builder, e.PointsDelta); return(NetAnnouncement.EndNetAnnouncement(builder)); }).ToArray()); } StringOffset customOffset = new StringOffset(); if (followFleet?.CustomData != null && followFleet.CustomData != CustomData) { customOffset = builder.CreateString(followFleet.CustomData); } NetWorldView.StartNetWorldView(builder); // define camera var cameraBody = NetBody.CreateNetBody( builder, Id: 0, DefinitionTime: followBody?.DefinitionTime ?? 0, originalPosition_X: (short)(followBody?.OriginalPosition.X ?? 0), originalPosition_Y: (short)(followBody?.OriginalPosition.Y ?? 0), velocity_X: (short)(followBody?.Momentum.X * VELOCITY_SCALE_FACTOR ?? 0), velocity_Y: (short)(followBody?.Momentum.Y * VELOCITY_SCALE_FACTOR ?? 0), OriginalAngle: (sbyte)(followBody?.OriginalAngle / MathF.PI / 127 ?? 0), AngularVelocity: 0, Size: 0, Sprite: 0, Mode: 0, Group: 0 ); NetWorldView.AddCamera(builder, cameraBody); NetWorldView.AddIsAlive(builder, player?.IsAlive ?? false); NetWorldView.AddTime(builder, world.Time); NetWorldView.AddUpdates(builder, updatesVector); NetWorldView.AddDeletes(builder, deletesVector); NetWorldView.AddGroups(builder, groupsVector); NetWorldView.AddGroupDeletes(builder, groupDeletesVector); if (messages != null && messages.Any()) { NetWorldView.AddAnnouncements(builder, announcementsVector); } if (followFleet?.CustomData != null && followFleet.CustomData != CustomData) { NetWorldView.AddCustomData(builder, customOffset); } CustomData = followFleet?.CustomData; var players = Player.GetWorldPlayers(world); NetWorldView.AddPlayerCount(builder, (uint)world.AdvertisedPlayerCount); NetWorldView.AddSpectatorCount(builder, (uint)players.Count(p => p.Connection?.IsSpectating ?? false)); NetWorldView.AddCooldownBoost(builder, (byte)((player?.Fleet?.BoostCooldownStatus * 255) ?? 0)); NetWorldView.AddCooldownShoot(builder, (byte)((player?.Fleet?.ShootCooldownStatus * 255) ?? 0)); NetWorldView.AddWorldSize(builder, (ushort)world.Hook.WorldSize); if (followFleet != null) { // inform the client of which the fleet id NetWorldView.AddFleetID(builder, (uint)followFleet.ID); } else { NetWorldView.AddFleetID(builder, 0); } var worldView = NetWorldView.EndNetWorldView(builder); var newHash = world.Hook.GetHashCode(); if (HookHash != newHash) { this.Events.Enqueue(new BroadcastEvent { EventType = "hook", Data = JsonConvert.SerializeObject(world.Hook) }); } HookHash = newHash; var q = NetQuantum.CreateNetQuantum(builder, AllMessages.NetWorldView, worldView.Value); builder.Finish(q.Value); } } await this.SendAsync(builder.DataBuffer, cancellationToken); if (LeaderboardTime != (world.Leaderboard?.Time ?? 0)) { LeaderboardTime = (world.Leaderboard?.Time ?? 0); builder = new FlatBufferBuilder(1); var stringName = builder.CreateString(world.Leaderboard?.ArenaRecord?.Name ?? " "); var stringColor = builder.CreateString(world.Leaderboard?.ArenaRecord?.Color ?? " "); NetLeaderboardEntry.StartNetLeaderboardEntry(builder); NetLeaderboardEntry.AddColor(builder, stringColor); NetLeaderboardEntry.AddName(builder, stringName); NetLeaderboardEntry.AddScore(builder, world.Leaderboard?.ArenaRecord?.Score ?? 0); NetLeaderboardEntry.AddToken(builder, !string.IsNullOrEmpty(world.Leaderboard?.ArenaRecord?.Token)); var record = NetLeaderboardEntry.EndNetLeaderboardEntry(builder); var entriesVector = NetLeaderboard.CreateEntriesVector(builder, world.Leaderboard.Entries.Select(e => { // the strings must be created into the buffer before the are referenced // and before the start of the entry object stringName = builder.CreateString(e.Name ?? string.Empty); stringColor = builder.CreateString(e.Color ?? string.Empty); StringOffset stringModeData = new StringOffset(); if (e.ModeData != null) { stringModeData = builder.CreateString(JsonConvert.SerializeObject(e.ModeData)); } // here's the start of the entry object, after this we can only use // predefined string offsets NetLeaderboardEntry.StartNetLeaderboardEntry(builder); NetLeaderboardEntry.AddFleetID(builder, e.FleetID); NetLeaderboardEntry.AddName(builder, stringName); NetLeaderboardEntry.AddColor(builder, stringColor); NetLeaderboardEntry.AddScore(builder, e.Score); NetLeaderboardEntry.AddPosition(builder, FromPositionVector(builder, e.Position)); NetLeaderboardEntry.AddToken(builder, !string.IsNullOrEmpty(e.Token)); if (e.ModeData != null) { NetLeaderboardEntry.AddModeData(builder, stringModeData); } return(NetLeaderboardEntry.EndNetLeaderboardEntry(builder)); }).ToArray()); var stringType = builder.CreateString(world.Leaderboard.Type ?? string.Empty); NetLeaderboard.StartNetLeaderboard(builder); NetLeaderboard.AddEntries(builder, entriesVector); NetLeaderboard.AddType(builder, stringType); NetLeaderboard.AddRecord(builder, record); var leaderboardOffset = NetLeaderboard.EndNetLeaderboard(builder); builder.Finish(NetQuantum.CreateNetQuantum(builder, AllMessages.NetLeaderboard, leaderboardOffset.Value).Value); await this.SendAsync(builder.DataBuffer, cancellationToken); } while (Events.Count > 0) { var e = Events.Dequeue(); var eventType = builder.CreateString(e.EventType); var eventData = builder.CreateString(e.Data); NetEvent.StartNetEvent(builder); NetEvent.AddType(builder, eventType); NetEvent.AddData(builder, eventData); var eventOffset = NetEvent.EndNetEvent(builder); builder.Finish(NetQuantum.CreateNetQuantum(builder, AllMessages.NetEvent, eventOffset.Value).Value); await this.SendAsync(builder.DataBuffer, cancellationToken); } } } catch (WebSocketException) { //Console.WriteLine(e); throw; } catch (Exception e) { Console.WriteLine(e); throw; } }
public async Task StepAsync(CancellationToken cancellationToken) { if (player != null) { // default to player var followFleet = player?.Fleet; // if the player doesn't have a fleet alive if (followFleet == null) { // find someone else to watch followFleet = Player.GetWorldPlayers(world) .ToList() .Where(p => p.IsAlive) .OrderByDescending(p => p.Score * 10000 + (10000 - p.Fleet.ID)) .FirstOrDefault() ?.Fleet; } Body followBody = null; // if we're watching a fleet, watch the center of their fleet if (followFleet != null) { var center = Core.Steering.Flocking.FleetCenterNaive(followFleet.Ships); followBody = new Body { DefinitionTime = world.Time, OriginalPosition = center, Position = center, Momentum = followFleet.FleetMomentum }; } // if we haven't found anything to watch yet, watch the first ship we find if (followBody == null) { followBody = player?.World.Bodies.OfType <Ship>().FirstOrDefault(); } // if we haven't found anything to watch yet, watch anything if (followBody == null) { followBody = player?.World.Bodies.FirstOrDefault(); } if (followBody != null) { var halfViewport = new Vector2(3000, 3000); BodyCache.Update( world.Bodies, world.Groups, world.Time, Vector2.Subtract(followBody.Position, halfViewport), Vector2.Add(followBody.Position, halfViewport) ); var updates = BodyCache.BodiesByError(); var updateBodies = updates.Take(100); var newHash = world.Hook.GetHashCode(); var builder = new FlatBufferBuilder(1); float VELOCITY_SCALE_FACTOR = 10000f; var updatedGroups = BodyCache.GroupsByError().ToList(); var groupsVector = NetWorldView.CreateGroupsVector(builder, updatedGroups.Select(b => { var serverGroup = b.GroupUpdated; var caption = builder.CreateString(serverGroup.Caption ?? " "); var group = NetGroup.CreateNetGroup(builder, group: serverGroup.ID, type: serverGroup.GroupType, captionOffset: caption, zindex: serverGroup.ZIndex ); return(group); }).ToArray()); foreach (var update in updatedGroups) { update.GroupClient = update.GroupUpdated.Clone(); } var groupDeletesVector = NetWorldView.CreateGroupDeletesVector(builder, BodyCache.CollectStaleGroups().Select(b => b.GroupUpdated.ID ).ToArray()); NetWorldView.StartUpdatesVector(builder, updateBodies.Count()); foreach (var b in updateBodies) { var serverBody = b.BodyUpdated; var body = NetBody.CreateNetBody(builder, Id: serverBody.ID, DefinitionTime: serverBody.DefinitionTime, originalPosition_X: (short)serverBody.OriginalPosition.X, originalPosition_Y: (short)serverBody.OriginalPosition.Y, velocity_X: (short)(serverBody.Momentum.X * VELOCITY_SCALE_FACTOR), velocity_Y: (short)(serverBody.Momentum.Y * VELOCITY_SCALE_FACTOR), OriginalAngle: (sbyte)(serverBody.OriginalAngle / MathF.PI * 127), AngularVelocity: (sbyte)(serverBody.AngularVelocity * VELOCITY_SCALE_FACTOR / MathF.PI * 127), Size: (byte)(serverBody.Size / 5), Sprite: (byte)serverBody.Sprite, Mode: 0, Group: serverBody.Group?.ID ?? 0); } var updatesVector = builder.EndVector(); foreach (var update in updateBodies) { update.BodyClient = update.BodyUpdated.Clone(); } var deletesVector = NetWorldView.CreateDeletesVector(builder, BodyCache.CollectStaleBuckets().Select(b => b.BodyUpdated.ID ).ToArray()); var messages = player.GetMessages(); VectorOffset announcementsVector = new VectorOffset(); if (messages != null && messages.Any()) { announcementsVector = NetWorldView.CreateAnnouncementsVector(builder, messages.Select(e => { var stringName = builder.CreateString(e); NetAnnouncement.StartNetAnnouncement(builder); NetAnnouncement.AddText(builder, stringName); return(NetAnnouncement.EndNetAnnouncement(builder)); }).ToArray()); } NetWorldView.StartNetWorldView(builder); // define camera var cameraBody = NetBody.CreateNetBody( builder, Id: 0, DefinitionTime: followBody?.DefinitionTime ?? 0, originalPosition_X: (short)(followBody?.OriginalPosition.X ?? 0), originalPosition_Y: (short)(followBody?.OriginalPosition.Y ?? 0), velocity_X: (short)(followBody?.Momentum.X * VELOCITY_SCALE_FACTOR ?? 0), velocity_Y: (short)(followBody?.Momentum.Y * VELOCITY_SCALE_FACTOR ?? 0), OriginalAngle: (sbyte)(followBody?.OriginalAngle / MathF.PI / 127 ?? 0), AngularVelocity: 0, Size: 0, Sprite: 0, Mode: 0, Group: 0 ); NetWorldView.AddCamera(builder, cameraBody); NetWorldView.AddIsAlive(builder, player?.IsAlive ?? false); NetWorldView.AddTime(builder, world.Time); NetWorldView.AddUpdates(builder, updatesVector); NetWorldView.AddDeletes(builder, deletesVector); NetWorldView.AddGroups(builder, groupsVector); NetWorldView.AddGroupDeletes(builder, groupDeletesVector); if (messages != null && messages.Any()) { NetWorldView.AddAnnouncements(builder, announcementsVector); } var worldView = NetWorldView.EndNetWorldView(builder); HookHash = newHash; var q = NetQuantum.CreateNetQuantum(builder, AllMessages.NetWorldView, worldView.Value); builder.Finish(q.Value); await this.SendAsync(builder.DataBuffer, cancellationToken); } if (LeaderboardTime != (world.Leaderboard?.Time ?? 0)) { LeaderboardTime = (world.Leaderboard?.Time ?? 0); var builder = new FlatBufferBuilder(1); var stringName = builder.CreateString(world.Leaderboard?.ArenaRecord?.Name ?? " "); var stringColor = builder.CreateString(world.Leaderboard?.ArenaRecord?.Color ?? " "); NetLeaderboardEntry.StartNetLeaderboardEntry(builder); NetLeaderboardEntry.AddColor(builder, stringColor); NetLeaderboardEntry.AddName(builder, stringName); NetLeaderboardEntry.AddScore(builder, world.Leaderboard?.ArenaRecord?.Score ?? 0); NetLeaderboardEntry.AddToken(builder, !string.IsNullOrEmpty(world.Leaderboard?.ArenaRecord?.Token)); var record = NetLeaderboardEntry.EndNetLeaderboardEntry(builder); var entriesVector = NetLeaderboard.CreateEntriesVector(builder, world.Leaderboard.Entries.Select(e => { stringName = builder.CreateString(e.Name ?? string.Empty); stringColor = builder.CreateString(e.Color ?? string.Empty); // stringToken = builder.CreateString( ?? string.Empty); NetLeaderboardEntry.StartNetLeaderboardEntry(builder); NetLeaderboardEntry.AddName(builder, stringName); NetLeaderboardEntry.AddColor(builder, stringColor); NetLeaderboardEntry.AddScore(builder, e.Score); NetLeaderboardEntry.AddPosition(builder, FromPositionVector(builder, e.Position)); NetLeaderboardEntry.AddToken(builder, !string.IsNullOrEmpty(e.Token)); return(NetLeaderboardEntry.EndNetLeaderboardEntry(builder)); }).ToArray()); var stringType = builder.CreateString(world.Leaderboard.Type ?? string.Empty); NetLeaderboard.StartNetLeaderboard(builder); NetLeaderboard.AddEntries(builder, entriesVector); NetLeaderboard.AddType(builder, stringType); NetLeaderboard.AddRecord(builder, record); var leaderboardOffset = NetLeaderboard.EndNetLeaderboard(builder); builder.Finish(NetQuantum.CreateNetQuantum(builder, AllMessages.NetLeaderboard, leaderboardOffset.Value).Value); await this.SendAsync(builder.DataBuffer, cancellationToken); } } }