├── anticheat.pyc ├── prelim_lstm.h5 ├── prelim_4feats_as.h5 ├── prelim_4feats_as.2.h5 ├── prelim_massfeats_as.2.h5 ├── prelim_massfeats_as.h5 ├── README.md ├── LICENSE ├── dum.py ├── anticheatlstm.py ├── anticheat.py └── anticheatMassfeats.py /anticheat.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrozenOrb/HAL_Prediction/HEAD/anticheat.pyc -------------------------------------------------------------------------------- /prelim_lstm.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrozenOrb/HAL_Prediction/HEAD/prelim_lstm.h5 -------------------------------------------------------------------------------- /prelim_4feats_as.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrozenOrb/HAL_Prediction/HEAD/prelim_4feats_as.h5 -------------------------------------------------------------------------------- /prelim_4feats_as.2.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrozenOrb/HAL_Prediction/HEAD/prelim_4feats_as.2.h5 -------------------------------------------------------------------------------- /prelim_massfeats_as.2.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrozenOrb/HAL_Prediction/HEAD/prelim_massfeats_as.2.h5 -------------------------------------------------------------------------------- /prelim_massfeats_as.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrozenOrb/HAL_Prediction/HEAD/prelim_massfeats_as.h5 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HAL_Prediction 2 | Experimental server-side ML anticheat for Minecraft. 3 | 4 | Sample data can be found at https://github.com/FrozenOrb/HALData. 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016 FrozenOrb, LLC 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /dum.py: -------------------------------------------------------------------------------- 1 | from keras.models import Sequential 2 | from keras.layers.core import Dense, Dropout, Activation 3 | from keras.optimizers import SGD 4 | import numpy as np 5 | from keras.utils import np_utils 6 | 7 | # Create a random matrix with 1000 rows (data points) and 15 columns (features) 8 | train_rows = 1000 9 | X_train = np.random.rand(train_rows, 15) 10 | 11 | # Create a vector of 1000 random binary labels (one for wach row of X_train). 12 | # It's a two class problem simulation, so a row can be class 0 or 1 13 | labels = np.random.randint(2, size=train_rows) 14 | 15 | # Now, the fit functions expects this labels to be encoded as one-hot vectors. 16 | # In this case, this means we want a labels matrix with 50 rows, each row being 17 | # [1, 0] (class 0) or [0, 1] (class 1). 18 | # We'll use a util function to convert our labels vector to this format 19 | y_train = np_utils.to_categorical(labels) 20 | 21 | # Let's create some bogus test data also 22 | test_rows = 500 23 | X_test = np.random.rand(test_rows, 15) 24 | labels = np.random.randint(2, size=test_rows) 25 | y_test = np_utils.to_categorical(labels) 26 | 27 | 28 | model = Sequential() 29 | # Dense(64) is a fully-connected layer with 64 hidden units. 30 | # in the first layer, you must specify the expected input data shape: 31 | # here, 20-dimensional vectors. 32 | model.add(Dense(64, input_dim=X_train.shape[1], init='uniform')) # X_train.shape[1] == 15 here 33 | model.add(Activation('tanh')) 34 | model.add(Dropout(0.5)) 35 | model.add(Dense(64, init='uniform')) 36 | model.add(Activation('tanh')) 37 | model.add(Dropout(0.5)) 38 | model.add(Dense(y_train.shape[1], init='uniform')) # y_train.shape[1] == 2 here 39 | model.add(Activation('softmax')) 40 | 41 | sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True) 42 | model.compile(loss='mean_squared_error', optimizer=sgd) 43 | 44 | model.fit(X_train, y_train, nb_epoch=10, batch_size=100) 45 | score = model.evaluate(X_test, y_test, batch_size=100) 46 | 47 | # We'll achieve a score of approximately 0.25. That's because in our random data 48 | # we have 50% = 0.5 of chance of getting the right answer, so the model will learn 49 | # to predict probabilities near 0.5. But as we're using a mean square error, 50 | # the score will be roughly 0.5^2 = 0.25 51 | print "Score: %f" % score 52 | 53 | # To see some predictions from the test set: 54 | print 'Some predictions from the test set:' 55 | print model.predict(X_test[0:10]) -------------------------------------------------------------------------------- /anticheatlstm.py: -------------------------------------------------------------------------------- 1 | # Sloppy Keras code to train a very basic MLP 2 | # Please have mercy on me. 3 | 4 | from __future__ import print_function 5 | import numpy as np 6 | np.set_printoptions(suppress=True) 7 | 8 | from keras.models import Sequential 9 | from keras.layers import Dense, Dropout, Activation 10 | from keras.layers import LSTM, SimpleRNN, GRU 11 | from keras.utils import np_utils 12 | from keras.optimizers import SGD 13 | import os, math, time 14 | 15 | class Timer(object): 16 | def __init__(self, name=None): 17 | self.name = name 18 | 19 | def __enter__(self): 20 | self.tstart = time.time() 21 | 22 | def __exit__(self, type, value, traceback): 23 | if self.name: 24 | print('[%s]' % self.name) 25 | print('Elapsed: %s' % (time.time() - self.tstart)) 26 | 27 | DATA = "D:\\Downloads\\HALData-master" 28 | 29 | def categorical_probas_to_classes(p): 30 | return np.argmax(p, axis=1) 31 | 32 | def probas_to_classes(y_pred): 33 | if len(y_pred.shape) > 1 and y_pred.shape[1] > 1: 34 | return categorical_probas_to_classes(y_pred) 35 | return np.array([1 if p > 0.5 else 0 for p in y_pred]) 36 | 37 | def shuffle_in_unison_inplace(a, b): 38 | assert len(a) == len(b) 39 | p = np.random.permutation(len(a)) 40 | return a[p], b[p] 41 | 42 | ## This returns two vectors: 43 | ## examples, which looks like [[feature, feature, feature, feature], 44 | # [features, feature, feature, feature]] 45 | # labels, which looks like [[0, 1], [1, 0]] ... 46 | def parse(d, keyword, op, Y_fn=False): 47 | examples = [] 48 | labels = [] 49 | for f in os.listdir(d): 50 | if keyword in f: 51 | lines = [line.rstrip('\n') for line in open(os.path.join(d, f))] 52 | ts = 0 53 | init_ts = -1 54 | 55 | lastAttackOS = -1 56 | attacks = [] 57 | 58 | for l in lines: 59 | if not l.startswith("#"): #and l.startswith("attackInfo"): 60 | s = l.split(',') 61 | if l.startswith("attackInfo"): 62 | if lastAttackOS < 0: 63 | lastAttackOS = long(s[11]) 64 | else: 65 | v = [int(long(s[11]) - lastAttackOS), float(s[7]), float(s[8])] 66 | attacks.append(v) 67 | lastAttackOS = long(s[11]) 68 | if len(attacks) == 20: 69 | examples.append(attacks) 70 | if Y_fn: 71 | labels.append(f) 72 | else: 73 | labels.append(op[:]) 74 | attacks = [] 75 | 76 | return np.asarray(examples), np.asarray(labels) 77 | 78 | 79 | X_van, Y_van = parse(DATA + "\\Vanilla", ".csv", [1, 0]) 80 | X_hac, Y_hac = parse(DATA + "\\Hacks", ".csv", [0, 1]) 81 | 82 | print("Shuffling") 83 | shuffle_in_unison_inplace(X_van, Y_van) 84 | shuffle_in_unison_inplace(X_hac, Y_hac) 85 | 86 | # Each class must have equal support 87 | X_hac = X_hac[:len(X_van)] 88 | Y_hac = Y_hac[:len(X_van)] 89 | 90 | # print(X_van[:3]) 91 | # print("Hack:") 92 | # print(X_hac[:3]) 93 | # exit() 94 | 95 | print("Support for each class: ", len(X_van)) 96 | 97 | 98 | van_l = math.floor(len(X_van) * 1) 99 | hac_l = math.floor(len(X_hac) * 1) 100 | 101 | X_train = np.concatenate((X_van[:van_l], X_hac[:hac_l]), axis=0) 102 | Y_train = np.concatenate((Y_van[:van_l], Y_hac[:hac_l]), axis=0) 103 | 104 | X_test = np.concatenate((X_van[van_l:], X_hac[hac_l:]), axis=0) 105 | Y_test = np.concatenate((Y_van[van_l:], Y_hac[hac_l:]), axis=0) 106 | 107 | model = Sequential() 108 | model.add(LSTM(32, input_dim=3, input_length=20)) 109 | model.add(Dense(2)) 110 | model.add(Activation('sigmoid')) 111 | 112 | model.compile(loss='binary_crossentropy', 113 | optimizer='adam', 114 | metrics=['accuracy']) 115 | 116 | model.load_weights('prelim_lstm.h5') 117 | 118 | #model.fit(X_train, Y_train, nb_epoch=100, batch_size=16) 119 | 120 | #model.save_weights('prelim_lstm.h5') 121 | 122 | score = model.evaluate(X_test, Y_test, batch_size=16) 123 | 124 | for i in range(len(score)): 125 | print(model.metrics_names[i], score[i]) 126 | 127 | 128 | #X_test, Y_test = parse("C:\\Users\\shrey\\Downloads\\Telegram Desktop", ".csv", [0, 1], Y_fn=True) 129 | X_test, Y_test = parse("D:\\Downloads\\HALData-master\\UnidentifiedHacks", ".csv", [0, 1], Y_fn=True) 130 | 131 | with Timer("perdiction"): # the spelling mistake is intentional 132 | pred_probas = model.predict_proba(X_test, batch_size=16) 133 | pred = probas_to_classes(pred_probas) 134 | actual = probas_to_classes(Y_test) 135 | 136 | for p, a, c in zip(pred, Y_test, pred_probas): 137 | print(p, a, c) 138 | # print('Test score:', score[0]) 139 | # print('Test accuracy:', score[1]) 140 | -------------------------------------------------------------------------------- /anticheat.py: -------------------------------------------------------------------------------- 1 | # Sloppy Keras code to train a very basic MLP 2 | # Please have mercy on me. 3 | 4 | from __future__ import print_function 5 | import numpy as np 6 | np.set_printoptions(suppress=True) 7 | 8 | from keras.models import Sequential 9 | from keras.layers import Dense, Dropout, Activation 10 | from keras.utils import np_utils 11 | from keras.optimizers import SGD 12 | import os, math, time 13 | 14 | class Timer(object): 15 | def __init__(self, name=None): 16 | self.name = name 17 | 18 | def __enter__(self): 19 | self.tstart = time.time() 20 | 21 | def __exit__(self, type, value, traceback): 22 | if self.name: 23 | print('[%s]' % self.name) 24 | print('Elapsed: %s' % (time.time() - self.tstart)) 25 | 26 | DATA = "D:\\Downloads\\HALData-master" 27 | 28 | def categorical_probas_to_classes(p): 29 | return np.argmax(p, axis=1) 30 | 31 | def probas_to_classes(y_pred): 32 | if len(y_pred.shape) > 1 and y_pred.shape[1] > 1: 33 | return categorical_probas_to_classes(y_pred) 34 | return np.array([1 if p > 0.5 else 0 for p in y_pred]) 35 | 36 | def shuffle_in_unison_inplace(a, b): 37 | assert len(a) == len(b) 38 | p = np.random.permutation(len(a)) 39 | return a[p], b[p] 40 | 41 | ## This returns two vectors: 42 | ## examples, which looks like [[feature, feature, feature, feature], 43 | # [features, feature, feature, feature]] 44 | # labels, which looks like [[0, 1], [1, 0]] ... 45 | def parse(d, keyword, op, Y_fn=False): 46 | examples = [] 47 | labels = [] 48 | for f in os.listdir(d): 49 | if keyword in f: 50 | lines = [line.rstrip('\n') for line in open(os.path.join(d, f))] 51 | ts = 0 52 | init_ts = -1 53 | 54 | 55 | 56 | for l in lines: 57 | if not l.startswith("#"): #and l.startswith("attackInfo"): 58 | s = l.split(',') 59 | if len(s) < 12: 60 | continue 61 | ts = long(s[11]) 62 | if init_ts < 0: 63 | init_ts = ts 64 | num_attacks = 0 65 | max_dist = -1.0 66 | max_angle = -1.0 67 | vel_total = [] 68 | vel_count = 0 69 | if l.startswith("attackInfo"): 70 | num_attacks += 1 71 | max_dist = max(float(s[8]), max_dist) 72 | max_angle = max(abs(float(s[7])), max_angle) 73 | if l.startswith("move"): 74 | if s[12].isdigit(): 75 | if int(s[12]) != 0: 76 | vel_count += 1 77 | vel_total.append(abs(float(s[1]) / (float(s[12])/1000))) 78 | #print(abs(float(s[1]) / (float(s[12])/1000)), f, ts) 79 | if ts - init_ts > 5*1000 - 1: 80 | init_ts = -1 81 | if num_attacks != 0: 82 | examples.append([num_attacks / 10.0, max_angle, max_dist, np.median(vel_total)]) 83 | if Y_fn: 84 | labels.append(f) 85 | else: 86 | labels.append(op[:]) 87 | return np.asarray(examples), np.asarray(labels) 88 | 89 | 90 | X_van, Y_van = parse(DATA + "\\Vanilla", ".csv", [1, 0]) 91 | X_hac, Y_hac = parse(DATA + "\\Hacks", ".csv", [0, 1]) 92 | 93 | print("Shuffling") 94 | shuffle_in_unison_inplace(X_van, Y_van) 95 | shuffle_in_unison_inplace(X_hac, Y_hac) 96 | 97 | # Each class must have equal support 98 | X_hac = X_hac[:len(X_van)] 99 | Y_hac = Y_hac[:len(X_van)] 100 | 101 | # print(X_van) 102 | # print("Hack:") 103 | # print(X_hac) 104 | # exit() 105 | 106 | print("Support for each class: ", len(X_van)) 107 | 108 | 109 | van_l = math.floor(len(X_van) * 1) 110 | hac_l = math.floor(len(X_hac) * 1) 111 | 112 | X_train = np.concatenate((X_van[:van_l], X_hac[:hac_l]), axis=0) 113 | Y_train = np.concatenate((Y_van[:van_l], Y_hac[:hac_l]), axis=0) 114 | 115 | X_test = np.concatenate((X_van[van_l:], X_hac[hac_l:]), axis=0) 116 | Y_test = np.concatenate((Y_van[van_l:], Y_hac[hac_l:]), axis=0) 117 | 118 | model = Sequential() 119 | model.add(Dense(20, input_dim=4, init='uniform')) 120 | model.add(Activation('tanh')) 121 | model.add(Dense(2, init='uniform')) 122 | model.add(Activation('softmax')) 123 | 124 | sgd = SGD(lr=0.005, decay=1e-6, momentum=0.9, nesterov=True) 125 | model.compile(loss='binary_crossentropy', 126 | optimizer=sgd, 127 | metrics=['accuracy']) 128 | 129 | model.load_weights('prelim_4feats_as.2.h5') 130 | 131 | # model.fit(X_train, Y_train, 132 | # nb_epoch=500, batch_size=16) 133 | 134 | # score = model.evaluate(X_test, Y_test, batch_size=16) 135 | 136 | # for i in range(len(model.metrics_names)): 137 | # print(model.metrics_names[i], score[i]) 138 | 139 | #model.save_weights('prelim_4feats_as.2.h5') 140 | 141 | X_test, Y_test = parse("C:\\Users\\shrey\\Downloads\\Telegram Desktop", ".csv", [0, 1], Y_fn=True) 142 | 143 | with Timer("perdiction"): 144 | pred_probas = model.predict_proba(X_test, batch_size=16) 145 | pred = probas_to_classes(pred_probas) 146 | actual = probas_to_classes(Y_test) 147 | 148 | for p, a, c in zip(pred, Y_test, pred_probas): 149 | print(p, a, c) 150 | # print('Test score:', score[0]) 151 | # print('Test accuracy:', score[1]) 152 | 153 | print(X_test) 154 | print(Y_test) 155 | -------------------------------------------------------------------------------- /anticheatMassfeats.py: -------------------------------------------------------------------------------- 1 | # Sloppy Keras code to train a very basic MLP 2 | # Please have mercy on me. 3 | 4 | from __future__ import print_function 5 | import numpy as np 6 | np.set_printoptions(suppress=True) 7 | 8 | from keras.models import Sequential 9 | from keras.layers import Dense, Dropout, Activation 10 | from keras.utils import np_utils 11 | from keras.optimizers import SGD 12 | import os, math, time 13 | 14 | class Timer(object): 15 | def __init__(self, name=None): 16 | self.name = name 17 | 18 | def __enter__(self): 19 | self.tstart = time.time() 20 | 21 | def __exit__(self, type, value, traceback): 22 | if self.name: 23 | print('[%s]' % self.name) 24 | print('Elapsed: %s' % (time.time() - self.tstart)) 25 | 26 | DATA = "D:\\Downloads\\HALData-master" 27 | 28 | def categorical_probas_to_classes(p): 29 | return np.argmax(p, axis=1) 30 | 31 | def probas_to_classes(y_pred): 32 | if len(y_pred.shape) > 1 and y_pred.shape[1] > 1: 33 | return categorical_probas_to_classes(y_pred) 34 | return np.array([1 if p > 0.5 else 0 for p in y_pred]) 35 | 36 | ## This returns two vectors: 37 | ## examples, which looks like [[feature, feature, feature, feature], 38 | # [features, feature, feature, feature]] 39 | # labels, which looks like [[0, 1], [1, 0]] ... 40 | def parse(d, keyword, op, Y_fn=False): 41 | examples = [] 42 | labels = [] 43 | for f in os.listdir(d): 44 | if keyword in f: 45 | moves = [] 46 | attacks = [] 47 | lastattackos = -1 48 | lastmoveos = -1 49 | lines = [line.rstrip('\n') for line in open(os.path.join(d, f))] 50 | 51 | ll = 10 52 | 53 | for l in lines: 54 | if not l.startswith("#"): #and l.startswith("attackInfo"): 55 | s = l.split(',') 56 | if len(s) < 12: 57 | continue 58 | ts = long(s[11]) 59 | #print(len(moves), len(attacks)) 60 | if len(moves) > ll*6-1 and len(attacks) > ll*3-1: 61 | examples.append(moves[:ll*6] + attacks[:ll*3]) 62 | if Y_fn: 63 | labels.append(f) 64 | else: 65 | labels.append(op[:]) 66 | moves = moves[ll:] 67 | attacks = attacks[ll:] 68 | if l.startswith("attackInfo"): 69 | if lastattackos < 0: 70 | lastattackos = long(s[11]) 71 | else: 72 | attacks.append(long(s[11]) - lastattackos) 73 | attacks.append(float(s[8])) 74 | attacks.append(float(s[7])) 75 | lastattackos = long(s[11]) 76 | if l.startswith("move"): 77 | if lastmoveos < 0: 78 | lastmoveos = long(s[11]) 79 | else: 80 | moves.append(long(s[11]) - lastmoveos) 81 | for i in [1,2,3,4,5]: 82 | moves.append(float(s[i])) 83 | lastmoveos = long(s[11]) 84 | 85 | return np.asarray(examples), np.asarray(labels) 86 | 87 | 88 | X_van, Y_van = parse(DATA + "\\Vanilla", ".csv", [1, 0]) 89 | X_hac, Y_hac = parse(DATA + "\\Hacks", ".csv", [0, 1]) 90 | 91 | # Each class must have equal support 92 | X_hac = X_hac[:len(X_van)] 93 | Y_hac = Y_hac[:len(X_van)] 94 | 95 | # for i in range(10): 96 | # print(len(X_van[i])) 97 | # print("Hack:") 98 | # for i in range(10): 99 | # print(len(X_hac[i])) 100 | # exit() 101 | 102 | print("Support for van: ", len(X_van)) 103 | print("Support for hac: ", len(X_hac)) 104 | 105 | van_l = math.floor(len(X_van) * 0.8) 106 | hac_l = math.floor(len(X_hac) * 0.8) 107 | 108 | X_train = np.concatenate((X_van[:van_l], X_hac[:hac_l]), axis=0) 109 | Y_train = np.concatenate((Y_van[:van_l], Y_hac[:hac_l]), axis=0) 110 | 111 | X_test = np.concatenate((X_van[van_l:], X_hac[hac_l:]), axis=0) 112 | Y_test = np.concatenate((Y_van[van_l:], Y_hac[hac_l:]), axis=0) 113 | 114 | model = Sequential() 115 | model.add(Dense(50, input_dim=90, init='uniform')) 116 | model.add(Activation('tanh')) 117 | model.add(Dense(20, init='uniform')) 118 | model.add(Activation('tanh')) 119 | model.add(Dense(2, init='uniform')) 120 | model.add(Activation('softmax')) 121 | 122 | sgd = SGD(lr=0.005, decay=1e-6, momentum=0.9, nesterov=True) 123 | model.compile(loss='binary_crossentropy', 124 | optimizer=sgd, 125 | metrics=['accuracy']) 126 | 127 | model.load_weights('prelim_massfeats_as.2.h5') 128 | 129 | # model.fit(X_train, Y_train, 130 | # nb_epoch=200, batch_size=32) 131 | 132 | # score = model.evaluate(X_test, Y_test, batch_size=32) 133 | 134 | # for i in range(len(model.metrics_names)): 135 | # print(model.metrics_names[i], score[i]) 136 | 137 | # model.save_weights('prelim_massfeats_as.2.h5') 138 | 139 | #X_test, Y_test = parse("C:\\Users\\shrey\\Downloads\\Telegram Desktop", ".csv", [0, 1], Y_fn=True) 140 | X_test, Y_test = parse("D:\\Downloads\\HALData-master\\Hacks", ".csv", [0, 1], Y_fn=True) 141 | 142 | with Timer("perdiction"): 143 | pred_probas = model.predict_proba(X_test, batch_size=32) 144 | pred = probas_to_classes(pred_probas) 145 | actual = probas_to_classes(Y_test) 146 | 147 | lst_c = {} 148 | 149 | for p, a, c in zip(pred, Y_test, pred_probas): 150 | if c[1] > 0.8: 151 | print(p, a, c) 152 | #lst_c[a.split('-')[2]] = '1' 153 | 154 | # for k in lst_c: 155 | # print(k) 156 | # print('Test score:', score[0]) 157 | # print('Test accuracy:', score[1]) 158 | 159 | --------------------------------------------------------------------------------