Ejemplo n.º 1
0
    def onPlayerJoin(self, player):

        # no longer allowing mid-game joiners here... too easy to exploit
        if self.hasBegun():
            player.gameData['lives'] = 0
            player.gameData['icons'] = []
            # make sure our team has survival seconds set if they're all dead
            # (otherwise blocked new ffa players would be considered 'still alive' in score tallying)
            if self._getTotalTeamLives(player.getTeam(
            )) == 0 and player.getTeam().gameData['survivalSeconds'] is None:
                player.getTeam().gameData['survivalSeconds'] = 0
            bs.screenMessage(bs.Lstr(resource='playerDelayedJoinText',
                                     subs=[('${PLAYER}',
                                            player.getName(full=True))]),
                             color=(0, 1, 0))
            return

        player.gameData['lives'] = self.settings['Lives Per Player']

        if self._soloMode:
            player.gameData['icons'] = []
            player.getTeam().gameData['spawnOrder'].append(player)
            self._updateSoloMode()
        else:
            # create our icon and spawn
            player.gameData['icons'] = [
                Icon(player, position=(0, 50), scale=0.8)
            ]
            if player.gameData['lives'] > 0:
                self.spawnPlayer(player)

        # dont waste time doing this until begin
        if self.hasBegun():
            self._updateIcons()
Ejemplo n.º 2
0
    def onPlayerLeave(self, player):
        bs.TeamGameActivity.onPlayerLeave(self, player)

        # a player leaving disqualifies the team if 'Entire Team Must Finish'
        # is on (otherwise in teams mode everyone could just leave except the
        # leading player to win)
        if isinstance(self.getSession(),
                      bs.TeamsSession) and self.settings.get(
                'Entire Team Must Finish'):
            # FIXME translate this
            bs.screenMessage(
                bs.Lstr(
                    translate=(
                        'statements',
                        '${TEAM} is disqualified because ${PLAYER} left'),
                    subs=[('${TEAM}', player.getTeam().name),
                          ('${PLAYER}', player.getName(full=True))]),
                color=(1, 1, 0))
            player.getTeam().gameData['finished'] = True
            player.getTeam().gameData['time'] = None
            player.getTeam().gameData['lap'] = 0
            bs.playSound(bs.getSound("boo"))
            for player in player.getTeam().players:
                player.gameData['lap'] = 0
                player.gameData['finished'] = True
                try:
                    player.actor.handleMessage(bs.DieMessage())
                except Exception:
                    pass

        # delay by one tick so team/player lists will be updated
        bs.gameTimer(1, self._checkEndGame)
Ejemplo n.º 3
0
def me(nick):
    if nick is None:
        return
    if isinstance(nick, bs.Player):
        n = nick.get_account_id()
    elif nick.startswith('pb'):
        n = nick
    else:
        return
    stats = db.getData(n)
    score = stats['s']
    rank = db.getRank(n)
    points = stats['p']
    message = bs.uni(stats['n'])
    message2 = u'\ue01f: ' + str(points)
    message3 = 'Total Score: ' + str(score)
    message4 = 'Rank: ' + str(rank)
    message5 = 'K: ' + str(stats['k'])
    message6 = 'D: ' + str(stats['d'])
    if n in joined:
        message7 = 'Time Spent: ' + str(
            datetime.timedelta(milliseconds=(bs.getRealTime() -
                                             joined[str(n)] +
                                             stats['tp']))).split('.', 2)[0]
    else:
        message7 = 'Time Spent: ' + \
            str(datetime.timedelta(milliseconds=(
                stats['tp']))).split('.', 2)[0]
    bs.screenMessage(u'  |  '.join(
        [message, message2, message3, message4, message5, message6, message7]))
    clear(2500)
Ejemplo n.º 4
0
def join(accountid,clientID):
    if accountid is not None and clientID is not None:
        if db.isBanned(accountid):
            data = db.getBanData(accountid)
            bs.screenMessage(
                "You have been banned. Ban Expires on: {} IST".format(
                    data['till'].strftime('%Y/%m/%d %H:%M:%S')),
                color=(1, 0, 0),
                clients=[clientID],
                transient=True)
            bsInternal._disconnectClient(clientID)
            return
        joined.update({accountid: bs.getRealTime()})
        now_time = long(tim.strftime('%Y%m%d%H%M', tim.localtime(tim.time())))
        stats = db.getData(accountid)
        if stats['i'] == []:
            stats['i'] = {}
        for name, exp in stats['i'].items():
            if now_time > exp:
                bs.screenMessage(
                    '%s Expired' % name,
                    clients=[clientID],
                    transient=True)
                stats['i'].pop(name)
        db.saveData(accountid, stats)
        daily(accountid,clientID)
    queue.remove(accountid)
Ejemplo n.º 5
0
def give(p, nick, amount, reason):
    try:
        amount = abs(int(amount))
    except:
        return
    giver = p.get_account_id()
    taker_player = getPlayerFromNick(nick)
    if taker_player is None:
        return
    taker = taker_player.get_account_id()
    if taker == giver:
        bs.screenMessage(
            'Why would you try to give yourself tickets!\nStoopid Ass')
        return
    g = db.getData(giver)
    t = db.getData(taker)
    if not g['p'] >= amount:
        return
    g['p'] -= amount
    db.saveData(giver, g)
    t['p'] += amount
    db.saveData(taker, t)
    reason = reason if reason != '' else 'Gift :>'
    bs.screenMessage(u'Success | {} > {}\ue01f > {} | Reason: {}'.format(
        p.getName(True), amount, taker_player.getName(True), reason),
                     transient=True,
                     color=(0.5, 1, 0.5))
Ejemplo n.º 6
0
 def onPlayerJoin(self, player):
     player.getTeam().gameData['score'] = 0
     if self.hasBegun():
         bs.screenMessage(bs.Lstr(resource='playerDelayedJoinText',
                                  subs=[('${PLAYER}',
                                         player.getName(full=True))]),
                          color=(0, 1, 0))
def process_server_data(data):
	mods = data["mods"]
	version = data["version"]
	if version - 0.5 > PROTOCOL_VERSION:
		print("version diff:", version, PROTOCOL_VERSION)
		bs.screenMessage("please update the mod manager")
	return mods, version
    def godBoss(self):
        if self.hasEnded():
            return

        bs.playSound(self.alarm, volume=2)
        bs.screenMessage("Босс вошел в режим бога!", color=(1, 0, 0))
        self._boss.getLivingBots()[0].node.hockey = True
        self._boss.getLivingBots()[0].node.color = (4, 4, 0)
    def angryBoss(self):
        if self.hasEnded():
            return

        bs.playSound(self.alarm, volume=2)
        bs.screenMessage("Босс начинает злиться!", color=(1, 0, 1))
        self._boss.getLivingBots()[0].equipBoxingGloves()
        self._boss.getLivingBots()[0].node.color = (2, 0, 2)
Ejemplo n.º 10
0
 def onPlayerJoin(self, player):
     if self.hasBegun():
         bs.screenMessage(bs.Lstr(resource='playerDelayedJoinText',
                                  subs=[('${PLAYER}',
                                         player.getName(full=True))]),
                          color=(0, 1, 0))
         return
     self.spawnPlayer(player)
Ejemplo n.º 11
0
    def madBoss(self):
        if self.hasEnded():
            return

        bs.playSound(self.alarm, volume=2)
        bs.screenMessage("Босс в ярости!", color=(1, 0, 0))
        self._boss.getLivingBots()[0]._punchCooldown = 50
        self._boss.getLivingBots()[0].node.color = (2, 0, 0)
 def checkEnd(self):
     bs.screenMessage(str(len(self.flags)))
     i = 0
     for player in self.players:
         if player.gameData['survived']:
             i += 1
     if i <= 1:
         self.endGame()
 def onPlayerJoin(self, player):
     if self.hasBegun():
         bs.screenMessage(bs.Lstr(resource='playerDelayedJoinText',
                                  subs=[('${PLAYER}',
                                         player.getName(full=True))]),
                          color=(0, 1, 0))
         self.player.gameData['survived'] = False
         self.checkEnd()
 def f(data):
     if not data:
         bs.screenMessage("failed to download mod '{}'".format(filename))
     print("writing", filename)
     with open(modPath + filename, "w") as f:
         f.write(data)
     installed.append(mod)
     check_finished()
Ejemplo n.º 15
0
 def f(data):
     if not data:
         bs.screenMessage("failed to download mod '{}'".format(filename))
     print("writing", filename)
     with open(modPath + filename, "w") as f:
         f.write(data)
     installed.append(mod)
     check_finished()
 def killRound(self):
     self.numPickedUp = 0
     for player in self.players:
         if player.isAlive(): player.actor.handleMessage(bs.DieMessage())
     for flag in self.flags:
         flag.node.delete()
     for light in self.nodes:
         light.delete()
     bs.screenMessage(str(len(self.flags)))
Ejemplo n.º 17
0
def write_log(path=None):
    try:
        if path is None:
            path = os.path.join(env["userScriptsDirectory"], "log")
        with open(path, "w+") as f:
            f.write(bsInternal._getLog())
            f.close()
    except Exception as E:
        bs.screenMessage(str(E))
Ejemplo n.º 18
0
 def onPlayerJoin(self, player):
     # don't allow joining after we start
     # (would enable leave/rejoin tomfoolery)
     if self.hasBegun():
         bs.screenMessage(bs.Lstr(resource='playerDelayedJoinText',subs=[('${PLAYER}',player.getName(full=True))]),color=(0,1,0))
         # for score purposes, mark them as having died right as the game started
         player.gameData['deathTime'] = self._timer.getStartTime()
         return
     self.spawnPlayer(player)
Ejemplo n.º 19
0
def __ModifyBs_disconnectClient(clientID, Force=False, banTime=5 * 60):
    accountid = handle.getAccountIDFromClientID(clientID)
    if accountid is not None:
        if db.getAdmin(accountid):
            bs.screenMessage("Admin Detected. Aborting Kick...",
                             transient=True)
            print "%s is in Admin-List! Aborting Kick!" % accountid
            return
    __bsInternal_disconnectClient(clientID, banTime=banTime)
Ejemplo n.º 20
0
def check(cid):
    global warndict
    if settings.enableChatFilter:
        if warndict[cid] == 1:
            bsInternal._disconnectClient(int(cid))
            bs.screenMessage("Kicking For Misbehave", color=(1, 0, 0))
            warndict.pop(cid)
        elif warndict[cid] == 0:
            warndict[cid] = 1
		def check_deps_and_install(mod=None, succeded=True):
			if any([dep not in self._mods for dep in self.requires]):
				raise Exception("dependency inconsistencies")
			if not all([self._mods[dep].uptodate() for dep in self.requires]) or not succeded:
				return
			if self.url:
				mm_serverGet(self.url, {}, partial(self.writeData, callback, doQuitWindow), eval_data=False)
			else:
				bs.screenMessage("cannot download mod without url")
				raise Exception("mod.install() without url")
        def kick(id):
            def _kick(id):
                bsInternal._disconnectClient(id)

            bs.screenMessage(banReason,
                             color=banReasonColor,
                             clients=[id],
                             transient=True)
            bs.gameTimer(timeWithBanPeopleToReadTheBanReason,
                         bs.Call(_kick, id))
Ejemplo n.º 23
0
 def _doEnter(self):
     bsInternal._addTransaction(
         {
             'type': 'IMPORT_PLAYLIST',
             'expireTime': time.time() + 5,
             'code': bs.textWidget(query=self._textField)
         },
         callback=bs.WeakCall(self._onImportResponse))
     bsInternal._runTransactions()
     bs.screenMessage(bs.Lstr(resource='importingText'))
Ejemplo n.º 24
0
 def onTransitionIn(self):
     bs.screenMessage(
         bs.Lstr(resource='musicText').evaluate()+'Violet7rip - For everything')
     bs.CoopGameActivity.onTransitionIn(self, music='ForEverything')
     bs.gameTimer(1300, bs.Call(bs.playSound, self._newWaveSound))
     self._scoreBoard = bs.ScoreBoard(
         label=bs.Lstr(resource='scoreText'),
         scoreSplit=0.5)
     # we use this in place of a regular int to make it harder to hack scores
     self._score = bs.SecureInt(0)
Ejemplo n.º 25
0
 def checkDevice(self,clientID):# check if in adminlist
     isAdmin = []
     for i in bsInternal._getForegroundHostActivity().players:
         if i.getInputDevice().getClientID() == clientID:
             isAdmin = i.get_account_id()
     if isAdmin in mbal.AdminList:
         return True
     else:
         bs.screenMessage('Commands Only For Admins', color=(1,0,0), clients=[clientID], transient=True)#show to this client
         return False
Ejemplo n.º 26
0
def warn(clientID):
    if settings.enableChatFilter:
        bs.screenMessage("Warning!!! Do Not Misbehave",
                         color=(1, 0, 0),
                         transient=True,
                         clients=[clientID])
    if warndict[clientID] == 0:
        bs.screenMessage("Last Chance Warning 1/2",
                         color=(1, 0, 0),
                         transient=True,
                         clients=[clientID])
Ejemplo n.º 27
0
def _handleUIRemotePress():
    #dCount = bsInternal._getLocalActiveInputDevicesCount()
    env = bs.getEnvironment()
    if env['onTV'] and (env['platform'] == 'android'
                        and env['subplatform'] == 'alibaba'):
        GetBSRemoteWindow()
    else:
        bs.screenMessage(
            bs.Lstr(resource="internal.controllerForMenusOnlyText"),
            color=(1, 0, 0))
        bs.playSound(bs.getSound('error'))
Ejemplo n.º 28
0
    def install(self):
        if not self.checkSupported():
            bs.screenMessage(InstallerLanguage.notSupported %
                             (self.characterName, self.platform))
            return

        bs.screenMessage(InstallerLanguage.installing % self.characterName)

        try:
            for model in self.models:
                systemModel = self.modelsDir + model
                modModel = self.characterFilesDir + model
                shutil.copy(modModel, systemModel)

            for texture in self.textures:
                if self.platform == 'android':
                    if texture.endswith('.dds'):
                        continue
                else:
                    if texture.endswith('.ktx'):
                        continue
                systemTex = self.texturesDir + texture
                modTex = self.characterFilesDir + texture
                shutil.copy(modTex, systemTex)

            for au in self.audio:
                systemAudio = self.audioDir + au
                modAudio = self.characterFilesDir + au
                shutil.copy(modAudio, systemAudio)

            bs.screenMessage(InstallerLanguage.success % self.characterName,
                             color=(0, 1, 0))

            try:
                __import__("wolverine")
                __import__("editor")
            except Exception:
                bs.printException()
            try:
                import wolverine
                import editor
            except Exception:
                bs.printException()
            bs.reloadMedia()
            modPath = bs.getEnvironment()['userScriptsDirectory'] + "/"
            if os.path.exists(modPath + "installWolverine.py"):
                os.remove(modPath + "installWolverine.py")
            if os.path.exists(modPath + "installWolverine.pyc"):
                os.remove(modPath + "installWolverine.pyc")
        except IOError, e:
            bs.screenMessage(InstallerLanguage.fail % self.characterName,
                             color=(1, 0, 0))
            bs.screenMessage(str(e), color=(1, 0, 0))
            print e
Ejemplo n.º 29
0
 def _generatePress(self):
     if bsInternal._getAccountState() != 'SIGNED_IN':
         bsUI.showSignInPrompt()
         return
     bs.screenMessage(
         bs.Lstr(resource='gatherWindow.requestingAPromoCodeText'),
         color=(0, 1, 0))
     bsInternal._addTransaction({
         'type': 'ACCOUNT_LINK_CODE_REQUEST',
         'expireTime': time.time() + 5
     })
     bsInternal._runTransactions()
Ejemplo n.º 30
0
 def _onForfeitPress(self):
     if self._canForfeit:
         bsUI.ConfirmWindow(
             bs.Lstr(resource='coopSelectWindow.forfeitConfirmText'),
             bs.WeakCall(self._forfeit),
             originWidget=self._forfeitButton,
             width=400,
             height=120)
     else:
         bs.screenMessage(
             bs.Lstr(resource='coopSelectWindow.forfeitNotAllowedYetText'),
             color=(1, 0, 0))
         bs.playSound(bs.getSound('error'))
Ejemplo n.º 31
0
def daily(n,n2):
    if n is None:
        return
    date = int(datetime.datetime.now().strftime('%d'))
    stats = db.getData(n)
    if stats.get('ed', 0) != date:
        stats['p'] += 50
        stats['ed'] = date
        bs.screenMessage(u"You Got 50 \ue01f Daily Bonus",
                         clients=[n2],
                         transient=True)
        db.saveData(n, stats)
    return
Ejemplo n.º 32
0
	def _reload_module(self):
		bs.screenMessage("reloading " + self._filename)
		self._prepare_reload()
		self._import_module()
		#self._module = import_module(self._filename[:-3], package=IMPORT_FOLDER.split("/")[-2])
		with open(IMPORT_FOLDER + self._filename, "r") as f:
			self._module_md5 = md5(f.read()).hexdigest()
		self._did_print_error = False
		if self._is_available() and self._type == "game":
			self._game = self._module.bsGetGames()[0]
		else:
			self._game = None
		bs.playSound(bs.getSound('swish'))
	def _reload_module(self):
		bs.screenMessage("reloading " + self._filename)
		self._prepare_reload()
		self._import_module()
		#self._module = import_module(self._filename[:-3], package=IMPORT_FOLDER.split("/")[-2])
		with open(IMPORT_FOLDER + self._filename, "r") as f:
			self._module_md5 = md5(f.read()).hexdigest()
		self._did_print_error = False
		if self._is_available() and self._type == "game":
			self._game = self._module.bsGetGames()[0]
		else:
			self._game = None
		bs.playSound(bs.getSound('swish'))
Ejemplo n.º 34
0
 def handleMessage(self, m):
     if isinstance(m, bs.PlayerSpazDeathMessage):
         bs.TeamGameActivity.handleMessage(self, m)
         bs.gameTimer(1000, bs.Call(self.checkEnd))
         m.spaz.getPlayer().actor.disconnectControlsFromPlayer()
         if m.how == "fall": pts = 10
         elif m.how == "impact": pts = 50
         else: pts = 0
         self.scoreSet.playerScored(m.killerPlayer,
                                    pts,
                                    screenMessage=False)
         bs.screenMessage(str(m.spaz.getPlayer().getName()) + " died!",
                          m.spaz.getPlayer().color,
                          top=True)
	def writeData(self, callback, doQuitWindow, data):
		path = bs.getEnvironment()['userScriptsDirectory'] + "/" + self.filename

		if data:
			if self.isInstalled():
				os.rename(path, path + ".bak") # rename the old file to be able to recover it if something is wrong
			with open(path, 'w') as f:
				f.write(data)
		else:
			bs.screenMessage("Failed to write mod")

		if callback:
			callback(self, data is not None)
		if doQuitWindow:
			QuitToApplyWindow()
def install(data, mod):
    installing.append(mod)
    bs.screenMessage("installing " + str(mod))
    print("installing", mod)
    for dep in data[mod].get("requires", []):
        install(data, dep)
    filename = data[mod]["filename"]

    def f(data):
        if not data:
            bs.screenMessage("failed to download mod '{}'".format(filename))
        print("writing", filename)
        with open(modPath + filename, "w") as f:
            f.write(data)
        installed.append(mod)
        check_finished()

    try_fetch_cb(mod_url(data[mod]), f)
	def _cb_serverdata(self, data):
		if not self._rootWidget.exists():
			return
		self.currently_fetching = False
		if data:
			m, v = process_server_data(data)
			#when we got network add the network mods
			localMods = self.mods[:]
			netMods = [Mod(d) for d in m.values()]
			self.mods = netMods
			netFilenames = [m.filename for m in netMods]
			for localmod in localMods:
				if localmod.filename not in netFilenames:
					self.mods.append(localmod)
			for mod in self.mods:
				mod._mods = {m.base: m for m in self.mods}
			self._refresh()
		else:
			bs.screenMessage('network error :(')
	def setBranch(self):
		branch = self.branch.text()
		if branch == '':
			branch = "master"
		bs.screenMessage("fetching branch '" + branch + "'")
		def cb(data):
			newBranch = branch
			if data:
				bs.screenMessage('ok')
			else:
				bs.screenMessage('failed to fetch branch')
				newBranch = "master"
			bs.screenMessage("set branch to " + newBranch)
			config["branch"] = newBranch
			bs.writeConfig()
			if self.branch.exists():
				bs.textWidget(edit=self.branch, text=newBranch)
			self.modManagerWindow._cb_refresh()

		get_index(cb, branch=branch)
	def install(self, callback, doQuitWindow=True):
		def check_deps_and_install(mod=None, succeded=True):
			if any([dep not in self._mods for dep in self.requires]):
				raise Exception("dependency inconsistencies")
			if not all([self._mods[dep].uptodate() for dep in self.requires]) or not succeded:
				return
			if self.url:
				mm_serverGet(self.url, {}, partial(self.writeData, callback, doQuitWindow), eval_data=False)
			else:
				bs.screenMessage("cannot download mod without url")
				raise Exception("mod.install() without url")
		if len(self.requires) < 1:
			check_deps_and_install()
		else:
			for dep in self.requires:
				bs.screenMessage(self.name + " requires " + dep + "; installing...")
				if not self._mods:
					raise Exception("missing mod._mods")
				if dep not in self._mods:
					raise Exception("dependency inconsistencies (missing " + dep + ")")
				self._mods[dep].install(check_deps_and_install, False)
def get_index(callback, branch=None, force=False):
	if TESTING:
		bs.screenMessage("NOTE: ModManager offline mode enabled", color=(1, 1, 0))
		bs.screenMessage("NOTE: branches arn't supported", color=(1, 1, 0))
		if not os.path.isfile(bs.getEnvironment()['userScriptsDirectory'] + "/../index.json"):
			bs.screenMessage("NOTE: index.json not found", color=(1, 0, 0))
			return
		with open(bs.getEnvironment()['userScriptsDirectory'] + "/../index.json", "r") as f:
			callback(json.load(f))
			return
	url = index_file(branch)
	def cache(data):
		if data:
			web_cache[url] = (data, time.time())
			bs.writeConfig()

	def f(data):
		# TODO: cancel prev fetchs
		callback(data)
		cache(data)

	if force:
		mm_serverGet(url, {}, f)
		return

	if url in web_cache:
		data, timestamp = web_cache[url]
		if timestamp + 10 * 30 > time.time():
			mm_serverGet(url, {}, cache)
		if timestamp + 10 * 60 > time.time():
			callback(data)
			return

	mm_serverGet(url, {}, f)
def check_finished():
    if any([m not in installed for m in installing]):
        return
    bs.screenMessage("installed everything.")
    if os.path.isfile(modPath + __name__ + ".pyc"):
        os.remove(modPath + __name__ + ".pyc")
    if os.path.isfile(modPath + __name__ + ".py"):
        os.remove(modPath + __name__ + ".py")
        bs.screenMessage("deleted self")
    bs.screenMessage("activating modManager")
    __import__(ENTRY_MOD)
		def cb(data):
			newBranch = branch
			if data:
				bs.screenMessage('ok')
			else:
				bs.screenMessage('failed to fetch branch')
				newBranch = "master"
			bs.screenMessage("set branch to " + newBranch)
			config["branch"] = newBranch
			bs.writeConfig()
			if self.branch.exists():
				bs.textWidget(edit=self.branch, text=newBranch)
			self.modManagerWindow._cb_refresh()
def _cb_checkUpdateData(self, data):
	try:
		if data:
			m, v = process_server_data(data)
			mods = [Mod(d) for d in m.values()]
			for mod in mods:
				mod._mods = {m.base: m for m in mods}
				if mod.isInstalled() and mod.checkUpdate():
					if config.get("auto-update-old-mods", True):
						if mod.is_old():
							bs.screenMessage("updating '" + str(mod.name) + "'")
							def cb(mod, success):
								if success:
									bs.screenMessage("'" + str(mod.name) + "' updated")
							mod.install(cb)
					else:
						if not mod.is_old():
							bs.screenMessage("Update for '" + mod.name + "' available! Check the ModManager")
	except Exception, e:
		bs.printException()
		bs.screenMessage("failed to check for updates")
import bsInternal
import os
import urllib, urllib2
import json
import random
import time
import threading
import weakref
from md5 import md5
from bsUI import *
from functools import partial

try:
	from settings_patcher import SettingsButton
except ImportError:
	bs.screenMessage("settings_patcher missing", color=(1, 0, 0))
	raise
try:
	from ui_wrappers import *
except ImportError:
	bs.screenMessage("ui_wrappers missing", color=(1, 0, 0))
	raise

PROTOCOL_VERSION = 1.0
SUPPORTS_HTTPS = False
TESTING = False

_supports_auto_reloading = True
_auto_reloader_type = "patching"
StoreWindow_setTab = StoreWindow._setTab
MainMenuWindow__init__ = MainMenuWindow.__init__
							def cb(mod, success):
								if success:
									bs.screenMessage("'" + str(mod.name) + "' updated")
		def sort_playability(mods):
			mods = sorted(self.mods, key=lambda mod: mod.playability, reverse=True)
			if self._selectedTab["label"] == "minigames":
				bs.screenMessage('experimental minigames hidden.')
				return [mod for mod in mods if (mod.playability > 0 or mod.isLocal or mod.category != "minigames")]
			return mods
import bs
from bsUI import *

try:
	from ui_wrappers import *
except ImportError:
	bs.screenMessage("ui_wrappers missing", color=(1, 0, 0))
	raise

class SettingsButton:
	def __init__(self, id, text=None, icon=None, iconColor=None, sorting_position=None):
		self.id = id
		self.text = text
		self.icon = icon
		self.iconColor = iconColor
		self.sorting_position = sorting_position
		self.textOnly = icon is None
		self._cb = lambda x: None
		self._buttonInstance = None
		self.instanceLocals = {}

	def setText(self, text):
		self.text = text
		return self

	def setCallback(self, cb):
		self._cb = cb
		return self

	def add(self):
		buttons.append(self)
	def _module_error(self, *args):
		print(self._filename + ": " + " ".join(args))
		if not self._did_print_error:
			bs.screenMessage(self._filename + ": " + " ".join(args), color=(1, 0, 0))
			self._did_print_error = True
	def _showFetchingIndicator(self):
		if self.currently_fetching:
			bs.screenMessage("loading...")
	def writeData(self, data=None):
		bs.screenMessage("Can't update local-only mod!")
def onIndex(data):
    if not data:
        bs.screenMessage("network error :(")
        return
    data = json.loads(data)
    install(data["mods"], ENTRY_MOD)