Skip to content

Commit

Permalink
Expanded the lobby host abilities and tests to match.
Browse files Browse the repository at this point in the history
  • Loading branch information
RGBKnights committed Feb 13, 2022
1 parent 334916d commit c6a5d4d
Show file tree
Hide file tree
Showing 2 changed files with 190 additions and 30 deletions.
152 changes: 147 additions & 5 deletions src/DotaGameCoordinatorHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
using SteamKit2.Internal;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Timers;

Expand Down Expand Up @@ -41,9 +43,12 @@ public DotaGameCoordinatorHandler(SteamClient client, Games appId, ESourceEngine
MapLocationStates = new Dictionary<int, CSODOTAMapLocationState>(2); // Generally this seems to be 2
ChatChannels = new List<CMsgDOTAJoinChatChannelResponse>(1); // Lobby

this.Lobby = null;
this.AbilityDraftLobbyDetails = null;

_gcConnectTimer = new Timer(30000);
_gcConnectTimer.AutoReset = true;
_gcConnectTimer.Elapsed += (s,e) => SayHello();
_gcConnectTimer.Elapsed += (s, e) => SayHello();
}

/// <summary>
Expand All @@ -60,7 +65,7 @@ public DotaGameCoordinatorHandler(SteamClient client, Games appId, ESourceEngine
/// Is the GC ready?
/// </summary>
public bool Ready { get; private set; }

/// <summary>
/// The underlying SteamClient.
/// </summary>
Expand All @@ -71,6 +76,7 @@ public DotaGameCoordinatorHandler(SteamClient client, Games appId, ESourceEngine
/// </summary>
/// <value>The lobby.</value>
public CSODOTALobby Lobby { get; private set; }
private CMsgPracticeLobbySetDetails.AbilityDraftSpecificDetails AbilityDraftLobbyDetails { get; set; }

/// <summary>
/// Econ items.
Expand All @@ -92,18 +98,33 @@ public DotaGameCoordinatorHandler(SteamClient client, Games appId, ESourceEngine
/// </summary>
public List<CMsgDOTAJoinChatChannelResponse> ChatChannels { get; private set; }

private static void CopyProperties<T>(T dest, T src)
{
foreach (PropertyDescriptor item in TypeDescriptor.GetProperties(src))
item.SetValue(dest, item.GetValue(src));
}

/// <summary>
/// Sends a game coordinator message.
/// </summary>
/// <param name="msg">The GC message to send.</param>
public void Send(IClientGCMsg msg)
{
var clientMsg = new ClientMsgProtobuf<CMsgGCClient>(EMsg.ClientToGC);

clientMsg.Body.msgtype = MsgUtil.MakeGCMsg(msg.MsgType, msg.IsProto);
clientMsg.Body.appid = (uint)GameId;
clientMsg.Body.payload = msg.Serialize();

Client.Send(clientMsg);
}

public void Send(IClientGCMsg msg, JobID id)
{
var clientMsg = new ClientMsgProtobuf<CMsgGCClient>(EMsg.ClientToGC);
clientMsg.Body.msgtype = MsgUtil.MakeGCMsg(msg.MsgType, msg.IsProto);
clientMsg.Body.appid = (uint)GameId;
clientMsg.Body.payload = msg.Serialize();
clientMsg.SourceJobID = id;

Client.Send(clientMsg);
}
Expand Down Expand Up @@ -240,9 +261,95 @@ public void CreateLobby(CMsgPracticeLobbySetDetails details)
if (string.IsNullOrWhiteSpace(create.Body.search_key))
create.Body.search_key = "";

this.AbilityDraftLobbyDetails = details.ability_draft_specific_details;

Send(create);
}

/// <summary>
/// Shuffle the current lobby
/// </summary>
public CMsgPracticeLobbySetDetails GetLobbyDetails()
{
if (this.Lobby is null)
throw new InvalidOperationException("Can not update a looby that dose not exist");

var details = new CMsgPracticeLobbySetDetails()
{
lobby_id = this.Lobby.lobby_id,
game_name = this.Lobby.game_name,
pass_key = this.Lobby.pass_key,
server_region = this.Lobby.server_region,
game_mode = this.Lobby.game_mode,
allow_cheats = this.Lobby.allow_cheats,
fill_with_bots = this.Lobby.fill_with_bots,
allow_spectating = this.Lobby.allow_spectating,
dota_tv_delay = this.Lobby.dota_tv_delay,
pause_setting = this.Lobby.pause_setting,
game_version = this.Lobby.game_version,
visibility = this.Lobby.visibility,
};

if (Lobby.team_details != null)
details.team_details.AddRange(this.Lobby.team_details);

//if(this.AbilityDraftLobbyDetails != null)
// details.ability_draft_specific_details = this.AbilityDraftLobbyDetails;

if (this.Lobby.requested_hero_ids != null)
details.requested_hero_ids.AddRange(this.Lobby.requested_hero_ids);

return details;
}


/// <summary>
/// Change the details of an existing lobby.
/// </summary>
/// <param name="details">Lobby details overrides.</param>
public void SetLobbyDetails(CMsgPracticeLobbySetDetails details)
{
var update = new ClientGCMsgProtobuf<CMsgPracticeLobbySetDetails>((uint)EDOTAGCMsg.k_EMsgGCPracticeLobbySetDetails);

// there's no way to pass a pre-allocated body, so copy the params
update.Body.allchat = details.allchat;
update.Body.allow_cheats = details.allow_cheats;
update.Body.allow_spectating = details.allow_spectating;
update.Body.bot_difficulty_dire = details.bot_difficulty_dire;
update.Body.bot_difficulty_radiant = details.bot_difficulty_radiant;
update.Body.bot_dire = details.bot_dire;
update.Body.bot_radiant = details.bot_radiant;
update.Body.dire_series_wins = details.dire_series_wins;
update.Body.dota_tv_delay = details.dota_tv_delay;
update.Body.fill_with_bots = details.fill_with_bots;
update.Body.game_mode = details.custom_difficulty;
update.Body.game_name = details.game_name;
update.Body.game_version = details.game_version;
update.Body.lobby_id = details.lobby_id;
update.Body.pass_key = details.pass_key;
update.Body.pause_setting = details.pause_setting;
update.Body.server_region = details.server_region;
update.Body.visibility = details.visibility;
//update.Body.leagueid = details.leagueid;
//update.Body.previous_match_override = details.previous_match_override;
//update.Body.radiant_series_wins = details.radiant_series_wins;
//update.Body.selection_priority_rules = details.selection_priority_rules;
//update.Body.series_type = details.series_type;
//update.Body.cm_pick = details.cm_pick;

update.Body.ability_draft_specific_details = details.ability_draft_specific_details;
//if(details.ability_draft_specific_details != null)
//update.Body.ability_draft_specific_details = details.ability_draft_specific_details;

if (details.team_details != null)
update.Body.team_details.AddRange(details.team_details);

if (details.requested_hero_ids != null)
update.Body.requested_hero_ids.AddRange(details.requested_hero_ids);

Send(update);
}


/// <summary>
/// Invite someone to the existing lobby.
Expand Down Expand Up @@ -300,6 +407,7 @@ public void JoinChatChannel(string name, DOTAChatChannelType_t type = DOTAChatCh
var joinChannel = new ClientGCMsgProtobuf<CMsgDOTAJoinChatChannel>((uint)EDOTAGCMsg.k_EMsgGCJoinChatChannel);
joinChannel.Body.channel_name = name;
joinChannel.Body.channel_type = type;

Send(joinChannel);
}

Expand Down Expand Up @@ -363,12 +471,27 @@ public void PracticeLobbyList(string passKey = null)
/// <summary>
/// Shuffle the current lobby
/// </summary>
public void PracticeLobbyShuffle()
public void PracticeLobbyShuffleTeam()
{
var shuffle = new ClientGCMsgProtobuf<CMsgBalancedShuffleLobby>((uint)EDOTAGCMsg.k_EMsgGCBalancedShuffleLobby);
Send(shuffle);
}

/// <summary>
/// Shuffle the current lobby
/// </summary>
public void PracticeLobbyShuffleDraftOrder(bool value)
{
var details = this.GetLobbyDetails();

details.ability_draft_specific_details = new CMsgPracticeLobbySetDetails.AbilityDraftSpecificDetails()
{
shuffle_draft_order = value
};

this.SetLobbyDetails(details);
}

/// <summary>
/// Flip the teams in the current lobby
/// </summary>
Expand All @@ -379,6 +502,23 @@ public void PracticeLobbyFlip()
}


/// <summary>
/// Set hero roster for lobby
/// </summary>
public void PracticeLobbySetRoster(IReadOnlyList<uint> roster)
{
var details = this.GetLobbyDetails();
details.requested_hero_ids.Clear();
details.requested_hero_ids.AddRange(roster);
this.SetLobbyDetails(details);
}

public void PracticeLobbySetRoster(params uint[] roster)
{
this.PracticeLobbySetRoster(roster.ToList());
}


/// <summary>
/// Packet GC message.
/// </summary>
Expand Down Expand Up @@ -508,6 +648,7 @@ public void HandleCacheDestroy(IPacketGCMsg obj)
if (Lobby != null && dest.Body.type_id == (int)CSOTypes.LOBBY)
{
Lobby = null;
this.AbilityDraftLobbyDetails = null;
Client.PostCallback(new PracticeLobbyLeave(null));
}
}
Expand All @@ -518,6 +659,7 @@ private void HandleCacheUnsubscribed(IPacketGCMsg obj)
if (Lobby != null && unSub.Body.owner_soid.id == Lobby.lobby_id)
{
Lobby = null;
this.AbilityDraftLobbyDetails = null;
Client.PostCallback(new PracticeLobbyLeave(unSub.Body));
}
else
Expand Down Expand Up @@ -796,4 +938,4 @@ internal enum CSOTypes : int
/// </summary>
LOBBYINVITE = 2011
}
}
}
68 changes: 43 additions & 25 deletions test/ConsoleHostedService .cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,13 @@ private void DoWork()
var client = new SteamClient();
client.AddHandler(new DotaGameCoordinatorHandler(client));

var apps = client.GetHandler<SteamApps>();
var steam = client.GetHandler<SteamGameCoordinator>();
//var apps = client.GetHandler<SteamApps>();
//var steam = client.GetHandler<SteamGameCoordinator>();
var user = client.GetHandler<SteamUser>();
var friends = client.GetHandler<SteamFriends>();
var dota = client.GetHandler<DotaGameCoordinatorHandler>();

var chatTimer = new System.Timers.Timer(30000);
chatTimer.AutoReset = true;
chatTimer.Elapsed += (s,e) =>
{
var chanel = dota.ChatChannels.FirstOrDefault();
if(chanel is not null)
{
dota.SendChannelMessage(chanel.channel_id, "Hello! I accept following commands: START, STOP, FLIP, SHUFFLE");
}
};


var callbacks = new CallbackManager(client);
callbacks.Subscribe<SteamClient.ConnectedCallback>((_) =>
Expand All @@ -91,8 +82,6 @@ private void DoWork()

friends.SetPersonaState(EPersonaState.Offline);

chatTimer.Stop();

client.Disconnect();
});

Expand Down Expand Up @@ -138,14 +127,13 @@ private void DoWork()
dota_tv_delay = LobbyDotaTVDelay.LobbyDotaTV_300,
pause_setting = LobbyDotaPauseSetting.LobbyDotaPauseSetting_Unlimited,
game_version = DOTAGameVersion.GAME_VERSION_CURRENT,
visibility = DOTALobbyVisibility.DOTALobbyVisibility_Public,

visibility = DOTALobbyVisibility.DOTALobbyVisibility_Public
};
details.ability_draft_specific_details = new CMsgPracticeLobbySetDetails.AbilityDraftSpecificDetails
{
shuffle_draft_order = false
};
details.requested_hero_ids.AddRange(new List<uint> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 });
//details.ability_draft_specific_details = new CMsgPracticeLobbySetDetails.AbilityDraftSpecificDetails
//{
// shuffle_draft_order = false
//};
//details.requested_hero_ids.AddRange(new List<uint> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 });

dota.CreateLobby(details);
});
Expand All @@ -160,6 +148,7 @@ private void DoWork()
_logger.LogInformation("Joining Chat Channel");
var name = $"Lobby_{dota.Lobby.lobby_id}";
dota.JoinChatChannel(name, DOTAChatChannelType_t.DOTAChannelType_Lobby);

});
callbacks.Subscribe<JoinChatChannelResponse>((_) =>
{
Expand All @@ -178,13 +167,16 @@ private void DoWork()
dota.SendChannelMessage(response.channel_id, "Hello World! ");

_logger.LogInformation("Start Chat Loop");
chatTimer.Start();
});

callbacks.Subscribe<ChatMessage>(async (_) =>
{
switch(_.result.text.ToUpper())
var cmd = _.result.text.ToUpper();
switch (cmd)
{
case "HELP":
SendHelpMessage(dota);
break;
case "START":
await StartMatch(dota);
break;
Expand All @@ -194,16 +186,29 @@ private void DoWork()
case "FLIP":
dota.PracticeLobbyFlip();
break;
case "SHUFFLE":
dota.PracticeLobbyShuffle();
case "SHUFFLE TEAMS":
dota.PracticeLobbyShuffleTeam();
break;
case "SHUFFLE PLAYERS":
dota.PracticeLobbyShuffleDraftOrder(true);
break;
default:
_logger.LogInformation($"Chatter: user {_.result.persona_name} said: {_.result.text}");
break;
}

if(cmd.StartsWith("SET HEROES"))
{
var collection = cmd.Replace("SET HEROES", "");
var roster = collection.Split(",").Select(_ => uint.Parse(_)).ToList();
if(roster.Count == 12)
dota.PracticeLobbySetRoster(roster);
}
});
callbacks.Subscribe<PracticeLobbySnapshot>((_) =>
{
SendHelpMessage(dota);

var members = _.lobby.all_members.Select(_ => _.name).ToList();
_logger.LogInformation($"Practice Lobby Updated! Members: {string.Join(", ", members)}");
});
Expand All @@ -216,6 +221,19 @@ private void DoWork()
}
}

private void SendHelpMessage(DotaGameCoordinatorHandler dota)
{
_logger.LogInformation("Sending Help Message to Lobby Chat Channel (if it exists)");

var chanel = dota.ChatChannels.FirstOrDefault();
if (chanel is not null)
{
dota.SendChannelMessage(chanel.channel_id, "Hello!");
dota.SendChannelMessage(chanel.channel_id, "I accept following commands:");
dota.SendChannelMessage(chanel.channel_id, "START, STOP, FLIP, SHUFFLE TEAMS, SHUFFLE PLAYERS");
}
}

private async Task StartMatch(DotaGameCoordinatorHandler dota)
{
_logger.LogInformation("Count Down....");
Expand Down

0 comments on commit c6a5d4d

Please sign in to comment.