… >w<
p.s. The bot update has finished, If you are interested in the changes then here they are:
- better support for upcoming features.
- better help text.
- admin support (I will be looking for someone who would be interested in this).
- better promise’s
- a clean look to the outputs
- alias’s (listed in the help text).
- new code ^w^
import MuckletBot, math, json, time
CHECK_COMMANDS = ["check", "c", "balance", "bal", "b", "inquire", "i", "query", "q"]
SEND_COMMANDS = ["send", "s", "give", "g", "transfer", "t", "pay", "p"]
MAX_IN_CIRCULATION = 1_000_000
def Log(message): print(f"[{time.strftime('%H:%M:%S')}] {message}")
class STORAGE:
def __init__(self, data): self.data = data; self.password = "not the actual password"
def get(self, id):
self.add(id)
return self.data.get(id).get("balance")
def add(self, id):
if self.data.get(id) is None: Log(f"Added user [{id}] to the storage.")
if self.data.get(id) is None: self.data[id] = {"balance": max((MAX_IN_CIRCULATION - self.getTotal()) // 1000, 0)}
def set(self, id, amount):
self.add(id)
self.data[id]["balance"] = amount
Log(f"Set user [{id}]'s balance to [{amount}].")
def getTotal(self):
total = 0
for id in self.data: total += self.data[id]["balance"]
return total
def multiplyAll(self, multiplier):
for id in self.data: self.data[id]["balance"] = math.floor(self.data[id]["balance"] * multiplier)
Log(f"Multiplied all balances by [{multiplier}].")
def save(self):
with open("storage.json", "w") as f: json.dump(self.data, f)
storage = STORAGE(json.load(open("storage.json", "r")))
def OnBotMessage(bot = None, data = None):
if data.get("type") != "message":
bot.message(data.get("sender"), f"[{data.get('message')}] is an invalid command type, I only accept messages.")
# Log(f"Invalid command type [{data.get('type')}] from [{data.get('sender').name}].")
else:
Log (f"-- [Received command [{data.get('message')}] from [{data.get('sender').name}]]")
commands = data.get("message").split(" ")
if commands[0] in CHECK_COMMANDS:
bot.message(data.get("sender"), f" You have [{str(storage.get(data.get('sender').id))}] SinderBucks.")
Log(f"{data.get('sender').name} has [{str(storage.get(data.get('sender').id))}] SinderBucks.")
elif commands[0] in SEND_COMMANDS:
if len(commands) < 4: bot.message(data.get("sender"), f"Invalid command, please use the format: [{commands[0]} <amount> <recipient>]"); return
recipientName = " ".join(commands[2:]).strip()
recipientID = bot.getChar(recipientName).join().value
if "error" in recipientID: bot.message(data.get("sender"), f"Invalid recipient [{recipientName}]. Please make sure you are also using the full name of the recipient."); return
recipientID = recipientID.get("result").get("rid").split(".")[-1]
try: amount = int(commands[1])
except: bot.message(data.get("sender"), f"Invalid amount [{commands[1]}]. Please make sure you are using a valid number."); return
if amount < 0: bot.message(data.get("sender"), f"Invalid amount [{commands[1]}]. Please make sure you are using a valid number."); return
senderBalance = storage.get(data.get("sender").id)
if senderBalance < amount: bot.message(data.get("sender"), f"You do not have enough money to send [{amount}] SinderBucks to [{recipientName}]."); return
storage.set(recipientID, storage.get(recipientID) + amount)
storage.set(data.get("sender").id, senderBalance - amount)
bot.message(data.get("sender"), f"You have sent [{amount}] SinderBucks to [{recipientName}].")
bot.message(recipientID, f"You have received [{amount}] SinderBucks from [{data.get('sender').name}].")
Log(f"{data.get('sender').name} has sent [{amount}] SinderBucks to [{recipientName}].")
elif commands[0] == "total":
if len(commands) < 2: bot.message(data.get("sender"), f"Invalid command, please use the format: [total <password>]"); return
if commands[1] != storage.password: bot.message(data.get("sender"), f"Invalid password [{commands[1]}]."); return
bot.message(data.get("sender"), f"There are currently [{storage.getTotal()}] SinderBucks in circulation.")
Log(f"{data.get('sender').name} has checked the total amount of SinderBucks in circulation.")
elif commands[0] == "set":
if len(commands) < 5: bot.message(data.get("sender"), f"Invalid command, please use the format: [set <recipitent> <amount> <password>")
if ' '.join(commands[4:]) != storage.password: bot.message(data.get("sender"), f"Invalid password [{' '.join(commands[4:])}]."); return
recipientName = " ".join(commands[1:3]).strip()
recipientID = bot.getChar(recipientName).join().value
if "error" in recipientID: bot.message(data.get("sender"), f"Invalid recipient [{recipientName}]. Please make sure you are also using the full name of the recipient."); return
recipientID = recipientID.get("result").get("rid").split(".")[-1]
try: amount = int(commands[3])
except: bot.message(data.get("sender"), f"Invalid amount [{commands[3]}]. Please make sure you are using a valid number."); return
# set the amount
storage.set(recipientID, amount)
bot.message(data.get("sender"), f"You have set [{recipientName}]'s balance to [{storage.get(recipientID)}] SinderBucks.")
Log(f"{data.get('sender').name} has set [{recipientName}]'s balance to [{storage.get(recipientID)}] SinderBucks.")
elif commands[0] == "get":
if len(commands) < 4: bot.message(data.get("sender"), f"Invalid command, please use the format: [get <recipitent> <password>"); return
if ' '.join(commands[3:]) != storage.password: bot.message(data.get("sender"), f"Invalid password [{' '.join(commands[3:])}]."); return
recipientName = " ".join(commands[1:3]).strip()
recipientID = bot.getChar(recipientName).join().value
if "error" in recipientID: bot.message(data.get("sender"), f"Invalid recipient [{recipientName}]. Please make sure you are also using the full name of the recipient."); return
recipientID = recipientID.get("result").get("rid").split(".")[-1]
bot.message(data.get("sender"), f"[{recipientName}] has [{storage.get(recipientID)}] SinderBucks.")
Log(f"{data.get('sender').name} has checked [{recipientName}]'s balance.")
elif commands[0] == "multiply-all":
if len(commands) < 3: bot.message(data.get("sender"), f"Invalid command, please use the format: [multiply-all <multiplier> <password>"); return
if ' '.join(commands[2:]) != storage.password: bot.message(data.get("sender"), f"Invalid password [{' '.join(commands[2:])}]."); return
try: multiplier = float(commands[1])
except: bot.message(data.get("sender"), f"Invalid multiplier [{commands[1]}]. Please make sure you are using a valid number."); return
storage.multiplyAll(multiplier)
bot.message(data.get("sender"), f"You have multiplied all balances by [{multiplier}].")
elif commands[0] in ["kill", "die", "shutdown", "stop"]:
if len(commands) < 2: bot.message(data.get("sender"), f"Invalid command, please use the format: [{commands[0]} <password>]"); return
if ' '.join(commands[1:]) != storage.password: bot.message(data.get("sender"), f"Invalid password [{' '.join(commands[1:])}]."); return
bot.message(data.get("sender"), f"Shutting down...")
bot.sleep(); bot.stop()
Log(f"{data.get('sender').name} has shut down the bot.")
elif commands[0] == "report":
if len(commands) < 2: bot.message(data.get("sender"), f"Invalid command, please use the format: [report <report>]"); return
report = ' '.join(commands[1:])
bot.message(data.get("sender"), f"Thank you for your report, it has been sent to the developer.")
with open("bugs.txt", "a") as f: json.dump({"report": report, "sender": data.get("sender").name, "time": time.time()}, f)
Log(f"{data.get('sender').name} has reported the bug [{report}].")
elif commands[0] == "suggest":
if len(commands) < 2: bot.message(data.get("sender"), f"Invalid command, please use the format: [suggest <suggestion>]"); return
suggestion = ' '.join(commands[1:])
bot.message(data.get("sender"), f"Thank you for your suggestion, it has been sent to the developer.")
with open("features.txt", "a") as f: json.dump({"suggestion": suggestion, "sender": data.get("sender").name, "time": time.time()}, f)
Log(f"{data.get('sender').name} has suggested the feature [{suggestion}].")
elif commands[0] == "help":
help = f"""
**Banker Badger Commands:**
**1. main commands:**
`message Banker = [{'/'.join(CHECK_COMMANDS)}]` - Check your character's balance.
`message Banker = [{'/'.join(SEND_COMMANDS)}] <amount> <recipient>` - Send SinderBucks to another character.
`message Banker = [report] <report>` - Report a bug or issue.
`message Banker = [suggest] <suggestion>` - Suggest a feature.
`message Banker = [help]` - Show this help message.
**2. admin commands:**
`message Banker = [total] <password>` - Check the total amount of SinderBucks in circulation.
`message Banker = [set] <recipient> <amount> <password>` - Set a character's balance.
`message Banker = [get] <recipient> <password>` - Check a character's balance.
`message Banker = [multiply-all] <multiplier> <password>` - Multiply all character's balances by a number.
`message Banker = [kill] <password>` - Shut down the bot.
**Example Commands:**
`message Banker = check` - Check your character's balance.
`message Banker = send 100 Ico Twilight` - Send 100 SinderBucks to Ico Twilight.
`message Banker = report I can't send money to those in different areas` - Report a bug or issue.
`message Banker = suggest I want to be able to get interest` - Suggest a feature.
`message Banker = help` - Show this help message.
**Notes:**
1. You must use the full name of the recipient with a space between the first and last name.
2. You can send SinderBucks to any character, even if they are not online. But they will not receive a message saying that they have received SinderBucks unless they are online.
3. You may use bots to send SinderBucks to other characters, but please message the developer if you do so.
4. Ico Twilight is the developer of this bot, if you have any questions or concerns please message them on the forums.
"""
bot.message(data.get("sender"), help)
Log(f"{data.get('sender').name} has requested help.")
else:
bot.message(data.get("sender"), f"[{data.get('message')}] is an invalid command. Please type `message Banker = help` for a list of commands.")
Log(f"{data.get('sender').name} has used an invalid command [{data.get('message')}].")
def OnBotConnect(bot):
while(1):
bot.ping()
storage.save()
time.sleep(10)
if __name__ == "__main__":
bot = MuckletBot.Bot(TOKEN = "TOKEN", ORIGIN = "https://wolfery.com", HOST = "wss://api.wolfery.com", VERBOSE = False)
bot.onMessage = OnBotMessage
bot.onOpen = OnBotConnect
bot.start()
- new bot library. again if intrested:
import websocket, json, threading, time, hashlib, hmac, codecs
PROMISE_TIMEOUT = "Promise Timed Out"
PROMISE_INVALID_REQUEST = "Invalid Promise Request"
PROMISE_TIMEOUT_VALUE = 10
def Error(promise, error): raise Exception(error.get("message"))
class Promise:
def __init__(self, Manager, id): self.id = id; self.manager = Manager; self.value = None
def join(self): self.value = self.manager.awaitResponse(self.id); return self
def kill(self): self.manager.kill(self.id)
def __str__(self): return f"Promise object [{self.id}:{self.manager.awaiting[self.id]}]"
def error(self, func): func(self, self.value.get("error")) if self.value.get("error") is not None else None; return self
class PromiseManager:
def __init__(self, ws): self.ws = ws; self.awaiting, self.itterID = {}, 0
def __call__(self, method, params = None):
self.itterID += 1
id = self.itterID
self.awaiting[id] = {'timeset': time.time(), 'response': None}
self.send(method, id, params)
return Promise(self, id)
def awaitResponse(self, id):
if self.awaiting.get(id) is None: raise Exception(PROMISE_INVALID_REQUEST)
while self.awaiting[id]['response'] is None:
if time.time() - self.awaiting[id]['timeset'] > PROMISE_TIMEOUT_VALUE: raise Exception(PROMISE_TIMEOUT)
return self.awaiting[id]['response']
def clean(self):
for id in self.awaiting:
if self.awaiting[id]['response'] is not None: del self.awaiting[id]
def kill(self, id): del self.awaiting[id]
def send(self, method, id = 0, params = None):
request = {"id":id,"method":method,"params":params}
msg = json.dumps(request)
self.ws.send(msg)
def clear(self): self.awaiting = {}; self.itterID = 0
class Character:
def __init__(self, bot, name = None, id = None): self.bot, self.name, self.id = bot, name, id
class Bot:
def __init__(self, TOKEN:str = None, USERNAME:str = None, PASSWORD:str = None, BOTFIRSTNAME:str = None, BOTLASTNAME:str = None, HOST:str = 'wss://api.test.mucklet.com', ORIGIN:str = 'https://test.mucklet.com', VERBOSE:bool = False):
self.ws = websocket.WebSocketApp(HOST,on_message = self._on_message,on_error = self._on_error,on_close = self._on_close,on_open = self._on_open)
self.promise = PromiseManager(self.ws)
self.TOKEN = TOKEN
if self.TOKEN is not None:
pass
elif USERNAME is not None and PASSWORD is not None and BOTFIRSTNAME is not None and BOTLASTNAME is not None:
self.BOTFIRSTNAME, self.BOTLASTNAME, self.USERNAME = BOTFIRSTNAME, BOTLASTNAME, USERNAME
m = hashlib.sha256(); m.update(bytes(PASSWORD,'UTF-8'))
self.PASS = codecs.encode(codecs.decode(m.hexdigest(), 'hex'), 'base64').decode()[:-1]
self.HASH = codecs.encode(codecs.decode(hmac.new(bytes("TheStoryStartsHere",'UTF-8'),msg=bytes(PASSWORD,'UTF-8'), digestmod = hashlib.sha256).hexdigest(), 'hex'), 'base64').decode()[:-1]
else: raise Exception("Invalid amount of login details provided. Must provide either a [token] or a [username, password, botfirstname, botlastname]")
self.HOST, self.ORIGIN, self.VERBOSE = HOST, ORIGIN, VERBOSE
self.onMessage, self.onError, self.onClose, self.onOpen = None, None, None, None
self.CID, self.RID = None, None
def start(self): self.ws.run_forever(origin=self.ORIGIN)
def _on_message(self, ws, message):
message = json.loads(message)
if self.VERBOSE: print(json.dumps(message, indent=4, sort_keys=True))
if message.get("id") is not None:
if self.promise.awaiting.get(message.get("id")) is not None:
self.promise.awaiting[message.get("id")]['response'] = message
return
if message.get("data") is None: return
data = {
"data": message.get("data"),
"type": message.get("data").get("type"),
"sender": Character(self, message.get("data").get("char").get("name") + " " + message.get("data").get("char").get("surname"), message.get("data").get("char").get("id")) if message.get("data").get("char") is not None else None,
"reciver": Character(self, message.get("data").get("target").get("name") + " " + message.get("data").get("char").get("surname"), message.get("data").get("target").get("id")) if message.get("data").get("target") is not None else None,
"message": message.get("data").get("msg"),}
if data.get("sender") is not None:
if data.get("sender").id == self.CID: return
if message.get("event") is not None:
if message.get("event").split(".")[2] != self.CID: return
if self.onMessage is not None:
threading.Thread(target=self.onMessage, args=(self, data)).start()
def _on_error(self, ws, error, message = None, code = None):print("error:", error)
def _on_close(self, ws, a = None, b = None):print("### closed ###", a, b)
def _on_open(self, ws):threading.Thread(target=self.on_open, args=(ws,)).start()
def on_open(self, ws):
print("### open ###")
if self.TOKEN is not None: value = self.promise("auth.auth.authenticateBot", {"token": self.TOKEN}).join().error(Error).value
else: value = self.promise("auth.auth.login", {"name": self.USERNAME, "hash": self.HASH}).join().error(Error).value
if self.TOKEN is not None: value = self.promise("call.core.getBot").join().error(Error).value
else: value = self.promise("call.core.getPlayer").join().error(Error).value
self.RID = value.get("result").get("rid")
if self.TOKEN is not None: self.CID = self.RID.split('.')[-1]
if self.TOKEN is None:
value = self.promise("get."+self.RID).join().error(Error).value
result = value.get("result"); models = result.get("models")
for CID, data in models.items():
if data.get("name") == self.BOTFIRSTNAME and data.get("surname") == self.BOTLASTNAME: self.CID = data.get("id")
value = self.promise("call."+self.RID+".controlChar",params={'charId':self.CID}).join().error(lambda promise, error: None).value
self.wake().join().error(lambda promise, error: None)
value = self.promise("subscribe."+self.RID).join().error(Error).value
if self.onOpen is not None: self.onOpen(self)
def sleep(self): return self.promise("call.core.char."+self.CID+".ctrl.sleep")
def wake(self): return self.promise("call.core.char."+self.CID+".ctrl.wakeup")
def say(self, msg): return self.promise("call.core.char."+self.CID+".ctrl.say",params={'msg':msg})
def pose(self, msg): return self.promise("call.core.char."+self.CID+".ctrl.pose",params={'msg':msg})
def whisper(self, target, msg, pose='whispers'): return self.promise("call.core.char."+self.CID+".ctrl.whisper",params={'msg':msg,'charId':target.id if type(target) == Character else target,'pose':pose})
def address(self, target, msg, pose='addreses'): return self.promise("call.core.char."+self.CID+".ctrl.address",params={'msg':msg,'charId':target.id if type(target) == Character else target,'pose':pose})
def message(self, target, msg): return self.promise("call.core.char."+self.CID+".ctrl.message",params={'msg':msg,'charId':target.id if type(target) == Character else target})
def ping(self): return self.promise("call.core.char."+self.CID+".ctrl.ping")
def getChar(self, name): return self.promise("call."+self.RID+".getChar", params={"charName": name})
def stop(self): self.ws.close()
Yes I know the code is absolutly messy as hell but I know whats going on and that’s all that matters ^w^