ssc.nob 0.1.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # frozen_string_literal: true
4
+
5
+ #--
6
+ # This file is part of SSC.Nob.
7
+ # Copyright (c) 2020 Jonathan Bradley Whited (@esotericpig)
8
+ #
9
+ # SSC.Nob is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # SSC.Nob is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with SSC.Nob. If not, see <https://www.gnu.org/licenses/>.
21
+ #++
22
+
23
+
24
+ module SSCNob
25
+ ###
26
+ # @author Jonathan Bradley Whited (@esotericpig)
27
+ # @since 0.1.0
28
+ ###
29
+ class Error < ::StandardError; end
30
+
31
+ class UserError < Error; end
32
+ end
@@ -0,0 +1,264 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # frozen_string_literal: true
4
+
5
+ #--
6
+ # This file is part of SSC.Nob.
7
+ # Copyright (c) 2020 Jonathan Bradley Whited (@esotericpig)
8
+ #
9
+ # SSC.Nob is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # SSC.Nob is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with SSC.Nob. If not, see <https://www.gnu.org/licenses/>.
21
+ #++
22
+
23
+
24
+ require 'java'
25
+ require 'time'
26
+
27
+ java_import 'java.awt.Robot'
28
+ java_import 'java.awt.Toolkit'
29
+
30
+ java_import 'java.awt.datatransfer.Clipboard'
31
+ java_import 'java.awt.datatransfer.ClipboardOwner'
32
+ java_import 'java.awt.datatransfer.StringSelection'
33
+
34
+ java_import 'java.awt.event.KeyEvent'
35
+
36
+
37
+ module SSCNob
38
+ ###
39
+ # @author Jonathan Bradley Whited (@esotericpig)
40
+ # @since 0.1.0
41
+ ###
42
+ class SSCBot
43
+ MESSAGE_FLOOD_COUNT = 8
44
+ MESSAGE_FLOOD_TIME = 5
45
+
46
+ attr_accessor :auto_delay_time
47
+ attr_reader :char_codes
48
+ attr_reader :clipboard
49
+ attr_reader :last_message_time
50
+ attr_reader :message_count
51
+ attr_accessor :message_key
52
+ attr_reader :robot
53
+
54
+ # TODO: save message_key in config
55
+ def initialize(auto_delay_time: 0.2,message_key: KeyEvent::VK_TAB)
56
+ super()
57
+
58
+ @auto_delay_time = auto_delay_time
59
+ @char_codes = {}
60
+ @clipboard = Toolkit.getDefaultToolkit().getSystemClipboard()
61
+ @last_message_time = Time.now()
62
+ @message_count = 0
63
+ @message_key = message_key
64
+ @robot = Robot.new()
65
+
66
+ @robot.setAutoDelay(0) # Don't use Java's, too slow
67
+
68
+ build_char_codes()
69
+ end
70
+
71
+ def auto_delay()
72
+ sleep(@auto_delay_time)
73
+
74
+ return self
75
+ end
76
+
77
+ def chat_message(channel,msg)
78
+ return pub_message(";#{channel};#{msg}")
79
+ end
80
+
81
+ def copy(str)
82
+ @clipboard.setContents(StringSelection.new(str),nil);
83
+
84
+ return self
85
+ end
86
+
87
+ def enter()
88
+ return type_key(KeyEvent::VK_ENTER)
89
+ end
90
+
91
+ def paste(str=nil)
92
+ copy(str) unless str.nil?()
93
+
94
+ # FIXME: change to VK_META for macOS
95
+ roll_keys(KeyEvent::VK_CONTROL,KeyEvent::VK_V)
96
+
97
+ return self
98
+ end
99
+
100
+ def prevent_flooding()
101
+ @message_count += 1
102
+
103
+ if @message_count >= MESSAGE_FLOOD_COUNT
104
+ time_diff = Time.now() - @last_message_time
105
+
106
+ if time_diff <= MESSAGE_FLOOD_TIME
107
+ sleep(MESSAGE_FLOOD_TIME - time_diff)
108
+ end
109
+
110
+ @message_count = 0
111
+ end
112
+
113
+ @last_message_time = Time.now()
114
+
115
+ return self
116
+ end
117
+
118
+ def pub_message(msg)
119
+ type_key(@message_key).paste(msg).enter()
120
+
121
+ sleep(1.2)
122
+
123
+ return self
124
+ end
125
+
126
+ def roll_keys(*key_codes)
127
+ key_codes.each() do |key_code|
128
+ @robot.keyPress(key_code)
129
+ auto_delay()
130
+ end
131
+
132
+ (key_codes.length - 1).downto(0) do |i|
133
+ @robot.keyRelease(key_codes[i])
134
+ auto_delay()
135
+ end
136
+
137
+ return self
138
+ end
139
+
140
+ def type(str)
141
+ str.each_char() do |c|
142
+ key_codes = @char_codes[c]
143
+
144
+ next if key_codes.nil?()
145
+
146
+ roll_keys(*key_codes)
147
+ end
148
+
149
+ return self
150
+ end
151
+
152
+ def type_key(key_code)
153
+ @robot.keyPress(key_code)
154
+ auto_delay()
155
+ @robot.keyRelease(key_code)
156
+ auto_delay()
157
+
158
+ return self
159
+ end
160
+
161
+ def build_char_codes()
162
+ @char_codes.store("\b",[KeyEvent::VK_BACK_SPACE])
163
+ @char_codes.store("\f",[KeyEvent::VK_PAGE_DOWN])
164
+ @char_codes.store("\n",[KeyEvent::VK_ENTER])
165
+ @char_codes.store("\r",[KeyEvent::VK_HOME])
166
+ @char_codes.store("\t",[KeyEvent::VK_TAB])
167
+ @char_codes.store(' ',[KeyEvent::VK_SPACE])
168
+ @char_codes.store('!',[KeyEvent::VK_SHIFT,KeyEvent::VK_EXCLAMATION_MARK])
169
+ @char_codes.store('"',[KeyEvent::VK_SHIFT,KeyEvent::VK_QUOTEDBL])
170
+ @char_codes.store('#',[KeyEvent::VK_SHIFT,KeyEvent::VK_3])
171
+ @char_codes.store('$',[KeyEvent::VK_SHIFT,KeyEvent::VK_4])
172
+ @char_codes.store('%',[KeyEvent::VK_SHIFT,KeyEvent::VK_5])
173
+ @char_codes.store('&',[KeyEvent::VK_SHIFT,KeyEvent::VK_7])
174
+ @char_codes.store('\'',[KeyEvent::VK_QUOTE])
175
+ @char_codes.store('(',[KeyEvent::VK_SHIFT,KeyEvent::VK_9])
176
+ @char_codes.store(')',[KeyEvent::VK_SHIFT,KeyEvent::VK_0])
177
+ @char_codes.store('*',[KeyEvent::VK_SHIFT,KeyEvent::VK_8])
178
+ @char_codes.store('+',[KeyEvent::VK_SHIFT,KeyEvent::VK_EQUALS])
179
+ @char_codes.store(',',[KeyEvent::VK_COMMA])
180
+ @char_codes.store('-',[KeyEvent::VK_MINUS])
181
+ @char_codes.store('.',[KeyEvent::VK_PERIOD])
182
+ @char_codes.store('/',[KeyEvent::VK_SLASH])
183
+ @char_codes.store('0',[KeyEvent::VK_0])
184
+ @char_codes.store('1',[KeyEvent::VK_1])
185
+ @char_codes.store('2',[KeyEvent::VK_2])
186
+ @char_codes.store('3',[KeyEvent::VK_3])
187
+ @char_codes.store('4',[KeyEvent::VK_4])
188
+ @char_codes.store('5',[KeyEvent::VK_5])
189
+ @char_codes.store('6',[KeyEvent::VK_6])
190
+ @char_codes.store('7',[KeyEvent::VK_7])
191
+ @char_codes.store('8',[KeyEvent::VK_8])
192
+ @char_codes.store('9',[KeyEvent::VK_9])
193
+ @char_codes.store(':',[KeyEvent::VK_SHIFT,KeyEvent::VK_COLON])
194
+ @char_codes.store(';',[KeyEvent::VK_SEMICOLON])
195
+ @char_codes.store('<',[KeyEvent::VK_LESS])
196
+ @char_codes.store('=',[KeyEvent::VK_EQUALS])
197
+ @char_codes.store('>',[KeyEvent::VK_SHIFT,KeyEvent::VK_GREATER])
198
+ @char_codes.store('?',[KeyEvent::VK_SHIFT,KeyEvent::VK_SLASH])
199
+ @char_codes.store('@',[KeyEvent::VK_SHIFT,KeyEvent::VK_AT])
200
+ @char_codes.store('A',[KeyEvent::VK_SHIFT,KeyEvent::VK_A])
201
+ @char_codes.store('B',[KeyEvent::VK_SHIFT,KeyEvent::VK_B])
202
+ @char_codes.store('C',[KeyEvent::VK_SHIFT,KeyEvent::VK_C])
203
+ @char_codes.store('D',[KeyEvent::VK_SHIFT,KeyEvent::VK_D])
204
+ @char_codes.store('E',[KeyEvent::VK_SHIFT,KeyEvent::VK_E])
205
+ @char_codes.store('F',[KeyEvent::VK_SHIFT,KeyEvent::VK_F])
206
+ @char_codes.store('G',[KeyEvent::VK_SHIFT,KeyEvent::VK_G])
207
+ @char_codes.store('H',[KeyEvent::VK_SHIFT,KeyEvent::VK_H])
208
+ @char_codes.store('I',[KeyEvent::VK_SHIFT,KeyEvent::VK_I])
209
+ @char_codes.store('J',[KeyEvent::VK_SHIFT,KeyEvent::VK_J])
210
+ @char_codes.store('K',[KeyEvent::VK_SHIFT,KeyEvent::VK_K])
211
+ @char_codes.store('L',[KeyEvent::VK_SHIFT,KeyEvent::VK_L])
212
+ @char_codes.store('M',[KeyEvent::VK_SHIFT,KeyEvent::VK_M])
213
+ @char_codes.store('N',[KeyEvent::VK_SHIFT,KeyEvent::VK_N])
214
+ @char_codes.store('O',[KeyEvent::VK_SHIFT,KeyEvent::VK_O])
215
+ @char_codes.store('P',[KeyEvent::VK_SHIFT,KeyEvent::VK_P])
216
+ @char_codes.store('Q',[KeyEvent::VK_SHIFT,KeyEvent::VK_Q])
217
+ @char_codes.store('R',[KeyEvent::VK_SHIFT,KeyEvent::VK_R])
218
+ @char_codes.store('S',[KeyEvent::VK_SHIFT,KeyEvent::VK_S])
219
+ @char_codes.store('T',[KeyEvent::VK_SHIFT,KeyEvent::VK_T])
220
+ @char_codes.store('U',[KeyEvent::VK_SHIFT,KeyEvent::VK_U])
221
+ @char_codes.store('V',[KeyEvent::VK_SHIFT,KeyEvent::VK_V])
222
+ @char_codes.store('W',[KeyEvent::VK_SHIFT,KeyEvent::VK_W])
223
+ @char_codes.store('X',[KeyEvent::VK_SHIFT,KeyEvent::VK_X])
224
+ @char_codes.store('Y',[KeyEvent::VK_SHIFT,KeyEvent::VK_Y])
225
+ @char_codes.store('Z',[KeyEvent::VK_SHIFT,KeyEvent::VK_Z])
226
+ @char_codes.store('[',[KeyEvent::VK_OPEN_BRACKET])
227
+ @char_codes.store('\\',[KeyEvent::VK_BACK_SLASH])
228
+ @char_codes.store(']',[KeyEvent::VK_CLOSE_BRACKET])
229
+ @char_codes.store('^',[KeyEvent::VK_SHIFT,KeyEvent::VK_CIRCUMFLEX])
230
+ @char_codes.store('_',[KeyEvent::VK_SHIFT,KeyEvent::VK_UNDERSCORE])
231
+ @char_codes.store('`',[KeyEvent::VK_BACK_QUOTE])
232
+ @char_codes.store('a',[KeyEvent::VK_A])
233
+ @char_codes.store('b',[KeyEvent::VK_B])
234
+ @char_codes.store('c',[KeyEvent::VK_C])
235
+ @char_codes.store('d',[KeyEvent::VK_D])
236
+ @char_codes.store('e',[KeyEvent::VK_E])
237
+ @char_codes.store('f',[KeyEvent::VK_F])
238
+ @char_codes.store('g',[KeyEvent::VK_G])
239
+ @char_codes.store('h',[KeyEvent::VK_H])
240
+ @char_codes.store('i',[KeyEvent::VK_I])
241
+ @char_codes.store('j',[KeyEvent::VK_J])
242
+ @char_codes.store('k',[KeyEvent::VK_K])
243
+ @char_codes.store('l',[KeyEvent::VK_L])
244
+ @char_codes.store('m',[KeyEvent::VK_M])
245
+ @char_codes.store('n',[KeyEvent::VK_N])
246
+ @char_codes.store('o',[KeyEvent::VK_O])
247
+ @char_codes.store('p',[KeyEvent::VK_P])
248
+ @char_codes.store('q',[KeyEvent::VK_Q])
249
+ @char_codes.store('r',[KeyEvent::VK_R])
250
+ @char_codes.store('s',[KeyEvent::VK_S])
251
+ @char_codes.store('t',[KeyEvent::VK_T])
252
+ @char_codes.store('u',[KeyEvent::VK_U])
253
+ @char_codes.store('v',[KeyEvent::VK_V])
254
+ @char_codes.store('w',[KeyEvent::VK_W])
255
+ @char_codes.store('x',[KeyEvent::VK_X])
256
+ @char_codes.store('y',[KeyEvent::VK_Y])
257
+ @char_codes.store('z',[KeyEvent::VK_Z])
258
+ @char_codes.store('{',[KeyEvent::VK_SHIFT,KeyEvent::VK_BRACELEFT])
259
+ @char_codes.store('|',[KeyEvent::VK_SHIFT,KeyEvent::VK_BACK_SLASH])
260
+ @char_codes.store('}',[KeyEvent::VK_SHIFT,KeyEvent::VK_BRACERIGHT])
261
+ @char_codes.store('~',[KeyEvent::VK_SHIFT,KeyEvent::VK_BACK_QUOTE])
262
+ end
263
+ end
264
+ end
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # frozen_string_literal: true
4
+
5
+ #--
6
+ # This file is part of SSC.Nob.
7
+ # Copyright (c) 2020 Jonathan Bradley Whited (@esotericpig)
8
+ #
9
+ # SSC.Nob is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # SSC.Nob is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with SSC.Nob. If not, see <https://www.gnu.org/licenses/>.
21
+ #++
22
+
23
+
24
+ require 'attr_bool'
25
+
26
+ require 'ssc.nob/ssc_chat_log/message'
27
+ require 'ssc.nob/ssc_chat_log/message_parser'
28
+
29
+
30
+ module SSCNob
31
+ ###
32
+ # @author Jonathan Bradley Whited (@esotericpig)
33
+ # @since 0.1.0
34
+ ###
35
+ class SSCChatLog
36
+ attr_reader :config
37
+ attr_reader :listeners
38
+ attr_reader :log_file
39
+ attr_reader :logname
40
+ attr_reader :messages
41
+ attr_reader? :running
42
+ attr_accessor :sleep_time
43
+ attr_reader :thread
44
+
45
+ def initialize(config,logname: 'nob.log',sleep_time: 0.2)
46
+ @config = config
47
+ @listeners = []
48
+ @log_file = File.join(config.build_ssc_log_dir(),logname)
49
+ @logname = logname
50
+ @messages = []
51
+ @running = false
52
+ @sleep_time = sleep_time
53
+ @thread = nil
54
+ end
55
+
56
+ def add_listener(proc=nil,&block)
57
+ @listeners.push(block) if block
58
+ @listeners.push(proc) if proc
59
+
60
+ return self
61
+ end
62
+
63
+ def run()
64
+ return if @running # Already running
65
+
66
+ stop() # Justin Case
67
+
68
+ if !File.exist?(@log_file)
69
+ # Create the file.
70
+ File.open(@log_file,'at') do |fout|
71
+ end
72
+ end
73
+
74
+ @thread = Thread.new() do
75
+ File.open(@log_file,'rt') do |fin|
76
+ fin.seek(0,:END)
77
+ fin.gets() # Ignore most recent line
78
+
79
+ parser = MessageParser.new(config: @config,fin: fin)
80
+
81
+ @running = true
82
+
83
+ while @running
84
+ while !(line = fin.gets()).nil?()
85
+ msg = parser.parse(line)
86
+
87
+ @messages.push(msg)
88
+
89
+ @listeners.each() do |l|
90
+ l.call(self,msg)
91
+ end
92
+ end
93
+
94
+ sleep(@sleep_time)
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ def stop()
101
+ @running = false
102
+
103
+ if !@thread.nil?()
104
+ if @thread.alive?()
105
+ @thread.join(5)
106
+ @thread.kill() if @thread.alive?()
107
+ end
108
+
109
+ @thread = nil
110
+ end
111
+
112
+ @messages = []
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # frozen_string_literal: true
4
+
5
+ #--
6
+ # This file is part of SSC.Nob.
7
+ # Copyright (c) 2020 Jonathan Bradley Whited (@esotericpig)
8
+ #
9
+ # SSC.Nob is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # SSC.Nob is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with SSC.Nob. If not, see <https://www.gnu.org/licenses/>.
21
+ #++
22
+
23
+
24
+ module SSCNob
25
+ class SSCChatLog
26
+ ###
27
+ # @author Jonathan Bradley Whited (@esotericpig)
28
+ # @since 0.1.0
29
+ ###
30
+ class Message
31
+ TYPES = [
32
+ :unknown,
33
+ :chat,:freq,:kill,:private,:pub,:team,
34
+ :q_chat,:q_kill,:q_namelen,:q_log,
35
+ ]
36
+
37
+ attr_reader :lines
38
+ attr_reader :meta
39
+ attr_reader :type
40
+
41
+ TYPES.each() do |type|
42
+ define_method(:"#{type}?") do
43
+ return @type == type
44
+ end
45
+ end
46
+
47
+ def initialize(lines,meta: {},type: :unknown)
48
+ super()
49
+
50
+ @lines = Array(lines)
51
+ @meta = meta
52
+ @type = type
53
+ end
54
+
55
+ def [](key)
56
+ return @meta[key]
57
+ end
58
+ end
59
+ end
60
+ end