-
Notifications
You must be signed in to change notification settings - Fork 2
/
Bot2.cs
257 lines (221 loc) · 10.3 KB
/
Bot2.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using TwitchLib.Client;
using TwitchLib.Client.Enums;
using TwitchLib.Client.Events;
using TwitchLib.Client.Extensions;
using TwitchLib.Client.Models;
using TwitchLib.Communication.Clients;
using TwitchLib.Communication.Models;
public class Bot2
{
public static int TimeRemaining = 15;
private static System.Threading.Timer VoteEndTimer;
public delegate void UpdateLabelDelegate(string timeremaining);
public static UpdateLabelDelegate UpdateTimer;
public static UpdateLabelDelegate UpdateLeft;
public static UpdateLabelDelegate UpdateRight;
public static UpdateLabelDelegate UpdateForward;
public static UpdateLabelDelegate UpdateBack;
public static UpdateLabelDelegate UpdateList;
private static List<string> initialUserList = new List<string>();
private static List<string> HasVoted = new List<string>();
private static int VotedLeft = 0;
private static int VotedRight = 0;
private static int VotedForward = 0;
private static int VotedBackward = 0;
private const string SPEED = "255";
public static int DURATION = 1;
public static float TURN_DURATION = 0.5f;
private static string VEHICLE_API_URL;
private static string TWITCH_API_KEY;
TwitchClient client;
// pretty simple stuff here, all the movement API's are simple gets
// with querystring parameters. use of constants for speed and duration
// and base URL, just make the call, E.Z. P.Z.
public static void SendVehicleCommand(string command)
{
string URL = VEHICLE_API_URL;
if (command.ToLower() == "forward")
URL += command.ToLower() + "?speed=" + SPEED + "&duration=" + DURATION.ToString();
else if (command.ToLower() == "left" || command.ToLower() == "right")
URL += command.ToLower() + "?speed=" + SPEED + "&duration=" + TURN_DURATION.ToString();
else
URL += command.ToLower() + "?speed=" + SPEED + "&duration=" + DURATION.ToString();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Method = "GET";
try
{
WebResponse webResponse = request.GetResponse();
Stream webStream = webResponse.GetResponseStream();
StreamReader responseReader = new StreamReader(webStream);
string response = responseReader.ReadToEnd();
Console.Out.WriteLine(response);
responseReader.Close();
}
catch (Exception e)
{
Console.Out.WriteLine("-----------------");
Console.Out.WriteLine(e.Message);
}
}
// a vote has ended when this timer strikes
private void OnTimer(object state)
{
string Winner = "no votes";
int WinningCount = 0;
Random rnd = new Random();
TimeRemaining -= 1;
if (TimeRemaining == 0)
{
TimeRemaining = 15;
//the vote has ended clear out the list of
//people who already voted in preparation for
//the next vote
HasVoted.Clear();
if (VotedLeft > 0)
{
Winner = "Left";
WinningCount = VotedLeft;
}
if (VotedRight > 0 && VotedRight >= WinningCount)
{
// **tie breaker (this is true for every remaining vote as well, no copy paste comment)
// this looks a little bit confusing and I don't love the readability of it
// basically if the "VotedRight" is a greater count than the current winner we use it
// OR if its the SAME as the current winnter, we essentially flip a coin (Random.Next is
// exclusive so Next(0,2) will always return 0 or 1 and I hate that, it should be 0,1 and inclusive).
// If the result of the coin flip is a 1 we use Right as the winner, otherwise we keep the previous winner
if (VotedRight > WinningCount || (VotedRight == WinningCount && rnd.Next(0, 2) == 1))
{
Winner = "Right";
WinningCount = VotedRight;
}
}
if (VotedForward > 0 && VotedForward >= WinningCount)
{
if (VotedForward > WinningCount || (VotedForward == WinningCount && rnd.Next(0, 2) == 1))
{
Winner = "Forward";
WinningCount = VotedForward;
}
}
if (VotedBackward > 0 && VotedBackward >= WinningCount)
{
if (VotedBackward > WinningCount || (VotedBackward == WinningCount && rnd.Next(0, 2) == 1))
{
Winner = "Backward";
WinningCount = VotedBackward;
}
}
//update previous winners list
UpdateList(Winner);
//reset all the vote counts on the form
VotedLeft = 0;
UpdateLeft("0");
VotedRight = 0;
UpdateRight("0");
VotedForward = 0;
UpdateForward("0");
VotedBackward = 0;
UpdateBack("0");
client.SendMessage(client.JoinedChannels[0], "Vote ended, winner: " + Winner + ". New vote started.");
//tell the vehicle to move to do the move
SendVehicleCommand(Winner);
}
UpdateTimer.Invoke(TimeRemaining.ToString());
}
public Bot2(UpdateLabelDelegate TimeCallback, UpdateLabelDelegate LeftCallback, UpdateLabelDelegate RightCallback, UpdateLabelDelegate ForwardCallback, UpdateLabelDelegate BackCallback, UpdateLabelDelegate ListCallback)
{
// all the "Update" delegates are callbacks
// on the UI thread to update the UI
UpdateTimer = TimeCallback;
UpdateLeft = LeftCallback;
UpdateRight = RightCallback;
UpdateForward = ForwardCallback;
UpdateBack = BackCallback;
UpdateList = ListCallback;
//don't do this at home kids, this is an embarassingly bad way to make config files
string[] lines = System.IO.File.ReadAllLines(@"d:\dev\TwitchDrivesATV\config.txt");
VEHICLE_API_URL = lines[0];
TWITCH_API_KEY = lines[1];
VoteEndTimer = new System.Threading.Timer(OnTimer, null, 1000, 1000);
ConnectionCredentials credentials = new ConnectionCredentials("twitchDrivesATV", TWITCH_API_KEY);
var clientOptions = new ClientOptions
{
MessagesAllowedInPeriod = 750,
ThrottlingPeriod = TimeSpan.FromSeconds(30)
};
WebSocketClient customClient = new WebSocketClient(clientOptions);
client = new TwitchClient(customClient);
client.Initialize(credentials, "twitchDrivesATV");
client.OnLog += Client_OnLog;
client.OnJoinedChannel += Client_OnJoinedChannel;
client.OnMessageReceived += Client_OnMessageReceived;
client.OnWhisperReceived += Client_OnWhisperReceived;
client.OnNewSubscriber += Client_OnNewSubscriber;
client.OnConnected += Client_OnConnected;
client.Connect();
}
private void Client_OnLog(object sender, OnLogArgs e)
{
Console.WriteLine($"{e.DateTime.ToString()}: {e.BotUsername} - {e.Data}");
}
private void Client_OnConnected(object sender, OnConnectedArgs e)
{
client.SendMessage(client.JoinedChannels[0], "Let the Games Begin! New vote started.");
}
private void Client_OnJoinedChannel(object sender, OnJoinedChannelArgs e)
{
}
private void Client_OnMessageReceived(object sender, OnMessageReceivedArgs e)
{
// ok pretty simple stuff, there is no interval BETWEEN votes, so voting messages are always tallied
// twitch has a "copy paste" protection that even as the owner of the channel you can't remove
// that is you can't type EXACTLY the same message within a 30 second period.
// the problem this creates is that on a 15 second vote interval, you couldn't vote "right" twice
// for example. Since I cannot remove that restriction, the hack is to tell users
// to type right and Right or RIGHT or RiGhT. Since there is a change in case twitch lets it through
// I always convert the chat to lowercase so that I can just make one check for a vote type
// this first if, checks to see if the message comes from someone who
// has already voted this round. If they have voted, ignore them.
// this means that a person can only vote once, and once they have
// voted there is no way to change their vote, democracy at it's finest
if (!HasVoted.Contains(e.ChatMessage.Username.ToLower()))
{
if (e.ChatMessage.Message.ToLower() == "left" || e.ChatMessage.Message.ToLower() == "l")
{
VotedLeft += 1;
// add this person to the list of people who have voted
HasVoted.Add(e.ChatMessage.Username.ToLower());
UpdateLeft(VotedLeft.ToString());
}
else if (e.ChatMessage.Message.ToLower() == "right" || e.ChatMessage.Message.ToLower() == "r")
{
VotedRight += 1;
HasVoted.Add(e.ChatMessage.Username.ToLower());
UpdateRight(VotedRight.ToString());
}
else if (e.ChatMessage.Message.ToLower() == "forward" || e.ChatMessage.Message.ToLower() == "f")
{
VotedForward += 1;
HasVoted.Add(e.ChatMessage.Username.ToLower());
UpdateForward(VotedForward.ToString());
}
else if (e.ChatMessage.Message.ToLower() == "back" || e.ChatMessage.Message.ToLower() == "backward" || e.ChatMessage.Message.ToLower() == "")
{
VotedBackward += 1;
HasVoted.Add(e.ChatMessage.Username.ToLower());
UpdateBack(VotedBackward.ToString());
}
}
}
private void Client_OnWhisperReceived(object sender, OnWhisperReceivedArgs e)
{
}
private void Client_OnNewSubscriber(object sender, OnNewSubscriberArgs e)
{
}
}