summaryrefslogtreecommitdiff
path: root/helpers.py
blob: 285a0f5ed8d055ad35545033b33fce42dee736ee (plain)
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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
#pylint: disable = F0401
from re import sub
from java.util.UUID import fromString as juuid
from json import dumps as json_dumps, loads as json_loads
import org.bukkit as bukkit
import org.bukkit.Location as Location
import org.bukkit.entity.Player as Player
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause as TeleportCause
import org.bukkit.event.block.BlockBreakEvent as BlockBreakEvent
import org.bukkit.block as bblock
import org.bukkit.event.entity as entity
import org.bukkit.command.ConsoleCommandSender
from org.bukkit.entity import *

#Imports for async query
from secrets import *
import mysqlhack
from com.ziclix.python.sql import zxJDBC
import threading

from traceback import format_exc as trace

helpers_version = "2.0.0"
shared = {} # this dict can be used to share stuff across modules

server = bukkit.Bukkit.getServer()


def info(text):
    """
    Log info to console
    """
    server.getLogger().info("[RedstonerUtils] %s" % text)


def warn(text):
    """
    Log warning to console
    """
    server.getLogger().warning("[RedstonerUtils] %s" % text)


def error(text):
    """
    Log error to console
    """
    server.getLogger().severe("[RedstonerUtils] %s" % text)


def fine(text):
    """
    Log anything to the logs alone, not the console
    """
    server.getLogger().fine(text)

def msg(player, text, usecolor = True, basecolor = None):
    """
    send a message to player
    the player may be None or offline, which this method just ignores
    unless usecolor is False, &-codes are translated to real color codes
    for that case, basecolor can be useful. basecolor accepts a single character as color code
    """
    if player and (player == server.getConsoleSender() or player.isOnline()): # getPlayer() returns None when offline
        if basecolor:
            if usecolor:
                text = colorify(text)
            player.sendMessage(colorify("&%s" % basecolor) + text)
        else:
            player.sendMessage(colorify(text) if usecolor else text)


def broadcast(perm, text, usecolor = True):
    """
    better than bukkit's broadcast.
    bukkit only works with permissibles that are subscribed to perm
    """
    if usecolor:
        text = colorify(text)
    for recipient in list(server.getOnlinePlayers()) + [server.getConsoleSender()]:
        if not perm or recipient.hasPermission(perm):
            msg(recipient, text, usecolor = False)


def colorify(text):
    """
    replace &-codes with real color codes
    """
    return sub("&(?=[?\\da-fk-or])", u"\u00A7", "%s" % text)


def stripcolors(text):
    """
    strips all (real) color codes from text
    """
    return sub(u"\u00A7[\\da-fk-or]", "", "%s" % text)


def safetp(player, world, x, y, z, yaw = 0, pitch = 0):
    """
    teleports the player to the given Location
    if the player would spawn inside blocks, the location is escalated until the location is safe
    """
    tpblock = Location(world, x, y, z).getBlock()
    if (tpblock.isEmpty() and tpblock.getRelative(bblock.BlockFace.UP).isEmpty()) or y > 255:
        player.teleport(Location(world, x+0.5, y, z+0.5, yaw, pitch), TeleportCause.COMMAND)
    else:
        safetp(player, world, x, y+1, z, yaw, pitch)


def plugin_header(recipient = None, name="Redstoner Utils"):
    """
    sends the recipient a "Plugin Header", in the format of: --=[ PluginName ]=--
    """

    head = "\n&2--=[ %s ]=--" % name
    msg(recipient, head)
    return head


def noperm(player):
    """
    Send the default permission failure message to the player
    """
    msg(player, "&cno permission")


def runas(player, cmd):
    """
    run a command as player
    the cmd should NOT be prefixed with a /
    """
    if is_player(player):
        player.chat("/" + cmd)
    else:
        server.dispatchCommand(player, cmd)


def is_player(obj):
    """
    return True when ob is a bukkit Player
    """
    return (isinstance(obj, Player))


def can_build(player, block):
    """
    return True if the player can change/build at the location of given block
    """
    event = BlockBreakEvent(block, player)
    server.getPluginManager().callEvent(event)
    return not event.isCancelled()


def checkargs(sender, args, amin, amax):
    """
    check if a command has a valid amount of args, otherwise notify the sender
    amin is the minimum amount of args
    amax is the maximum amount of args
    if amax is < 0, infinite args will be accepted
    return True if args has a valid length, False otherwise
    """
    if not (len(args) >= amin and (amax < 0 or len(args) <= amax)):
        if amin == amax:
            msg(sender, "&cNeeds " + str(amin) + " arguments!")
            return False
        elif amax < 0:
            msg(sender, "&cNeeds at least " + str(amin) + " arguments!")
            return False
        else:
            msg(sender, "&cNeeds " + str(amin) + " to " + str(amax) + " arguments!")
            return False
    return True


def is_creative(player):
    """
    returns True if the player is in Creative mode
    """
    return str(player.getGameMode()) == "CREATIVE"


def uid(player):
    """
    returns the player's UUID
    """
    return str(player.getUniqueId())


def retrieve_player(uuid_str):
    """
    gets an offline player by UUID string
    the uuid MUST contain dashes
    """
    return server.getOfflinePlayer(juuid(uuid_str))


def known_player(player):
    """
    to be used on OfflinePlayer (which can be online!)
    returns True if the player has been on the server
    this is different to HasPlayedBefore(), which will return False on first join
    """
    return player.hasPlayedBefore()

"""
Runs a async query, calls target function with fetchall as an argument, it will be an empty list if there is nothing to fetch.
(So make sure your function takes that argument.)

If you want your function to run sync in the case you are doing something spigot wouldn't like to be async use the bukkit scheduler.
Example can be found in loginsecurity.py

"""
def async_query(mysql_database,query,query_args,target,*target_args,**target_kwargs):

    def async_query_t(mysql_database,query,query_args,target,target_args,target_kwargs):
        db_conn = zxJDBC.connect(mysql_database, mysql_user, mysql_pass, "com.mysql.jdbc.Driver")
        db_curs = db_conn.cursor()
        db_curs.execute(query,query_args)
        db_conn.commit()
        fetchall = db_curs.fetchall()
        db_curs.close()
        db_conn.close()
        target(fetchall,target_args,target_kwargs)

    t = threading.Thread(target=async_query_t,args=(mysql_database,query,query_args,target,target_args,target_kwargs))
    t.daemon = True
    t.start()


def open_json_file(filename, default = None):
    """
    opens the given json file and returns an object or returns None on error
    filename is only the name of the file without .json appended.
    """
    try:
        with open("plugins/redstoner-utils.py.dir/files/%s.json" % filename) as obj:
            default = json_loads(obj.read())
    except Exception, e:
        error("Failed to read from %s: %s" % (filename, e))
    return default


def save_json_file(filename, obj):
    """
    saves the given object as json into filename
    filename is only the name of the file without .json appended.
    """
    try:
        with open("plugins/redstoner-utils.py.dir/files/%s.json" % filename, "w") as f:
            f.write(json_dumps(obj))
    except Exception, e:
        error("Failed to write to %s: %s" % (filename, e))


def toggle(player, ls, name = "Toggle", add = None):
    """
    Toggles presence of a player's UUID in a list
    If add is given, True explicitely adds it whereas False removes it
    """
    pid = uid(player)
    if pid in ls or add is False:
        ls.remove(pid)
        msg(player, "&a%s turned off!" % name)
    elif add is not False:
        ls.append(pid)
        msg(player, "&a%s turned on!" % name)



def send_JSON_message(playername, message):
    bukkit.Bukkit.getServer().dispatchCommand(bukkit.Bukkit.getServer().getConsoleSender(), "tellraw " + playername + " " + message)


# Allows to check if a String is a valid IPv4 or not. Accepts any string, returns true if the String is a valid IPv4
def is_ip(tocheck):
    subsets = ["","","",""]
    i = 0
    for j in range(0,len(tocheck)):
        if not (tocheck[j] in "0123456789."):
            return False
        elif tocheck[j] == ".":
            i += 1
            if (i >= 4):
                return False
        else:
            subsets[i] +=  tocheck[j]
    if not (i == 3):
        return False
    for j in range(0,3):
        if not ((int(subsets[j]) >= 0) & (int(subsets[j]) <= 255)):
            return False
    return True


# Allows the use of e.g. numeric permission nodes like "permission.amount.5" and similar.
# To get the data fetch the player and the start of the permission node, looking like "permission.amount."
def get_permission_content(player, permnode, default_value = None):
    try:
        perms = player.getEffectivePermissions()
        for perm in perms:
            if str(perm.getPermission()).startswith(permnode):
                   return str(perm.getPermission())[len(permnode):]
        return default_value
    except:
        error(trace())


def array_to_list(array):
    return_list = []
    for a in array:
        return_list.append(a)
    return return_list


#debug wrapper
def debug(func):
    def wrap(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except:
            error(trace())
            return None
    return wrap