Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- chatFunctions = {}
- droneFunctions = {}
- aboutFunctions = {}
- subFunctions = {}
- subFunctions.about = {}
- subFunctions.mail = {}
- subFunctions.computer = {}
- subFunctions.editWarp = {}
- -- startup functions -------------
- function startup()
- systemName = "server helper"
- patchNotes = {{name = "1.2", notes = "\n- @about system now shows the pastebin link for the program.\n- With @about ranks you can now see information about the diffrent ranks.\n- Added a notification you get when you rankup.\n- Now there is an \"$\" before every insertion of chat commands to hide the message."},
- {name = "1.2.1", notes = "\n- Fixed a bug that would crash the program every time someon used the @pay command while not entering a number as the second parameter."},
- {name = "1.3", notes = "\n- Added the following chat commands: \n - @warp\n - @setWarp\n - @delWarp\n\n- Renamed the following chat commands:\n - @balanceScoreboard ---> @balTop\n - @playtimeScoreboard ---> @timeTop"},
- {name = "1.4", notes = "\n- Now you dont lose all your data when you change your minecraft name.\n- Added the subcommand @about player.\n- Added the @mail chat command."},
- {name = "1.4.1", notes = "\nFixed the @about player subcommand, before you could only get information about yourself. Now you can get information about every other player as well."},
- {name = "1.5", notes = '\n- Chat commands and player names are not case-sensitive anymore.\n- Fixed a bug that caused all teleportation commands to not work.\n- With the "@tp" chat command you can now also teleport to relative coordinates like with the vanilla "/tp" command.\n- Now you can insert the "@about player" command directly form the scoreboard.\n- With the "@about player" subcommand you can now also see the placement of the player in all scoreboards.'},
- {name = "1.6", notes = '\n- Added the "@computer" chat command, this is used together with the server API\n- Added the server API, this API is used for interacting with the server helper with your own program. You can find a link to the api in "@about system"'},
- {name = "1.7", notes = '\n- "~" now works the same as "~0" (As relative coordinates when using "@tp").\n- Added the "@computer unregister" subcommand.\n- Removed the "@setWarp" and "@delWarp" chat commands.\n- Added the "@editWarp" command with the following subcommands: \n - create: Creates a warp with the given name.\n - delete: Deletes the warp with the given name.\n - setPublic: Makes the warp with the given name public wich means other players can use it as well.\n - setPrivate: Makes the warp with the given name private wich means other players cant use the warp.'},
- {name = "1.7.1", notes = 'Just a small update that adds the "@mail clear" subcommand wich deletes all read mails.'}
- }
- curVersion = patchNotes[table.maxn(patchNotes)]["name"]
- for k,name in pairs(peripheral.getNames()) do
- if peripheral.getType(name) == "modem" then
- if peripheral.wrap(name).isWireless() then
- rednet.open(name)
- end
- end
- end
- createRanks()
- createSettings()
- standardPlayerData = {
- ["rank"] = standardRank,
- ["settings"] = standardSettings,
- ["latestVersion"] = curVersion,
- ["warps"] = {},
- ["receivedMails"] = {},
- ["stats"] = {
- ["playtime"] = 0,
- ["balance"] = 250,
- ["reputation"] = 0
- },
- ["computerCount"] = 0,
- ["publicWarpCount"] = 0
- }
- mainProgramLink = "qQERbqsa"
- messageSenderLink = "FpXUacvK"
- serverAPILink = "EJ9S67hC"
- if fs.exists(systemName .. "/refuelCoords") then
- local file = fs.open(systemName .. "/refuelCoords","r")
- refuelCoords = {["x"] = tonumber(file.readLine()) ,["y"] = tonumber(file.readLine()), ["z"] = tonumber(file.readLine())}
- file.close()
- else
- term.clear()
- print("x:")
- local x = tonumber(read())
- print("y:")
- local y = tonumber(read())
- print("z:")
- local z = tonumber(read())
- local file = fs.open(systemName .. "/refuelCoords","w")
- file.writeLine(x)
- file.writeLine(y)
- file.writeLine(z)
- file.flush()
- file.close()
- refuelCoords = {["x"] = x ,["y"] = y, ["z"] = z}
- end
- if fs.exists(systemName .. "/firstStartupDate") then
- local file = fs.open(systemName .. "/firstStartupDate","r")
- firstStartupDate = file.readLine()
- file.close()
- else
- firstStartupDate = os.date()
- local file = fs.open(systemName .. "/firstStartupDate","w")
- file.write(firstStartupDate)
- file.flush()
- file.close()
- end
- createFiles()
- getPeripherals()
- onlinePlayers = playerDetector.getOnlinePlayers()
- scrollmenuLen={}
- scrollmenuInfos={}
- dropdown = {}
- dropdown["loaded"] = {}
- dropdown["loaded"]["len"] = 0
- requestedKeys = readFolder(programFolderName .. "/requestedKeys")
- registeredComputers = readFolder(programFolderName .. "/registeredComputers")
- publicWarps = readFolder(programFolderName .. "/publicWarps")
- playerData = {}
- sendTheseMessages = {}
- checkTeleportTimers = {}
- createChatCommands()
- loadPlayerData()
- createRankups()
- createScoreboard("playtime")
- createScoreboard("balance")
- getDroneData()
- createDroneActions()
- createRankInformationMessage()
- createSubcommands()
- addTimeTimer = os.startTimer(60)
- checkJoinedPlayersTimer = os.startTimer(10)
- end
- function createDroneActions() -- Creates all drone actions (a drone action is a list of functions that the drone will perform one after the other)
- createDroneAction("refuel",{"teleport","standby"})
- createDroneAction("teleportPlayer",{"importPlayer","teleport","exportEntity"})
- end
- function getPeripherals() -- checks if all peripherals that are needed are connected to the computer and connects them
- chatBoxes = {}
- droneNames = {}
- for k,peripheralName in pairs(peripheral.getNames()) do
- if string.find(peripheralName,"playerDetector") then
- playerDetector = peripheral.wrap(peripheralName)
- end
- if peripheral.getType(peripheralName) == "modem" then
- rednet.open(peripheralName)
- end
- if string.find(peripheralName,"chatBox") then
- table.insert(chatBoxes, {peripheral = peripheral.wrap(peripheralName), cooldownTime = 0})
- end
- if string.find(peripheralName,"drone_interface") then
- table.insert(droneNames, peripheralName)
- end
- if peripheral.getType(peripheralName) == "modem" then
- if peripheral.wrap(peripheralName).isWireless() then
- rednet.open(peripheralName)
- end
- end
- end
- if not playerDetector then
- error("No Player Detector found")
- end
- if table.maxn(chatBoxes) < 1 then
- error("No Chat Box found")
- end
- end
- function createFiles() -- Creates all for the program necessary files/folders
- programFolderName = systemName
- if not fs.exists(programFolderName .. "/playerData") then
- fs.makeDir(programFolderName .. "/playerData")
- end
- end
- function createRanks() -- Creates all player ranks
- playerRanks = {}
- rankNames = {}
- standardRank = "Beginner"
- createRank("Owner",6,{["canChangeOtherPlayersSettings"] = true}, {["maxWarps"] = 100, ["maxComputers"]=100, ["maxPublicWarps"] = 100}, "They own the " .. systemName .. ".")
- createRank("Admin",5,{["canChangeOtherPlayersSettings"] = true}, {["maxWarps"] = 50, ["maxComputers"]=30, ["maxPublicWarps"] = 25}, "Same as a Supervisor, but can do more Stuff.")
- createRank("Supervisor",4,{}, {["maxWarps"] = 35, ["maxComputers"] = 15, ["maxPublicWarps"] = 10}, "A supervisor is there to, you guessed it, supervise! They look after stuff like drones and Bugs. You can only become a Supervisor by being granted this Rank by an Admin or Owner.")
- createRank("Elder",3,{}, {["maxWarps"] = 25, ["maxComputers"] = 9, ["maxPublicWarps"] = 5}, "To reach the Elder rank you need to play 3000 minutes on the server.")
- createRank("Member",2,{}, {["maxWarps"] = 10, ["maxComputers"] = 3, ["maxPublicWarps"] = 2}, "To reach the Member rank you need to play 500 minutes on the server.")
- createRank("Beginner",1,{}, {["maxWarps"] = 3, ["maxComputers"] = 1, ["maxPublicWarps"] = 0}, "Everyone starts out as a Beginner. As a Beginner you only have basic permissions, to get more you need to rank up.")
- createRank("Banned",0,{["canChangeOtherPlayersSettings"] = false}, {["maxWarps"] = 0, ["maxComputers"] = 0, ["maxPublicWarps"] = 0}, "You are Banned you cant do anything.")
- end
- function createChatCommands() -- creates all chat commands (a chat command is a function that can be called by typing its name together with an @ in the chat)
- chatCommands = {}
- chatCommandNames = {}
- lowerToExactChatCommands = {}
- createChatCommand("help",1, "Lists all chat commands. As the first parameter either enter a number to change the help page or specify the name of a chat command to only get info about that command.")
- createChatCommand("about",1, "If you enter it without any parameters it gives you a list of what you can get information about.")
- createChatCommand("giveFeedback",1, "You can use this chat command to report bugs/problems or also to give ideas about new chat commands or things like settings.")
- createChatCommand("tp",1, "You can either enter a player as the first parameter or you can enter the x, y and z coordinates of your destination. If you enter \"Back\" as the first parameter you will be teleported to your last teleport position. The chunk you teleport to needs to be loaded.")
- createChatCommand("warp",1, "With this command you can enter the name of a warp you created with \"@editWarp create\" to teleport to that warp. You can also use \"@tp back\" to teleport back to where you came from.")
- createChatCommand("editWarp",1, "Lets you delete and create warps. You can also use this command to make your warps public.")
- createChatCommand("mail",1, "lets you send and read mails.")
- createChatCommand("listSettings",1, "Lists all your settings.")
- createChatCommand("changeSetting",1, "The first parameter either needs to be the name of a player or the name of a setting. If you enter the name of a player, then the setting of that player will be changed either your setting will be changed. After that just enter the value you want the setting to be changed to.")
- createChatCommand("balance",1, "Shows your balance. If you enter a player as the first parameter then it shows the balance of that player.")
- createChatCommand("pay",1, "Pays the player that you enter as the first parameter the amount of credits that you specified as the second parameter.")
- createChatCommand("timeTop",1, "Shows the playtime scoreboard. If the first parameter is blank, then it shows your position, if it is a number, then it shows the page with that number.")
- createChatCommand("balTop",1, "Shows the balance scoreboard. If the first parameter is blank, then it shows your position, if it is a number, then it shows the page with that number.")
- createChatCommand("computer",2, "Lets you do like things like requesting payment from other players with your own program.")
- createChatCommand("setRank",5, "Sets the rank of the player specified in the first parameter to the rank specified in the second parameter.")
- createChatCommand("ban",5, "Bans the player specified in the first parameter.")
- createChatCommand("unban",5, "Unbans the player specified in the first parameter.")
- end
- function createSubcommands() -- creates all subcommands
- createSubcommand("about","system",1,"Gives information about the system.")
- createSubcommand("about","ranks",1,"Gives information about all player ranks.")
- createSubcommand("about","player",1,"Gives information about the player stated as the first parameter.")
- createSubcommand("mail","send",1,"Lets you send mails. The first parameter is the receiving player, after that you just type in the text you want to send.")
- createSubcommand("mail","list",1,"Lists all your mails. You can also enter a page as the first parameter.")
- createSubcommand("mail","read",1,"Lets you read the mail you entered the id (number) of.")
- createSubcommand("mail","respond",1,"Sends a mail as a response to the mail you entered the id (number) of.")
- createSubcommand("mail","delete",1,"Deletes the mail you entered the id (number) of.")
- createSubcommand("mail","clear",1,"Deletes all read mails.")
- createSubcommand("computer","requestKey",2,'Sends you a key you need to be able to use the server api (you can find the link to the server api with "@about system").')
- createSubcommand("computer","clearKeys",2,"Deletes all the keys that you requested that you didnt use to register with a computer.")
- createSubcommand("computer","list",2,"Lists all your registered computers.")
- createSubcommand("computer","pay",2,"Pays the computer with the id specifed in the first parameter the amount specifed in the second parameter.")
- createSubcommand("computer","unregister",2,"Unregisters the computer with the id given as the first parameter.")
- createSubcommand("editWarp","create",1,"Creates a warp with the given name.")
- createSubcommand("editWarp","delete",1,"Deletes a warp with the given name.")
- createSubcommand("editWarp","list",1,"Lists all of your private and public warps.")
- createSubcommand("editWarp","setPublic",2,"Sets the given warp to be public, wich means other players can use it as well.")
- createSubcommand("editWarp","setPrivate",2,"Sets the given warp to be private, wich means other players cant it.")
- end
- function createSettings() -- creates all player settings
- settings = {}
- standardSettings = {}
- createSetting("disableJoinMessage",false,0, "Disables the joining message.")
- createSetting("disablePatchMessage",false,0, "Disables the patch notes notifications.")
- createSetting("disableMailNotifications",false,0, "Disables all mail notifications.")
- createSetting("disableAllMessages",false,0, "Disables all system messages (not recommended, if you set this to true a lot of essential functions will be disabled for you).")
- createSetting("canChangeOtherPlayersSettings",false,5, "Allows you, to change other players settings.")
- end
- function createRankups() -- creates all rankup conditions (such as how long you need to play to get a new rank)
- createRankup("Member", "playtime", 500)
- createRankup("Elder", "playtime", 3000)
- end
- function loadPlayerData() -- loads the data of all registered players
- playerNames = fs.list(programFolderName .. "/playerData")
- lowerToExactPlayerNames = {}
- for k,playerName in pairs(playerNames) do
- lowerToExactPlayerNames[string.lower(playerName)] = playerName
- getPlayerData(playerName)
- updatePlayerData(playerName)
- end
- end
- function updatePlayerData(playerName) -- checks if the settings of any player are outdated and changes them if necessary
- for dataName, dataValue in pairs(standardPlayerData) do
- if not playerData[playerName][dataName] then
- playerData[playerName][dataName] = dataValue
- end
- end
- for settingName, settingValue in pairs(standardSettings) do
- if not playerData[playerName]["settings"][settingName] then
- playerData[playerName]["settings"][settingName] = settingValue
- end
- end
- for settingName, settingValue in pairs(playerData[playerName]["settings"]) do
- if not settings[settingName] then
- playerData[playerName]["settings"][settingName] = nil
- end
- end
- savePlayerData(playerName)
- end
- function createRankInformationMessage() -- creates the message about ranks that will be sent with the aboutFunctions.ranks function
- rankInformationMessage = {}
- for k,rankName in ipairs(rankNames) do
- local rankTable = playerRanks[rankName]
- table.insert(rankInformationMessage, {text = "\n" .. rankName, color = "green", hoverEvent = hoverMessage(rankTable["info"])})
- table.insert(rankInformationMessage, {text = " - Permission level: ", hoverEvent = hoverMessage(rankTable["info"])})
- table.insert(rankInformationMessage, {text = rankTable["permissionLevel"], color = "green", hoverEvent = hoverMessage(rankTable["info"])})
- end
- end
- -------------------------------------
- -- main functions -------------------
- function main() -- the main function that runs the whole time and listens to events
- while true do
- os.startTimer(0.25)
- info1,info2,info3,info4 = os.pullEvent()
- performDroneActions()
- if info1 == "rednet_message" then
- if registeredComputers[info2] and info4 == "server" then
- local message = getMessageTable(info3,registeredComputers[info2]["key"])
- if message["action"] == "requestPayment" then
- message["amount"] = tonumber(message["amount"])
- if type(message["amount"]) ~= "number" then
- computerError(info2,"The amount you request a player to pay needs to be a number.")
- goto skipMessage
- end
- if message["amount"] <= 0 then
- computerError(info2,"The amount you request a player to pay needs to be a positive number.")
- goto skipMessage
- end
- if type(message["text"]) ~= "string" then
- computerError(info2,"The text of the requestPayment function needs to a string")
- goto skipMessage
- end
- if not playerData[exactName(message["player"])] then
- computerError(info2,"The player you request a payment from needs to be a registered player.")
- goto skipMessage
- end
- sendMessage({{text = message["text"], hoverEvent = hoverMessage("Shift + click to pay " .. message["amount"] .. "c"), insertion = "$@computer pay " .. info2 .. " " .. message["amount"]}}, message["player"])
- end
- if message["action"] == "pay" then
- message["amount"] = tonumber(message["amount"])
- if type(message["amount"]) ~= "number" then
- computerError(info2,"The amount you pay a player needs to be a number.")
- goto skipMessage
- end
- if message["amount"] <= 0 then
- computerError(info2,"The amount you pay a player needs to be a positive number.")
- goto skipMessage
- end
- if message["amount"] > registeredComputers[info2]["balance"] then
- computerError(info2,"The Computer dosnt have enaugh credits to pay this amount.")
- goto skipMessage
- end
- if not playerData[exactName(message["player"])] then
- computerError(info2,"The player you pay needs to be a registered player.")
- goto skipMessage
- end
- payPlayerFromComputer(info2,message["player"],message["amount"])
- if type(message["text"]) == "string" then
- sendMessage(message["text"], message["player"])
- end
- end
- if message["action"] == "getBalance" then
- sendRednet(info2,{["action"] = "sendingBalance", ["balance"] = registeredComputers[info2]["balance"]})
- end
- if message["action"] == "getOwner" then
- sendRednet(info2,{["action"] = "sendingOwner", ["owner"] = registeredComputers[info2]["owner"]})
- end
- else
- registerComputer(info2,info3)
- end
- ::skipMessage::
- end
- if info1 == "chat" and not isMessageDouble() then
- local uuid = info4
- local uuidName = getPlayerNameByuuid(uuid)
- if not playerData[info2] then -- checks if player is registered
- if uuidName then
- playerData[info2] = playerData[uuidName]
- playerData[info2]["uuid"] = uuid
- savePlayerData(info2)
- fs.delete(programFolderName .. "/playerData/" .. uuidName)
- sendMessage("It seems like you renamed yourself, your data from your old name has been succesfully transferred to your new one.", info2, "green")
- else
- getPlayerData(info2)
- end
- end
- if not playerData[info2]["uuid"] then
- playerData[info2]["uuid"] = uuid
- savePlayerData(info2)
- end
- returnMessage,params = getChatCommand(info2,info3)
- if returnMessage then -- checks if the message was a chat command
- executingPlayer = info2
- if type(returnMessage) == "function" then -- checks if the chat command is valid
- local chatErrorMessage = returnMessage(params)
- if chatErrorMessage then
- sendMessage(chatErrorMessage,executingPlayer,"red")
- end
- else
- sendMessage(returnMessage,executingPlayer,"red") -- sends an error message
- end
- end
- end
- if info1 == "timer" then
- if info2 == addTimeTimer then
- addTime()
- checkRankups()
- giveMoney()
- end
- if info2 == checkJoinedPlayersTimer then -- checks if a player joined the server
- sendJoinMessages()
- sendPatchNotes()
- checkJoinedPlayersTimer = os.startTimer(10)
- end
- end
- end
- end
- ------------------------------------
- -- external computer functions ------------------------------
- function payPlayerFromComputer(computerId,playerName,amount)
- if registeredComputers[computerId]["balance"] < amount then
- error("amount is higher then balance")
- end
- if 0 >= amount then
- error("amount needs to be positive")
- end
- registeredComputers[computerId]["balance"] = registeredComputers[computerId]["balance"] - amount
- saveComputerData(computerId)
- playerData[playerName]["stats"]["balance"] = playerData[playerName]["stats"]["balance"] + amount
- savePlayerData(playerName,"stats")
- updateScoreboard("balance",playerName)
- sendRednet(info2,{["action"] = "paymentConfirmation", ["player"] = playerName, ["amount"] = amount})
- end
- function computerError(id,errorMessage)
- if not registeredComputers[id] then
- error("This is not a registered computer.")
- end
- sendMail(registeredComputers[id]["owner"], "Your computer caused an error.", errorMessage)
- end
- function generateKey()
- local usableChars = {"1","2","3","4","5","6","7","8","9","0","!","\"","§","$","%","&","/","(",")","?","\\","}","]","[","{","@","q","w","e","r","t","z","u","i","o","p","ü","+","a","s","d","f","g","h","j","k","l","ö","ä","#","y","x","c","v","b","n","m",".","-","<",">","Y","X","C","V","B","N","M",";",":","_","'","L","K","J","H","G","F","D","S","A","*","P","O","I","U","Z","T","R","E","W","Q","|","~"}local usableCount = #usableChars
- local key = ""
- for i = 1,16 do
- key = key .. usableChars[math.random(1, usableCount)]
- end
- return key
- end
- function encrypt(text,key)
- local result = ""
- local keyLength = #key
- for i = 1, #text do
- local textByte = text:byte(i)
- local keyByte = key:byte((i - 1) % keyLength + 1)
- result = result .. string.char(bit.bxor(textByte, keyByte))
- end
- return result
- end
- function decrypt(encryptedText,key)
- return encrypt(encryptedText,key)
- end
- function createMessageString(messageTable,key)
- local outTable = {}
- local returnString = "@@"
- local i = 1
- for k,v in pairs(messageTable) do
- outTable[i] = {["key"] = k, ["value"] = v}
- i=i+1
- end
- for i = 1, #outTable do
- local i = math.random(1,#outTable)
- returnString = returnString .. outTable[i]["key"] .. "=" .. outTable[i]["value"] .. ","
- table.remove(outTable,i)
- end
- returnString = encrypt(returnString,key)
- return returnString
- end
- function getMessageTable(messageString,key)
- local messageString = decrypt(messageString,key)
- if string.sub(messageString,1,2) == "@@" then
- messageString = string.sub(messageString,3,-1)
- else
- return {}
- end
- local returnTable = {}
- local curPos = 1
- while true do
- local equalPos = string.find(messageString,"=",curPos)
- if not equalPos then
- break
- end
- local curKey = string.sub(messageString,curPos,equalPos-1)
- curPos = equalPos+1
- local commaPos = string.find(messageString,",",curPos)
- if not commaPos then
- break
- end
- local curValue = string.sub(messageString,curPos,commaPos-1)
- curPos = commaPos+1
- returnTable[curKey] = curValue
- end
- return returnTable
- end
- function sendRednet(id,messageTable)
- if not registeredComputers[id] then
- error("This is not a registered computer.")
- end
- local messageString = createMessageString(messageTable,registeredComputers[id]["key"])
- rednet.send(id,messageString,"serverResponse")
- end
- function registerComputer(id, messageString)
- for k, requestedKey in pairs(requestedKeys) do
- print(decrypt(messageString,requestedKey["key"]))
- local curMessage = getMessageTable(messageString,requestedKey["key"])
- if curMessage["action"] == "register" then
- registeredComputers[id] = {}
- registeredComputers[id]["key"] = requestedKey["key"]
- registeredComputers[id]["balance"] = 0
- registeredComputers[id]["owner"] = requestedKey["owner"]
- saveComputerData(id)
- table.remove(requestedKeys,k)
- saveTable(programFolderName .. "/requestedKeys", requestedKeys)
- sendRednet(id, {["action"]="registrationResponse",["registrationWorked"]="true"})
- return
- end
- end
- print("")
- end
- function getComputerData(id)
- if not registeredComputers[id] then
- error("This is not a registered computer.")
- end
- if id == "all" then
- registeredComputers = readFolder(programFolderName .. "/registeredComputers")
- return
- end
- registeredComputers[id] = readFolder(programFolderName .. "/registeredComputers/" .. id)
- end
- function saveComputerData(id)
- if not registeredComputers[id] then
- error("This is not a registered computer.")
- end
- saveTable(programFolderName .. "/registeredComputers/" .. id,registeredComputers[id])
- end
- function unregisterComputer(id)
- local owner = registeredComputers[id]["owner"]
- playerData[owner]["computerCount"] = playerData[owner]["computerCount"]-1
- playerData[owner]["stats"]["balance"] = playerData[owner]["stats"]["balance"] + registeredComputers[id]["balance"]
- savePlayerData(owner)
- updateScoreboard("balance",owner)
- registeredComputers[id] = nil
- fs.delete(programFolderName .. "/registeredComputers/" .. id)
- sendMessage("The computer with the ID " .. id .. " has been unregistered.", executingPlayer, "green")
- end
- -------------------------------------------------
- -- Drone functions ------------------------------
- function getDroneData(droneName) -- loads all drone data from the files
- if not droneName then
- droneData = readFolder(programFolderName .. "/droneData")
- for k,droneName in pairs(droneNames) do
- if not droneData[droneName] then
- registerDrone(droneName)
- else
- droneData[droneName]["peripheral"] = peripheral.wrap(droneName)
- end
- end
- else
- droneData[droneName] = readFolder(programFolderName .. "/droneData/" .. droneName)
- if not droneData[droneName] then
- registerDrone(droneName)
- else
- droneData[droneName]["peripheral"] = peripheral.wrap(droneName)
- end
- end
- end
- function registerDrone(droneName) -- registers a new drone (creates all the files and stuff)
- local dronePeripheral = peripheral.wrap(droneName)
- if not dronePeripheral then
- error("Not a valid drone interface")
- end
- droneData[droneName] ={["hasWork"] = false, ["peripheral"] = dronePeripheral}
- refuelDrone(droneName)
- saveDroneData(droneName)
- end
- function saveDroneData(droneName) -- saves the drone data in a file
- if droneName == "all" or (not droneData) then
- saveTable(programFolderName .. "/droneData",droneData)
- return
- end
- if not droneData[droneName] then
- registerDrone(droneName)
- return
- end
- saveTable(programFolderName .. "/droneData/" .. droneName, droneData[droneName])
- end
- function setDroneAction(droneName,action,params,controllingPlayer) -- sets the action of a drone
- if not droneData[droneName] then
- error("This drone does not exist.")
- end
- if controllingPlayer then
- if playerData[controllingPlayer]["lostDrone"] and action ~= "refuel" then
- sendMessage("Because you have lost a drone, you currently cant use drones. Please try again later.", controllingPlayer, "red")
- return false
- end
- end
- droneData[droneName]["hasWork"] = true
- droneData[droneName]["actionName"] = action
- droneData[droneName]["startedFunctions"] = 0
- droneData[droneName]["controllingPlayer"] = controllingPlayer
- droneData[droneName]["params"] = params or {}
- droneData[droneName]["startTime"] = os.epoch("local")
- return true
- end
- function createDroneAction(name, functions)
- if type(name) ~= "string" then
- error("name needs to be a string got " .. type(name))
- end
- if type(functions) ~= "table" then
- error("functions needs to be a table got " .. type(name))
- end
- droneActions = droneActions or {}
- local actionFunctions = {}
- for k,v in pairs(functions) do
- table.insert(actionFunctions,_ENV["droneFunctions"][v])
- end
- droneActions[name] = actionFunctions
- end
- function disconnectDrone(droneName) -- disconnects the drone (this drone will not be used anymore till its reconnected)
- if not droneData[droneName] then
- error("A drone named \"" .. droneName .. "\" does not exist." )
- end
- local controller = droneData[droneName]["controllingPlayer"]
- local file = fs.open(programFolderName .. "/disconnectedDrones", "a")
- if controller then
- file.write(os.date("local") .. ": The player \"" .. controller .. "\" has disconnected the drone named \"" .. droneName .. "\"")
- sendMessage("Your reputation decreased by 50, because you havent recovered the drone in time. To recover some of your lost reputation you can recover the drone at a later time.", controller, "red")
- playerData[controller]["lostDrone"] = nil
- giveReputation(controller, -50)
- else
- file.writeLine(os.date() .. ": The drone named \"" .. droneName .. "\" has been disconnected.")
- end
- file.flush()
- file.close()
- droneData[droneName] = {["isDisconnected"] = true, ["hasWork"] = false, ["peripheral"] = droneData[droneName]["peripheral"]}
- saveDroneData(droneName)
- end
- function performDroneActions() -- performs the drone actions of all drones
- for droneName,drone in pairs(droneData) do
- checkDroneStatus(droneName)
- if drone["hasWork"] then
- performDroneAction(droneName)
- end
- end
- end
- function performDroneAction(droneName) -- performs the drone action of the specified drone
- local dronePeriph = droneData[droneName]["peripheral"]
- if not dronePeriph.isConnectedToDrone() then -- checks if the drone is connected
- return "error"
- end
- if os.epoch("local") - droneData[droneName]["startTime"] > 120000 then -- Checks if the drone takes too long to perform its action
- finishAction(droneName)
- end
- if droneData[droneName]["startedFunctions"] == 0 then -- Starts the first function of the drone
- droneData[droneName]["startedFunctions"] = droneData[droneName]["startedFunctions"] + 1
- droneActions[droneData[droneName]["actionName"]][droneData[droneName]["startedFunctions"]](droneName, droneData[droneName]["params"][droneData[droneName]["startedFunctions"]])
- end
- if (not pcall(dronePeriph.isActionDone)) and droneData[droneName]["actionName"] then -- restarts the drone function if it got cancelled because of something like a server restart
- droneActions[droneData[droneName]["actionName"]][droneData[droneName]["startedFunctions"]](droneName, droneData[droneName]["params"][droneData[droneName]["startedFunctions"]])
- end
- if dronePeriph.isActionDone() then -- starts next function or completes the action
- if droneData[droneName]["startedFunctions"] == table.maxn(droneActions[droneData[droneName]["actionName"]]) then
- finishAction(droneName)
- return
- end
- droneData[droneName]["startedFunctions"] = droneData[droneName]["startedFunctions"] + 1
- droneActions[droneData[droneName]["actionName"]][droneData[droneName]["startedFunctions"]](droneName, droneData[droneName]["params"][droneData[droneName]["startedFunctions"]])
- saveDroneData(droneName)
- end
- end
- function finishAction(droneName, errorMessage) -- cancels/finishes the action of the drone
- if droneData[droneName]["controllingPlayer"] and droneData[droneName]["actionName"] ~= "refuel" then
- if errorMessage then
- sendMessage(errorMessage, droneData[droneName]["controllingPlayer"] ,"red")
- elseif checkPlayerTpFailure(droneName) then
- sendMessage("Teleportation failed, please only teleport to loaded chunks", droneData[droneName]["controllingPlayer"], "red")
- else
- sendMessage("The drone named \"" .. droneName .. "\" has finished its task.", droneData[droneName]["controllingPlayer"], "green")
- end
- end
- if droneData[droneName]["actionName"] == "refuel" then
- droneData[droneName]["startedFunctions"] = nil
- droneData[droneName]["hasWork"] = false
- droneData[droneName]["params"] = nil
- droneData[droneName]["actionName"] = nil
- droneData[droneName]["controllingPlayer"] = nil
- droneData[droneName]["actionName"] = nil
- droneData[droneName]["startTime"] = nil
- else
- refuelDrone(droneName, droneData[droneName]["controllingPlayer"])
- end
- saveDroneData(droneName)
- end
- function checkPlayerTpFailure(droneName) -- checks if the player that was teleported has reached his destination
- local playerName = droneData[droneName]["controllingPlayer"]
- if droneData[droneName]["actionName"] ~= "teleportPlayer" or not table.contains(playerDetector.getOnlinePlayers(), playerName) then
- return false
- end
- local x = droneData[droneName]["params"][droneData[droneName]["startedFunctions"]-1]["x"]
- local y = droneData[droneName]["params"][droneData[droneName]["startedFunctions"]-1]["y"]
- local z = droneData[droneName]["params"][droneData[droneName]["startedFunctions"]-1]["z"]
- local playerPos = playerDetector.getPlayerPos(playerName)
- local pX = playerPos["x"]
- local pY = playerPos["y"]
- local pZ = playerPos["z"]
- if not (pX > x-10 and pX < x+10 and pY > y-10 and pY < y+10 and pZ > z-10 and pZ < z+10) then
- droneFunctions.exportEntity(droneName)
- return true
- end
- end
- function checkDroneStatus(droneName) -- checks if the drone was disconnected/reconnected etc.
- checkDroneDisconnection(droneName)
- checkCancelledDroneDisconnection(droneName)
- checkDroneReconnection(droneName)
- end
- function checkDroneDisconnection(droneName) -- checks if the drone was disconnected
- if (not droneData[droneName]["peripheral"].isConnectedToDrone()) and (not droneData[droneName]["isDisconnected"]) then
- if not droneData[droneName]["disconnectTime"] and droneData[droneName]["controllingPlayer"] then
- sendMessage("The drone named \"" .. droneName .. "\" you were using has been disconnected, please recover the drone (replace it in the world) within 60 seconds, if you dont, and this happens too often, you will get banned.", droneData[droneName]["controllingPlayer"], "red")
- playerData[droneData[droneName]["controllingPlayer"]]["lostDrone"] = true
- savePlayerData(droneData[droneName]["controllingPlayer"])
- end
- if not droneData[droneName]["disconnectTime"] then
- droneData[droneName]["disconnectTime"] = os.epoch("local")
- saveDroneData(droneName)
- elseif os.epoch("local") - droneData[droneName]["disconnectTime"] > 60000 then
- disconnectDrone(droneName)
- end
- end
- end
- function checkCancelledDroneDisconnection(droneName) -- checks if the drone disconnection was cancelled
- if droneData[droneName]["disconnectTime"] and droneData[droneName]["peripheral"].isConnectedToDrone() then
- droneData[droneName]["disconnectTime"] = nil
- refuelDrone(droneName, droneData[droneName]["peripheral"].getOwnerName())
- if droneData[droneName]["controllingPlayer"] then
- sendMessage("The drone named \"" .. droneName .. "\" has been reconnected.", droneData[droneName]["controllingPlayer"], "green")
- playerData[droneData[droneName]["controllingPlayer"]]["lostDrone"] = nil
- savePlayerData(droneData[droneName]["controllingPlayer"])
- end
- end
- end
- function checkDroneReconnection(droneName) -- checks if the drone was reconnected
- if droneData[droneName]["isDisconnected"] and droneData[droneName]["peripheral"].isConnectedToDrone() then
- droneData[droneName]["isDisconnected"] = nil
- droneData[droneName]["disconnectTime"] = nil
- saveDroneData(droneName)
- refuelDrone(droneName, droneData[droneName]["peripheral"].getOwnerName())
- giveReputation(droneData[droneName]["peripheral"].getOwnerName(), 25)
- sendMessage("You have gained 25 reputation for reconnecting the drone named \"" .. droneName .. "\".", droneData[droneName]["peripheral"].getOwnerName(), "green")
- end
- end
- function refuelDrone(droneName,player) -- refuels the drone
- if not droneData[droneName] then
- error("The drone named " .. droneName .. " does not exist.")
- end
- setDroneAction(droneName,"refuel",{refuelCoords},player)
- end
- function getFreeDrone() -- gets the first free drone (a drone that currently does not perform an action)
- for droneName,drone in pairs(droneData) do
- if not drone["hasWork"] and not drone["isDisconnected"] then
- return droneName
- end
- end
- end
- function getConnectedDroneCount() -- gets the count of connected drones
- local count = 0
- for k,v in pairs(droneData) do
- if not v["isDisconnected"] then
- count = count + 1
- end
- end
- return count
- end
- function droneFunctions.teleport(droneName,params) -- teleports the drone to the specified coordinates
- if not params then
- finishAction(droneName, "The teleportation was stopped because of an unexpected error.")
- return
- end
- local dronePeriph = droneData[droneName]["peripheral"]
- local x = params["x"]
- local y = params["y"]
- local z = params["z"]
- dronePeriph.clearArea()
- dronePeriph.addArea(x,y,z)
- dronePeriph.abortAction()
- dronePeriph.setAction("goto")
- end
- function droneFunctions.standby(droneName) -- sets the drone to be on standby
- droneData[droneName]["peripheral"].abortAction()
- droneData[droneName]["peripheral"].setAction("standby")
- end
- function droneFunctions.importPlayer(droneName,params) -- picks up the player that is controlling the drone
- if not params then
- finishAction(droneName, "The player import was stopped because of an unexpected error.")
- return
- end
- local x1 = params["x"] - 3
- local y1 = params["y"] - 3
- local z1 = params["z"] - 3
- local x2 = params["x"] + 3
- local y2 = params["y"] + 3
- local z2 = params["z"] + 3
- local dronePeriph = droneData[droneName]["peripheral"]
- dronePeriph.clearArea()
- dronePeriph.addArea(x1,y1,z1,x2,y2,z2,"Filled")
- dronePeriph.clearWhitelistText()
- dronePeriph.clearBlacklistText()
- dronePeriph.addWhitelistText("player")
- dronePeriph.abortAction()
- dronePeriph.setAction("entity_import")
- end
- function droneFunctions.exportEntity(droneName) -- exports the entity that the drone is currently carrying
- local dronePeriph = droneData[droneName]["peripheral"]
- dronePeriph.clearWhitelistText()
- dronePeriph.clearBlacklistText()
- dronePeriph.clearArea()
- dronePeriph.addArea(dronePeriph.getDronePosition())
- dronePeriph.abortAction()
- dronePeriph.setAction("entity_export")
- end
- -------------------------------------------------
- -- Settings and data functions -------------------
- function getRankVariable(variable,player)
- return playerRanks[playerData[player]["rank"]]["rankVariables"][variable]
- end
- function getPlayerNameByuuid(uuid)
- for name,data in pairs(playerData) do
- if data["uuid"] == uuid then
- return name
- end
- end
- end
- function getPlayerSetting(setting,player) -- get the value of the specified setting of the specified player
- if not playerData[player] then
- error(player .. " is not a registered player.")
- end
- if not settings[setting] then
- error(setting .. " is not a setting")
- end
- return playerData[player]["settings"][setting] or settings[setting]["standardValue"]
- end
- function createSetting(name,standardValue,requiredPermLevl,info) -- creates a player setting
- settings[name] = {}
- settings[name]["standardValue"] = standardValue
- settings[name]["requiredPermLevl"] = requiredPermLevl
- settings[name]["type"] = type(standardValue)
- settings[name]["info"] = info
- settingNames = settingNames or {}
- table.insert(settingNames,name)
- standardSettings[name] = standardValue
- end
- function changeSetting(player,setting,value) -- changes the setting of a player
- if not table.contains(playerNames,player) then
- error("not a viable player")
- end
- if not settings[setting] then
- error("not a viable setting")
- end
- if type(value) ~= settings[setting]["type"] then
- error("bad argument #3 (value supposed to have the type " .. settings[setting]["type"] .. " but has the type" .. type(value) .. ")")
- end
- playerData[player]["settings"][setting] = value
- saveTable(programFolderName .. "/playerData/" .. player .. "/settings", playerData[player]["settings"])
- end
- function addTime() -- adds playtime to all players
- for k,player in pairs(playerDetector.getOnlinePlayers()) do
- if not playerData[player] then -- registers the player if they are new
- getPlayerData(player)
- end
- playerData[player]["stats"]["playtime"] = playerData[player]["stats"]["playtime"] + 1
- if playerData[player]["stats"]["playtime"] % 60 == 0 then
- giveMoney(player, 150)
- end
- savePlayerData(player, "stats")
- updateScoreboard("playtime", player)
- end
- addTimeTimer = os.startTimer(60)
- end
- function updateScoreboard(data, player) -- updates position of the specified player in the specified scoreboard
- if not scoreboards[data] then
- error("This scoreboard does not exist")
- end
- local score = playerData[player]["stats"][data]
- local position = getScoreboardPosition(data, player)
- if not position then -- adds the player to the end of the scoreboard if they dont have a position yet
- table.insert(scoreboards[data], {["playerName"] = player, ["score"] = score})
- position = table.maxn(scoreboards[data])
- end
- scoreboards[data][position]["score"] = score
- if position ~= 1 then
- while score > scoreboards[data][position-1]["score"] do -- ckecks if the score of the player is higher than the players in the spots over them
- table.remove(scoreboards[data], position)
- position = position - 1
- table.insert(scoreboards[data], position, {["playerName"] = player, ["score"] = score})
- if position == 1 then
- return
- end
- end
- end
- if scoreboards[data][position+1] then
- while score < scoreboards[data][position+1]["score"] do -- ckecks if the score of the player is lower than the players in the spots under them
- table.remove(scoreboards[data], position)
- position = position + 1
- table.insert(scoreboards[data], position, {["playerName"] = player, ["score"] = score})
- if not scoreboards[data][position+1] then
- return
- end
- end
- end
- end
- function getScoreboardPosition(data, player) -- gets the position of a specified player in a specified scoreboard
- if not scoreboards[data] then
- error("This scoreboard does not exist")
- end
- for k,v in pairs(scoreboards[data]) do
- if v["playerName"] == player then
- return k
- end
- end
- end
- function createScoreboard(data) -- creates a scoreboard (the variable data needs to be a index of the playerData[playerName]["stats"] table)
- scoreboards = scoreboards or {}
- local returnTable = {}
- local scores = {}
- local temporaryTable = {}
- for k,v in pairs(playerData) do
- temporaryTable[v["stats"][data]] = temporaryTable[v["stats"][data]] or {}
- table.insert(temporaryTable[v["stats"][data]], k)
- if not table.contains(scores, v["stats"][data]) then
- table.insert(scores,v["stats"][data])
- end
- end
- scores = sortScores(scores)
- local maxn = table.maxn(scores)
- for k,v in pairs(scores) do
- for k2,v2 in pairs(temporaryTable[v]) do
- table.insert(returnTable, table.maxn(returnTable)+1, {playerName = v2, score = v})
- end
- end
- scoreboards[data] = returnTable
- end
- function sortScores(scores) -- sorts the scores of a scoreboard in the right order
- local returnTable = {[1] = scores[table.maxn(scores)]}
- scores[table.maxn(scores)] = nil
- for k,v in pairs(scores) do
- local worked = false
- for k2,v2 in pairs(returnTable) do
- if v > v2 then
- table.insert(returnTable,k2 , v)
- worked = true
- break
- end
- end
- if not worked then
- table.insert(returnTable, v)
- end
- end
- return returnTable
- end
- ----------------------------------------
- -- player functions ---------------
- function getComputersOfPlayer(name)
- local returnTable = {}
- for id,computer in pairs(registeredComputers) do
- if computer["owner"] == name then
- returnTable[id] = computer
- end
- end
- return returnTable
- end
- function getMaxComputers(name)
- return playerRanks[playerData[name]["rank"]]["rankVariables"]["maxComputers"]
- end
- function exactName(name) -- returns the exact player name (makes player names not case-sensitive)
- return lowerToExactPlayerNames[string.lower(name or "")]
- end
- function sendMail(receiver,subject,text,sender) -- sends a mail to the receiver
- if not playerData[receiver] then
- error(receiver .. " is not a registered player.")
- end
- table.insert(playerData[receiver]["receivedMails"], 1, {["subject"] = subject, ["text"] = text, ["sender"] = sender or systemName, ["date"] = os.date("%A %d %B %Y")})
- playerData[receiver]["receivedMails"][51] = nil
- savePlayerData(receiver,"receivedMails")
- sendMessage({{text = "You have received a new mail.", hoverEvent = hoverMessage("Shift + click to disable this message."), insertion = "$@changeSetting disableMailNotifications true"}}, receiver, "green")
- end
- function getWarpCount(player) -- returns the count of warps the player currently has
- local warpCount = 0
- for k,v in pairs(playerData[player]["warps"]) do
- warpCount = warpCount + 1
- end
- return warpCount
- end
- function getMaxWarps(player) -- returns the count of warps the player can have
- return playerRanks[playerData[player]["rank"]]["rankVariables"]["maxWarps"]
- end
- function getJoinedPlayers() -- checks if a player joined the server
- local returnTable = {}
- for k, playerName in pairs(playerDetector.getOnlinePlayers()) do
- if not playerData[playerName] then
- registerNewPlayer(playerName)
- end
- if not table.contains(onlinePlayers, playerName) then
- table.insert(returnTable, playerName)
- end
- end
- onlinePlayers = playerDetector.getOnlinePlayers()
- return returnTable
- end
- function isPlayerOnline(player) -- checks if the player is online
- return table.contains(playerDetector.getOnlinePlayers(),player)
- end
- function giveReputation(player, amount) -- gives reputation to the player
- if not playerData[player]["stats"]["reputation"] then
- playerData[player]["stats"]["reputation"] = amount
- else
- playerData[player]["stats"]["reputation"] = playerData[player]["stats"]["reputation"] + amount
- end
- if playerData[player]["stats"]["reputation"] <= -100 and playerData[player]["rank"] ~= "Banned" then -- checks if the player should be banned
- banPlayer(player)
- elseif playerData[player]["stats"]["reputation"] > -100 and playerData[player]["rank"] == "Banned" then -- chekcs if the player should be unbanned
- unbanPlayer(player)
- end
- savePlayerData(player)
- end
- function unbanPlayer(player, unbanningPlayer) -- unbanns the specified player
- if unbanningPlayer then
- sendMessage("You have been unbanned from the " .. systemName .. " by " .. unbanningPlayer .. ".", player, "green")
- sendMessage("You have succesfully unbanned the player " .. player .. ".", unbanningPlayer, "green")
- setPlayerRank(player, getRankByPlaytime(player))
- else
- sendMessage("You have been unbanned from the " .. systemName .. ".", player, "green")
- setPlayerRank(player, getRankByPlaytime(player))
- end
- savePlayerData(player)
- end
- function banPlayer(player, banningPlayer) -- banns the specified player
- if banningPlayer then
- if getPermissionLevel(banningPlayer) > getPermissionLevel(player) then
- sendMessage("You have been banned from the " .. systemName .. " by " .. banningPlayer .. ". If you think this is unfair, please message someon of the rank of supervisor or higher.", player, "red")
- sendMessage("You have succesfully banned the player " .. player .. ".", banningPlayer, "green")
- setPlayerRank(player, "Banned")
- else
- sendMessage("Your permission level isnt high enaugh to ban this player.", banningPlayer, "red")
- end
- else
- sendMessage("You have been banned from the " .. systemName .. ". If you think this is unfair, please message someon of the rank of supervisor or higher.", player, "red")
- setPlayerRank(player, "Banned")
- end
- savePlayerData(player)
- end
- function getRankByPlaytime(playerName) -- checks what rank the player would have based on their playtime (used for unbannig)
- local curHighestRank = "Beginner"
- for rankupName,rankup in pairs(rankups) do
- if playerData[playerName]["stats"][rankup["statName"]] >= rankup["condition"] and playerRanks[curHighestRank]["permissionLevel"] < playerRanks[rankupName]["permissionLevel"] then
- curHighestRank = rankupName
- end
- end
- return curHighestRank
- end
- function giveMoney(player,amount) -- gives money to the specified player
- if not table.contains(playerNames,player) then
- return
- end
- if playerData[player]["stats"]["balance"] then
- playerData[player]["stats"]["balance"] = playerData[player]["stats"]["balance"] + amount
- else
- playerData[player]["stats"]["balance"] = amount
- end
- updateScoreboard("balance", player)
- sendMessage({"You have received ", {text = amount .. "c", color = "green"}, ".\nBalance: ", {text = playerData[player]["stats"]["balance"], color = "green"}},player)
- end
- function getPlayerData(player) -- gets the data of a player
- playerData[player] = {}
- if fs.exists(programFolderName .. "/playerData/" .. player) then
- playerData[player] = readFolder(programFolderName .. "/playerData/" .. player)
- else
- registerNewPlayer(player)
- end
- end
- function registerNewPlayer(player) -- registers a new player
- lowerToExactPlayerNames[string.lower(player)] = player
- playerData[player] = standardPlayerData
- playerData[player]["lastLogin"] = os.date("%A %d %B %Y")
- savePlayerData(player)
- table.insert(playerNames,player)
- updateScoreboard("playtime", player)
- updateScoreboard("balance", player)
- sendMessage("Congratulations, you have been registered to the " .. systemName .. ", you can use it for things like teleporting, paying other players or getting stat ranklists. Type \"@help\" for more info.", player, "green")
- end
- function savePlayerData(player,saveWhat) -- saves the data of a player (if player is "all" then it saves the data of all players, if saveWhat is nil it saves the whole playerData)
- if player == "all" then
- for k,v in pairs(playerData) do
- savePlayerData(k, saveWhat)
- end
- else
- if saveWhat then
- if not playerData[player][saveWhat] then
- error(saveWhat .. "is not a existing playerData")
- end
- saveTable(programFolderName .. "/playerData/" .. player .. "/" .. saveWhat, playerData[player][saveWhat])
- else
- saveTable(programFolderName .. "/playerData/" .. player, playerData[player])
- end
- end
- end
- function setPlayerRank(player,rank) -- sets the rank of the specified player
- if not table.contains(playerNames,player) then
- error("bad argument #1 (" .. player .. " is not a viable player)")
- elseif not table.contains(rankNames,rank) then
- error("bad argument #1 (" .. rank .. " is not a viable rank)")
- end
- playerData[player]["rank"] = rank
- for k,v in pairs(playerRanks[rank]["settings"]) do
- playerData[player]["settings"][k] = v
- end
- savePlayerData(player)
- end
- function createRank(name,permissionLevel,rankSettings,rankVariables,info) -- creates a player rank (the rank settings are all the settings that will be changed when a player reaches that rank. its a table in the format {[settingName] = settingValue})
- if type(name) ~= "string" then
- error("bad argument #1 (name is supposed to be a string)")
- elseif type(permissionLevel) ~= "number" then
- error("bad argument #2 (permissionLevel is supposed to be a number)")
- end
- playerRanks[name] = {
- ["allowedChatCommands"] = allowedChatCommands,
- ["permissionLevel"] = permissionLevel,
- ["settings"] = rankSettings or {},
- ["info"] = info,
- ["rankVariables"] = rankVariables
- }
- table.insert(rankNames,name)
- end
- function getPermissionLevel(player) -- gets the permission level of a player based on their rank
- return playerRanks[playerData[player]["rank"]]["permissionLevel"] or 0
- end
- function isPermLevelHigher(playerOne,playerTwo) -- checks if the permission level of playerOne is higher than that of player two
- return getPermissionLevel(playerOne) > getPermissionLevel(playerTwo)
- end
- function createRankup(rank, statName, condition) -- creates a rankup, players will automatically rank up to that rank if the player has the specified value of the data specified in statName
- rankups = rankups or {}
- rankups[rank] =
- {["statName"] = statName,
- ["condition"] = condition
- }
- end
- function checkRankups() -- checks if any of the online players are supposed to rank up
- for k,player in pairs(playerDetector.getOnlinePlayers()) do
- checkRankup(player)
- end
- end
- function checkRankup(player) -- checks if the specified player is supposed to rank up (if so they will get ranked up)
- for rankupName,rankup in pairs(rankups) do
- if playerData[player]["stats"][rankup["statName"]] == rankup["condition"] and playerRanks[rankupName]["permissionLevel"] > playerRanks[playerData[player]["rank"]]["permissionLevel"] then
- setPlayerRank(player, rankupName)
- sendMessage("Congratulations, your rank is now " .. rankupName .. ".")
- return
- end
- end
- end
- -------------------------
- -- chat functions -------------
- function listWarps(player,sendErrorMessage)
- if getWarpCount(player) == 0 then
- sendMessage("You dont have any warps.", player, "red")
- return
- end
- local message = {{text = "\nPrivate warps:", color = "green"}}
- if sendErrorMessage then
- table.insert(message,1,{text = "\nYou dont have a warp with this name.\n", color = "red"})
- end
- for warpName, warpData in pairs(playerData[player]["warps"]) do
- table.insert(message, {text = "\n - " .. warpName, hoverEvent = hoverMessage("isPublic = " .. tostring(warpData["isPublic"] or false) .. "\nX = " .. warpData["x"] .. "\nY = " .. warpData["y"] .. "\nZ = " .. warpData["z"] .. "\nshift + click to warp"), insertion = "$@warp " .. warpName})
- end
- table.insert(message, {text = "\n\nPublic warps:", color = "green"})
- for warpName, warpData in pairs(publicWarps) do
- if not (warpData["owner"] == executingPlayer) then
- table.insert(message, {text = "\n - " .. warpName, hoverEvent = hoverMessage("Owner = " .. warpData["owner"] .. "\nX = " .. warpData["x"] .. "\nY = " .. warpData["y"] .. "\nZ = " .. warpData["z"] .. "\nshift + click to warp"), insertion = "$@warp " .. warpName})
- end
- end
- sendMessage(message, player)
- end
- function sendJoinMessages() -- sends a welcome message to all newly joined players
- for k,playerName in pairs(getJoinedPlayers()) do
- if playerData[playerName] then
- local message = {}
- if not getPlayerSetting("disableJoinMessage", playerName) then
- sendMessage({{text = "\nWelcome back to the server. For more info on the " .. systemName .. " enter @help.", hoverEvent = hoverMessage("shift + click to disable this message."), insertion = "$@changeSetting disableJoinMessage true"}}, playerName, "green")
- end
- if not getPlayerSetting("disableMailNotifications", playerName) then
- local newMailCount = 0
- for mailID,mail in pairs(playerData[playerName]["receivedMails"]) do
- if not mail["isRead"] then
- newMailCount = newMailCount + 1
- end
- end
- if newMailCount == 1 then
- sendMessage({{text = "\nYou have an unread mail.", hoverEvent = hoverMessage("shift + click to disable this message."), insertion = "$@changeSetting disableMailNotifications true"}}, playerName, "green")
- elseif newMailCount > 1 then
- sendMessage({{text = "\nYou have " .. newMailCount .. " unread mails.", hoverEvent = hoverMessage("shift + click to disable this message."), insertion = "$@changeSetting disableMailNotifications true"}}, playerName, "green")
- end
- end
- playerData[playerName]["lastLogin"] = os.date("%A %d %B %Y")
- savePlayerData(playerName)
- end
- end
- end
- function sendPatchNotes() -- sends the patchnotes if the player joined the current version for the first time
- for k,playerName in pairs(playerDetector.getOnlinePlayers()) do
- if playerData[playerName]["latestVersion"] ~= curVersion then
- if not getPlayerSetting("disablePatchMessage", playerName) then
- local pastLatestVersion = false
- for version,v in pairs(patchNotes) do
- if pastLatestVersion then
- sendMessage({{text = "\nPatch notes " .. version .. ":\n", hoverEvent = hoverMessage("shift + click to disable this message."), insertion = "$@changeSetting disablePatchMessage true", color = "green"},{text = v["notes"], hoverEvent = hoverMessage("shift + click to disable this message."), insertion = "$@changeSetting disablePatchMessage true" }}, playerName)
- end
- if v["name"] == playerData[playerName]["latestVersion"] then
- pastLatestVersion = true
- end
- end
- end
- playerData[playerName]["latestVersion"] = curVersion
- savePlayerData(playerName)
- end
- end
- end
- function isMessageDouble() -- checks if the chat event is double (if multiple chatboxes are connected to the same computer there will be multiple events for each message)
- if os.epoch("local") - (lastMessageTime or 0) < 100 and lastMessagePlayer == info2 then
- return true
- end
- lastMessageTime = os.epoch("local")
- lastMessagePlayer = info2
- end
- function createChatCommand(name,requiredPermLevl,info) -- creats a chat command, if someon types @[name] in the chat the function named chatFunctions.[name] will be executed
- if type(name) ~= "string" then
- error("bad argument #1 (name is supposed to be a string)")
- elseif type(requiredPermLevl) ~= "number" then
- error("bad argument #2 (requiredPermLevl is supposed to be a number)")
- elseif type(info) ~= "string" then
- error("bad argument #3 (info is supposed to be a string)")
- end
- chatCommands[name] = {
- ["requiredPermLevl"] = requiredPermLevl,
- ["function"] = _ENV["chatFunctions"][name],
- ["info"] = info
- }
- table.insert(chatCommandNames,name)
- lowerToExactChatCommands[string.lower(name)] = name
- end
- function getChatCommand(player,message) -- checks if the chat message was a chat command and also returns the parameters written into the chat if the message was a chat command
- if string.sub(message,1,1) == "@" then
- chatCommand = string.sub(message,2,(string.find(message," ") or 0) -1)
- chatCommand = lowerToExactChatCommands[string.lower(chatCommand)]
- else
- return
- end
- if not chatCommands[chatCommand] then
- return "This command does not exist."
- end
- if getPermissionLevel(player) < chatCommands[chatCommand]["requiredPermLevl"] then
- return "You do not have permission to use this command."
- end
- messageRest = string.sub(message,string.len(chatCommand)+3)
- local params = {}
- i = 1
- while string.len(messageRest) ~= 0 do
- params[i] = string.sub(messageRest,1,(string.find(messageRest," ") or 0) -1)
- messageRest = string.sub(messageRest,string.len(params[i])+2)
- i = i+1
- end
- if not subcommands[chatCommand] then
- return chatCommands[chatCommand]["function"], params
- end
- local subcommandName = params[1]
- if not subcommands[chatCommand][subcommandName] then
- sendAvailableSubcommands(player,chatCommand)
- return
- end
- table.remove(params,1)
- if getPermissionLevel(player) < subcommands[chatCommand][subcommandName]["requiredPermLevl"] then
- return "You do not have permission to use this subcommand."
- end
- return _ENV["subFunctions"][chatCommand][subcommandName], params
- end
- function sendMessage(message,player,color) -- sends a message to the specified player, the message can be a normal string or a table. For more info go to https://docs.advanced-peripherals.de/latest/peripherals/chat_box/#sendformattedmessage
- if not isPlayerOnline(player) then
- return false
- end
- if getPlayerSetting("disableAllMessages", player) then
- return false
- end
- table.insert(sendTheseMessages, {message = message, player = player, color = color or "white"})
- os.queueEvent("sendMessage")
- end
- function hoverMessage(message) -- returns the table used for a hoverEvent in the sendMessage function for more info also check https://docs.advanced-peripherals.de/latest/peripherals/chat_box/#sendformattedmessage
- return {action = "show_text",value = message}
- end
- function showScoreboard(data, player, page, extraText) -- shows the specified scoreboard to the specified player (in form of a chat message)
- if not scoreboards[data] then
- error("This scoreboard does not exist")
- return
- end
- local page = page or math.ceil(getScoreboardPosition(data, player)/10) -- sets the page to the page the executing player is on if the page isnt specified
- if not scoreboards[data][page*10-9] then
- sendMessage("This page does not exist", player, "red")
- return
- end
- local message = {"\n"}
- for i = 1,10 do
- position = (page-1)*10+i
- if not scoreboards[data][position] then
- break
- end
- table.insert(message, {text = "#" .. position .. " ", color = "green", hoverEvent = hoverMessage("Shift + click to get information about this player"), insertion = "$@about player " .. scoreboards[data][position]["playerName"]})
- local color = "white"
- if scoreboards[data][position]["playerName"] == player then
- color = "green"
- elseif position == 1 then
- color = "#ffe400"
- elseif position == 2 then
- color = "#c0cbe4"
- elseif position == 3 then
- color = "#c46403"
- end
- table.insert(message, {text = scoreboards[data][position]["playerName"] .. ": " .. scoreboards[data][position]["score"] .. (extraText or "") .. "\n", color = color, hoverEvent = hoverMessage("Shift + click to get information about this player"), insertion = "$@about player " .. scoreboards[data][position]["playerName"]})
- end
- sendMessage(message, player)
- end
- function combineFormattedMessages(messages) -- a function used in the help chat command to format the message because im to lazy to do it properly
- local returnTable = {}
- for k,message in pairs(messages) do
- for k2, v in pairs(message) do
- table.insert(returnTable, v)
- end
- end
- return returnTable
- end
- function getOwnersText() -- returns a text about the owner*s of the system (used for the about sytem command)
- local owners = ""
- local ownerCount = 0
- for name,data in pairs(playerData) do
- if data["rank"] == "Owner" then
- ownerCount = ownerCount + 1
- if ownerCount == 1 then
- owners = name
- else
- owners = owners .. ", " .. name
- end
- end
- end
- local ownersText = {}
- if ownerCount == 1 then
- table.insert(ownersText, {text = "Owner: ", color = "green"})
- else
- table.insert(ownersText, {text = "Owners: ", color = "green"})
- end
- if ownerCount == 0 then
- table.insert(ownersText, "None")
- else
- table.insert(ownersText, owners)
- end
- return ownersText[1], ownersText[2]
- end
- function chatFunctions.setRank(params) -- chat function to set the rank of a player
- local player = exactName(params[1])
- local rank = params[2]
- if not table.contains(playerNames,player) then
- return "param #1 is supposed to be a registered player"
- end
- if not playerRanks[rank] then
- return "param #2 is not a viable rank"
- end
- if not (isPermLevelHigher(executingPlayer,player) or executingPlayer == player) then
- return "Your permission level is not high enough to change the rank of this player"
- end
- if playerData[player]["rank"] == rank then
- return "This player already has this rank"
- end
- if getPermissionLevel(executingPlayer) <= playerRanks[rank]["permissionLevel"] then
- return "Your permission level is not high enough to grant this rank"
- end
- setPlayerRank(player,rank)
- sendMessage("Rank succesfully changed to " .. rank, executingPlayer, "green")
- end
- function chatFunctions.changeSetting(params) -- chat function to change the setting of a player
- if playerData[exactName(params[1])] then
- player = exactName(params[1])
- setting = params[2]
- value = params[3] or ""
- else
- player = executingPlayer
- setting = params[1]
- value = params[2] or ""
- end
- if not playerData[player] then
- return "This is not a registered player."
- end
- if not settings[setting] then
- if not getPlayerSetting("canChangeOtherPlayersSettings", player) then
- if playerData[player] then
- return "You do not have permission to change other players settings."
- else
- return "This setting does not exist."
- end
- end
- end
- if getPermissionLevel(player) < settings[setting]["requiredPermLevl"] then
- return "Your permission level is not high enough to change this setting."
- end
- if player ~= executingPlayer and getPermissionLevel(player) >= getPermissionLevel(executingPlayer) then
- return "Your permission level is not high enaugh to change this players settings."
- end
- if settings[setting]["type"] == "boolean" then
- if string.lower(value) == "true" then
- value = true
- elseif string.lower(value) == "false" then
- value = false
- end
- elseif settings[setting]["type"] == "number" then
- value = tonumber(value)
- end
- if type(value) ~= settings[setting]["type"] then
- return "bad argument (value has the wrong type, expected type: ".. settings[setting]["type"] ..")"
- end
- if executingPlayer == player or (isPermLevelHigher(executingPlayer,player) and getPlayerSetting("canChangeOtherPlayersSettings")) then
- changeSetting(player,setting,value)
- sendMessage("The setting was succesfully changed.", executingPlayer, "green")
- end
- end
- function chatFunctions.help(params) -- chat function that gives the executing player information about the chat commands
- local returnMessage = nil
- local getHelpOnWhat = params[1]
- if tonumber(getHelpOnWhat) or not getHelpOnWhat then -- checks if a chat command to get information on was specified
- local sendThisMessage = {}
- local page = tonumber(getHelpOnWhat) or 1
- local numberOfCommands = 0
- if (page-1)*10+1 > table.maxn(chatCommandNames) then
- sendMessage("This page does not exist.", executingPlayer, "red")
- return
- end
- if page > 1 then
- table.insert(sendThisMessage, {{text = "\n<<<< Last page", color = "blue", hoverEvent = hoverMessage("shift + click to insert"), insertion = "$@help " .. page-1}})
- end
- for k,commandName in pairs(chatCommandNames) do
- if numberOfCommands >= (page-1)*10 and numberOfCommands < page*10 then
- local info = chatCommands[commandName]["info"]
- if getPermissionLevel(executingPlayer) >= chatCommands[commandName]["requiredPermLevl"] then
- table.insert(sendThisMessage,
- {"\n",
- {text = "@" .. commandName, color = "green", insertion = "$@" .. commandName, hoverEvent = hoverMessage(info .. "\nshift + click to insert")},
- {text = " - Required permission level: ", insertion = "$@" .. commandName, hoverEvent = hoverMessage(info .. "\nshift + click to insert")},
- {text = chatCommands[commandName]["requiredPermLevl"], color = "green", insertion = "$@" .. commandName, hoverEvent = hoverMessage(info .. "\nshift + click to insert")}})
- else
- table.insert(sendThisMessage,
- {"\n",
- {text = "@" .. commandName, color = "red", hoverEvent = hoverMessage("You dont have permission to use this command.")},
- {text = " - Required permission level: ", color = "red",hoverEvent = hoverMessage("You dont have permission to use this command.")},
- {text = chatCommands[commandName]["requiredPermLevl"], color = "red", hoverEvent = hoverMessage("You dont have permission to use this command.")}})
- end
- end
- numberOfCommands = numberOfCommands + 1
- end
- if (page)*10 < table.maxn(chatCommandNames) then
- table.insert(sendThisMessage, {{text = "\nNext page >>>>", color = "blue", hoverEvent = hoverMessage("shift + click to insert"), insertion = "$@help " .. page+1}})
- end
- sendMessage(combineFormattedMessages(sendThisMessage), executingPlayer)
- return
- end
- if chatCommands[getHelpOnWhat] then
- sendMessage({"\n", {text = "@" .. getHelpOnWhat .. ": ", color = "green", insertion = "$@" .. getHelpOnWhat, hoverEvent = {action = "show_text",value = "shift + click to insert"}}, {text = chatCommands[getHelpOnWhat]["info"] .. " ", insertion = "$@" .. getHelpOnWhat, hoverEvent = {action = "show_text",value = "shift + click to insert"} }, {text = "Required permission level: " .. chatCommands[getHelpOnWhat]["requiredPermLevl"], color = "green", insertion = "$@" .. getHelpOnWhat, hoverEvent = {action = "show_text",value = "shift + click to insert"}}}, executingPlayer)
- else
- return nil
- end
- end
- function chatFunctions.timeTop(params) -- shows the executing player the playtime scoreboard
- showScoreboard("playtime", executingPlayer, params[1], " minutes")
- end
- function chatFunctions.listSettings() -- lists the settings of the executing player
- local message = {}
- local greenOrRed = {[true] = "green", [false] = "red"}
- for k,settingName in pairs(settingNames) do
- local settingValue = getPlayerSetting(settingName,executingPlayer)
- table.insert(message, "\n")
- if getPermissionLevel(executingPlayer) >= settings[settingName]["requiredPermLevl"] then
- table.insert(message, {text = settingName .. ": ", color = "green", insertion = "$@changeSetting " .. settingName .. " ", hoverEvent = hoverMessage(settings[settingName]["info"] .. "\nshift + click to change")})
- table.insert(message, {text = settingValue, insertion = "$@changeSetting " .. settingName .. " ", hoverEvent = hoverMessage(settings[settingName]["info"] .. "\nshift + click to change")})
- else
- table.insert(message, {text = settingName .. ": ", color = "red", hoverEvent = hoverMessage(settings[settingName]["info"] .. "\nYou dont have permission to change this setting.")})
- table.insert(message, {text = settingValue, hoverEvent = hoverMessage(settings[settingName]["info"] .. "\nYou dont have permission to change this setting.")})
- end
- end
- sendMessage(message, executingPlayer)
- end
- function chatFunctions.balance(params) -- tells the executing player what their balance is
- player = exactName(params[1] or executingPlayer)
- if not playerData[player] then
- return "This is not a registered player."
- end
- sendMessage({"Balance: ", {text = (playerData[player]["stats"]["balance"] or 0) .. "c", color = "green"}}, executingPlayer)
- end
- function chatFunctions.pay(params) -- pays the receiving player the specified amount and removes that amount from the balance of the executing player
- local receivingPlayer = exactName(params[1])
- local amount = tonumber(params[2])
- if not amount then
- return "You cant pay \"" .. (params[2] or "nothing") .. "\". The second parameter needs to be a number."
- end
- if not playerData[receivingPlayer] then
- return "This is not a registered player."
- end
- if receivingPlayer == executingPlayer then
- return "You cant pay yourself."
- end
- if amount > playerData[executingPlayer]["stats"]["balance"] then
- return "Your balance is too low."
- end
- if amount < 0 then
- return "You cant pay someon less then zero credits."
- end
- playerData[receivingPlayer]["stats"]["balance"] = playerData[receivingPlayer]["stats"]["balance"] + amount
- playerData[executingPlayer]["stats"]["balance"] = playerData[executingPlayer]["stats"]["balance"] - amount
- savePlayerData(receivingPlayer, "stats")
- savePlayerData(executingPlayer, "stats")
- updateScoreboard("balance", receivingPlayer)
- updateScoreboard("balance", executingPlayer)
- sendMessage({"You succesfully paid ", receivingPlayer, " ", {text = amount .. "c", color = "green"}, "\n Balance: ", {text = playerData[executingPlayer]["stats"]["balance"] .. "c", color = "green"}}, executingPlayer)
- end
- function chatFunctions.balTop(params) -- shows the executing player the balance scoreboard
- showScoreboard("balance", executingPlayer, params[1], "c")
- end
- function chatFunctions.tp(params) -- teleports the executing player to the specified coordinates
- if not params[1] then
- return "The first parameter needs to be either a player or a number."
- end
- local x,y,z = 0,0,0
- local executingPlayerPos = playerDetector.getPlayerPos(executingPlayer)
- local eX = executingPlayerPos["x"]
- local eY = executingPlayerPos["y"]
- local eZ = executingPlayerPos["z"]
- if table.contains(playerDetector.getOnlinePlayers(),exactName(params[1])) then
- if getPermissionLevel(executingPlayer) > 1 then
- local playerPos = playerDetector.getPlayerPos(exactName(params[1]))
- x = playerPos["x"]
- y = playerPos["y"]
- z = playerPos["z"]
- else
- return "You can only tp to other players at Member rank or higher."
- end
- elseif string.lower(params[1]) == "back" then
- if not playerData[executingPlayer]["lastTpPos"] then
- return "You dont have a saved last teleport position."
- end
- x = playerData[executingPlayer]["lastTpPos"]["x"]
- y = playerData[executingPlayer]["lastTpPos"]["y"]
- z = playerData[executingPlayer]["lastTpPos"]["z"]
- elseif params[1] and params[2] and params[3] then
- if string.sub(params[1],1,1) == "~" then
- x = (tonumber(string.sub(params[1],2)) or 0) + eX
- else
- x = tonumber(params[1])
- end
- if string.sub(params[2],1,1) == "~" then
- y = (tonumber(string.sub(params[2],2)) or 0) + eY
- else
- y = tonumber(params[2])
- end
- if string.sub(params[3],1,1) == "~" then
- z = (tonumber(string.sub(params[3],2)) or 0) + eZ
- else
- z = tonumber(params[3])
- end
- else
- return 'Either you enter "back" or a player name as the first parameter, else all three parameters need to be numbers (coordinates).'
- end
- if type(x) ~= "number" then
- return "The first parameter needs to be either a player or a number."
- end
- if type(y) ~= "number" then
- return "The second parameter needs to be a number."
- end
- if type(z) ~= "number" then
- return "The third parameter needs to be a number."
- end
- local droneName = getFreeDrone()
- if not droneName then
- sendMessage("There is currently no free drone available.", executingPlayer, "red")
- return
- elseif setDroneAction(droneName,"teleportPlayer",{{x=eX,y=eY,z=eZ},{x=x,y=y,z=z}},executingPlayer) then
- sendMessage("Please stand still until the teleportation is complete.", executingPlayer, "green")
- playerData[executingPlayer]["lastTpPos"] = {["x"]=eX,["y"]=eY,["z"]=eZ}
- savePlayerData(executingPlayer,"lastTpPos")
- end
- end
- function chatFunctions.warp(params)
- local warpName = ""
- for k,v in pairs(params) do
- warpName = warpName .. v
- end
- warpName = string.lower(warpName)
- if not (playerData[executingPlayer]["warps"][warpName] or publicWarps[warpName]) then
- listWarps(executingPlayer,true)
- return
- end
- local executingPlayerPos = playerDetector.getPlayerPos(executingPlayer)
- local eX = executingPlayerPos["x"]
- local eY = executingPlayerPos["y"]
- local eZ = executingPlayerPos["z"]
- local warpPos = playerData[executingPlayer]["warps"][warpName] or publicWarps[warpName]
- local droneName = getFreeDrone()
- if not droneName then
- sendMessage("There is currently no free drone available.", executingPlayer, "red")
- return
- elseif setDroneAction(droneName,"teleportPlayer",{{x=eX,y=eY,z=eZ},{x=warpPos["x"],y=warpPos["y"],z=warpPos["z"]}},executingPlayer) then
- sendMessage("Please stand still until the teleportation is complete.", executingPlayer, "green")
- playerData[executingPlayer]["lastTpPos"] = {["x"]=eX,["y"]=eY,["z"]=eZ}
- savePlayerData(executingPlayer,"lastTpPos")
- end
- end
- function chatFunctions.ban(params) -- bans the specified player
- local player = exactName(params[1])
- if not playerData[player] then
- return "This is not a registered player."
- end
- if playerData[player]["rank"] == "Banned" then
- return "This player is already banned."
- end
- banPlayer(player, executingPlayer)
- end
- function chatFunctions.unban(params) -- unbans the specifed player
- local player = exactName(params[1])
- if not playerData[player] then
- return "This is not a registered player."
- end
- if playerData[player]["rank"] ~= "Banned" then
- return "This player is not banned."
- end
- unbanPlayer(player, executingPlayer)
- end
- function chatFunctions.giveFeedback(params) -- lets the executing player five feedback about the system, the feedback will be sent to all owners as a mail
- local feedback = ""
- for k,v in pairs(params) do
- feedback = feedback .. v .. " "
- end
- for playerName, data in pairs(playerData) do
- if data["rank"] == "Owner" then
- sendMail(playerName,"Feedback from " .. executingPlayer,feedback,executingPlayer)
- end
- end
- sendMessage("Thank you for giving feedback.", executingPlayer, "green")
- end
- ------------------------------------------------
- -- subFunctions
- function sendAvailableSubcommands(player,chatCommand) -- sends the given player a message that contains all subcommands of the given chat command
- local availableSubcommands = subcommands[chatCommand]
- local message = {"Available subcommands:"}
- for subName,subData in pairs(availableSubcommands) do
- table.insert(message, {text = "\n@" .. chatCommand .. " ", insertion = "$@" .. chatCommand .. " " .. subName, hoverEvent = hoverMessage(subData["info"] .. "\nshift + click to insert")})
- table.insert(message, {text = subName, insertion = "$@" .. chatCommand .. " " .. subName, hoverEvent = hoverMessage(subData["info"] .. "\nshift + click to insert"), color = "green"})
- end
- sendMessage(message, player)
- end
- function createSubcommand(mainCommand,name,requiredPermLevl,info) -- creates a sub command (for example: @about system)
- subcommands = subcommands or {}
- subcommands[mainCommand] = subcommands[mainCommand] or {}
- subcommands[mainCommand][name] = {["info"] = info, ["requiredPermLevl"] = requiredPermLevl}
- end
- function subFunctions.about.system() -- Gives the executingPlayer player information about the system.
- local ownerOrOwners, ownerNames = getOwnersText()
- sendMessage({
- {text = "\nFirst startup date: ", color = "green"},
- firstStartupDate .. "\n",
- ownerOrOwners,
- ownerNames,
- {text = "\nRegistered player count: ", color = "green"},
- table.maxn(playerNames),
- {text = "\nConnected drone count: ", color = "green"},
- getConnectedDroneCount(),
- {text = "\nMain program pastebin link: ", color = "green", clickEvent = {action = "open_url", value = "https://pastebin.com/" .. mainProgramLink}, hoverEvent = hoverMessage("Click to open link.")},
- {text = mainProgramLink, clickEvent = {action = "open_url", value = "https://pastebin.com/" .. mainProgramLink}, hoverEvent = hoverMessage("Click to open link.")},
- {text = "\nMessage sender pastebin link: ", color = "green", clickEvent = {action = "open_url", value = "https://pastebin.com/" .. messageSenderLink}, hoverEvent = hoverMessage("Click to open link.")},
- {text = messageSenderLink, clickEvent = {action = "open_url", value = "https://pastebin.com/" .. messageSenderLink}, hoverEvent = hoverMessage("Click to open link.")},
- {text = "\nServer API pastebin link: ", color = "green", clickEvent = {action = "open_url", value = "https://pastebin.com/" .. serverAPILink}, hoverEvent = hoverMessage("Click to open link.")},
- {text = serverAPILink, clickEvent = {action = "open_url", value = "https://pastebin.com/" .. serverAPILink}, hoverEvent = hoverMessage("Click to open link.")}
- }, executingPlayer)
- end
- function subFunctions.about.ranks() -- Gives the executingPlayer player information about all ranks.
- sendMessage(rankInformationMessage, executingPlayer)
- end
- function subFunctions.about.player(params) -- Gives the executingPlayer player information the stated player.
- local playerName = exactName(params[1])
- if not playerData[playerName] then
- return "This is not a registered player."
- end
- local message = {}
- table.insert(message, {text = playerName .. "'s information:", color = "green"})
- table.insert(message, "\nRank: ")
- table.insert(message, {text = playerData[playerName]["rank"], color = "green"})
- table.insert(message, "\nlast login date: ")
- table.insert(message, {text = playerData[playerName]["lastLogin"] or "Unknown", color = "green"})
- table.insert(message, "\n\nStats: ")
- for statName,stat in pairs(playerData[playerName]["stats"]) do
- table.insert(message, "\n - " .. statName .. ": ")
- table.insert(message, {text = stat, color = "green"})
- end
- table.insert(message, "\n\nScoreboards: ")
- for statName,stat in pairs(scoreboards) do
- table.insert(message, "\n - " .. statName .. " scoreboard" .. ": ")
- table.insert(message, {text = getScoreboardPosition(statName, playerName) .. ". Place", color = "green"})
- end
- sendMessage(message, executingPlayer)
- end
- function subFunctions.mail.send(params) -- sends a mail to the player stated as the first parameter
- local receiver = params[1]
- if not playerData[receiver] then
- return "The first parameter needs to be a registered player."
- end
- local text = ""
- params[1] = nil
- for k,v in pairs(params) do
- text = text .. v .. " "
- end
- if string.len(text) < 2 then
- return "Your message is too short."
- end
- sendMail(receiver, "Mail from " .. executingPlayer, text, executingPlayer)
- sendMessage("Your mail was succesfully sent.", executingPlayer, "green")
- end
- function subFunctions.mail.list(params) -- lists all mails of the executing player
- local page = tonumber(params[1]) or 1
- local mailsPerPage = 10
- local mails = playerData[executingPlayer]["receivedMails"]
- if not mails[1] then
- return "You dont have any Mails."
- end
- if not mails[page*mailsPerPage-mailsPerPage+1] then
- return "This page does not exist."
- end
- local message = {}
- if page > 1 then
- message[1] = {text = "\n<<<< Last page", color = "blue", hoverEvent = hoverMessage("shift + click to insert"), insertion = "$@mail list " .. page-1}
- end
- for i = 1, mailsPerPage do
- local mailID = page*mailsPerPage-mailsPerPage+i
- local curMail = mails[mailID]
- if not curMail then
- break
- end
- if curMail["isRead"] then
- table.insert(message, {text = "\n" .. curMail["subject"], hoverEvent = hoverMessage("Shift + click to read"), insertion = "$@mail read " .. mailID, color = "gray"})
- else
- table.insert(message, {text = "\n" .. curMail["subject"], hoverEvent = hoverMessage("Shift + click to read"), insertion = "$@mail read " .. mailID, color = "green"})
- end
- end
- if mails[(page+1)*mailsPerPage-mailsPerPage+1] then
- table.insert(message, {text = "\nNext page >>>>", color = "blue", hoverEvent = hoverMessage("shift + click to insert"), insertion = "$@mail list " .. page+1})
- end
- sendMessage(message, executingPlayer)
- end
- function subFunctions.mail.read(params) -- lets the executing player read the mail stated as the first parameter
- local mailID = tonumber(params[1])
- local mail = playerData[executingPlayer]["receivedMails"][mailID]
- if not mail then
- return "The first parameter needs to be the ID (number) of one of your mails."
- end
- local message = {}
- message[1] = {text = "\nSender: "}
- message[2] = {text = mail["sender"], color = "green"}
- message[3] = {text = "\nDate: ",}
- message[4] = {text = mail["date"], color = "green"}
- message[5] = {text = "\nSubject: "}
- message[6] = {text = mail["subject"], color = "green"}
- message[7] = {text = "\n\n" .. mail["text"] .. "\n\n"}
- for k,v in pairs(message) do -- doing this cause if i dont, for some reason the player info shows up on every part of the message
- message[k]["hoverEvent"] = hoverMessage("")
- message[k]["insertion"] = ""
- end
- if playerData[mail["sender"]] then
- message[1]["hoverEvent"] = hoverMessage("Shift + click to get information about this player.")
- message[1]["insertion"] = "$@about player " .. mail["sender"]
- message[2]["hoverEvent"] = hoverMessage("Shift + click to get information about this player.")
- message[2]["insertion"] = "$@about player " .. mail["sender"]
- message[8] = {text = "[Respond] ", color = "green", hoverEvent = hoverMessage("Shift + click to respond"), insertion = "$@mail respond " .. mailID .. " "}
- message[9] = {text = "[Delete] ", color = "red", hoverEvent = hoverMessage("Shift + click to delete"), insertion = "$@mail delete " .. mailID}
- if playerData[executingPlayer]["receivedMails"][mailID+1] then
- message[10] = {text = "[Read next]", color = "blue", hoverEvent = hoverMessage("Shift + click to read next"), insertion = "$@mail read " .. mailID+1}
- end
- else
- message[8] = {text = "[Delete] ", color = "red", hoverEvent = hoverMessage("Shift + click to delete"), insertion = "$@mail delete " .. mailID}
- if playerData[executingPlayer]["receivedMails"][mailID+1] then
- message[9] = {text = "[Read next]", color = "blue", hoverEvent = hoverMessage("Shift + click to read next"), insertion = "$@mail read " .. mailID+1}
- end
- end
- sendMessage(message, executingPlayer)
- mail["isRead"] = true
- savePlayerData(executingPlayer,"receivedMails")
- end
- function subFunctions.mail.delete(params) -- deletes the mail with the given id
- local mailID = tonumber(params[1])
- if not playerData[executingPlayer]["receivedMails"][mailID] then
- return "The first parameter needs to be the ID (number) of one of your mails."
- end
- table.remove(playerData[executingPlayer]["receivedMails"], mailID)
- savePlayerData(executingPlayer, "receivedMails")
- sendMessage("Your mail was succesfully deleted.", executingPlayer, "green")
- end
- function subFunctions.mail.respond(params) -- sends a mail as a response to the mail with the given id
- local mailID = tonumber(params[1])
- local mail = playerData[executingPlayer]["receivedMails"][mailID]
- if not mail then
- return "The first parameter needs to be the ID (number) of one of your mails."
- end
- local text = ""
- params[1] = nil
- for k,v in pairs(params) do
- text = text .. v .. " "
- end
- if string.len(text) < 2 then
- return "Your message is too short."
- end
- sendMail(mail["sender"], "Response from " .. executingPlayer, text, executingPlayer)
- sendMessage("Your response was succesfully sent.", executingPlayer, "green")
- end
- function subFunctions.mail.clear(params) -- deletes all the read mails of a player
- if not playerData[executingPlayer]["receivedMails"][1] then
- return "You dont have any Mails."
- end
- local clearCount = 0
- repeat
- local deletedOne = false
- for mailID,mail in pairs(playerData[executingPlayer]["receivedMails"]) do
- if mail["isRead"] then
- clearCount = clearCount + 1
- table.remove(playerData[executingPlayer]["receivedMails"],mailID)
- deletedOne = true
- break
- end
- end
- until not deletedOne
- if clearCount == 0 then
- return "You dont have any read mails"
- elseif clearCount == 1 then
- savePlayerData(executingPlayer,"receivedMails")
- sendMessage("Deleted 1 read mail.",executingPlayer,"green")
- else
- savePlayerData(executingPlayer,"receivedMails")
- sendMessage("Deleted " .. clearCount .. " read mails.",executingPlayer,"green")
- end
- end
- function subFunctions.computer.requestKey() -- sends the executing player a message with a key that they can use to use the server api
- if not (playerData[executingPlayer]["computerCount"] < getMaxComputers(executingPlayer)) then
- return "You already have your maximum computer keys, to get more you need to rank up."
- end
- local key = generateKey()
- table.insert(requestedKeys,{["key"] = key, ["owner"] = executingPlayer})
- saveTable(programFolderName .. "/requestedKeys", requestedKeys)
- playerData[executingPlayer]["computerCount"] = playerData[executingPlayer]["computerCount"] + 1
- savePlayerData(executingPlayer)
- local message = {}
- table.insert(message,{text = "Your key is [", clickEvent = {action = "copy_to_clipboard", value = key}, hoverEvent = hoverMessage("Click to copy to clipboard")})
- table.insert(message,{text = key, color = "green", clickEvent = {action = "copy_to_clipboard", value = key}, hoverEvent = hoverMessage("Click to copy to clipboard")})
- table.insert(message,{text = "] please dont share this code.", clickEvent = {action = "copy_to_clipboard", value = key}, hoverEvent = hoverMessage("Click to copy to clipboard")})
- sendMessage(message, executingPlayer)
- end
- function subFunctions.computer.clearKeys() -- deletes all unused requested keys of the executing player
- if playerData[executingPlayer]["computerCount"] == 0 then
- return "You dont have any requested Keys"
- end
- local keyCount = 0
- for k,requestedKey in pairs(requestedKeys) do
- if requestedKey["owner"] == executingPlayer then
- requestedKeys[k] = nil
- keyCount = keyCount + 1
- end
- end
- if keyCount == 0 then
- return "You dont have any unused requested Keys"
- else
- playerData[executingPlayer]["computerCount"] = playerData[executingPlayer]["computerCount"] - keyCount
- savePlayerData(executingPlayer)
- saveTable(programFolderName .. "/requestedKeys", requestedKeys)
- sendMessage(keyCount .. " requested key(s) have been deleted.", executingPlayer, "green")
- end
- end
- function subFunctions.computer.list() -- lists all registered computers of a player
- if playerData[executingPlayer]["computerCount"] == 0 then
- return "You dont have any computers"
- end
- local message = {}
- local hasComputers = false
- for id, computer in pairs(getComputersOfPlayer(executingPlayer)) do
- hasComputers = true
- table.insert(message,{text = "\n- Computer ", hoverEvent = hoverMessage("Key = " .. computer["key"] .. "\nBalance = " .. computer["balance"] .. "\nShift + click to unregister"), insertion = "$@computer unregister " .. id})
- table.insert(message,{text = id, color = "green", hoverEvent = hoverMessage("Key = " .. computer["key"] .. "\nBalance = " .. computer["balance"] .. "\nShift + click to unregister"), insertion = "$@computer unregister " .. id})
- end
- if hasComputers then
- sendMessage(message, executingPlayer)
- else
- return "You dont have any registered computers"
- end
- end
- function subFunctions.computer.pay(params) -- lets the executing player pay the specifed amount to the specified computer
- local id = tonumber(params[1])
- local amount = tonumber(params[2])
- if not registeredComputers[id] then
- return "The first parameter needs to be a registered computer"
- end
- if not amount then
- return "The second parameter needs to be the amount of credits you want to pay the computer."
- end
- if amount <= 0 then
- return "The amount of credits you want to pay the computer needs to be positive."
- end
- if amount > playerData[executingPlayer]["stats"]["balance"] then
- return "Your balance is not high enaugh to pay this amount."
- end
- playerData[executingPlayer]["stats"]["balance"] = playerData[executingPlayer]["stats"]["balance"] - amount
- savePlayerData(executingPlayer,"stats")
- registeredComputers[id]["balance"] = registeredComputers[id]["balance"] + amount
- saveComputerData(id)
- sendMessage("Payment succesfull.", executingPlayer, "green")
- sendRednet(id,{["action"] = "receivedPayment", ["amount"] = amount, ["player"] = player})
- end
- function subFunctions.computer.unregister(params) -- unregisters the computer with the given id
- local id = tonumber(params[1])
- if not registeredComputers[id] then
- return "The first parameter needs to be the id of an registered computer."
- end
- if registeredComputers[id]["owner"] ~= executingPlayer then
- return "You need to be the owner of the computer you want to unregister."
- end
- unregisterComputer(id)
- end
- function subFunctions.editWarp.create(params) -- creates a warp with the given name
- local warpName = ""
- for k,v in pairs(params) do
- warpName = warpName .. v
- end
- warpName = string.lower(warpName)
- if playerData[executingPlayer]["warps"][warpName] then
- return "You already have a warp with this name."
- end
- if getMaxWarps(executingPlayer) <= getWarpCount(executingPlayer) then
- return "At your current rank you cant have more warps."
- end
- local playerPos = playerDetector.getPlayerPos(executingPlayer)
- playerData[executingPlayer]["warps"][warpName] = {["x"] = playerPos["x"], ["y"] = playerPos["y"], ["z"] = playerPos["z"]}
- savePlayerData(executingPlayer,"warps")
- sendMessage("Successfully created the warp named " .. warpName .. ".", executingPlayer, "green")
- end
- function subFunctions.editWarp.delete(params) -- deletes the warp with the given name
- local warpName = ""
- for k,v in pairs(params) do
- warpName = warpName .. v
- end
- warpName = string.lower(warpName)
- if not playerData[executingPlayer]["warps"][warpName] then
- return "You dont have a warp with this name."
- end
- if publicWarps[warpName] then
- if publicWarps[warpName]["owner"] == executingPlayer then
- publicWarps[warpName] = nil
- fs.delete(programFolderName .. "/publicWarps/" .. warpName)
- playerData[executingPlayer]["publicWarpCount"] = playerData[executingPlayer]["publicWarpCount"] - 1
- end
- end
- playerData[executingPlayer]["warps"][warpName] = nil
- savePlayerData(executingPlayer,"warps")
- sendMessage("Successfully deleted the warp named " .. warpName .. ".", executingPlayer, "green")
- end
- function subFunctions.editWarp.setPublic(params) -- Sets the warp with the given name to be public
- local warpName = ""
- for k,v in pairs(params) do
- warpName = warpName .. v
- end
- warpName = string.lower(warpName)
- local warp = playerData[executingPlayer]["warps"][warpName]
- if getRankVariable("maxPublicWarps",executingPlayer) <= playerData[executingPlayer]["publicWarpCount"] then
- return "At your current rank you cant have more public warps."
- end
- if not warp then
- return "You dont have a warp with this name."
- end
- if warp["isPublic"] then
- return "This warp is already public."
- end
- if publicWarps[warpName] then
- return "A public warp with this name already exists."
- end
- publicWarps[warpName] = {["x"] = warp["x"], ["y"] = warp["y"], ["z"] = warp["z"], ["owner"] = executingPlayer}
- saveTable(programFolderName .. "/publicWarps/" .. warpName, publicWarps[warpName])
- playerData[executingPlayer]["publicWarpCount"] = playerData[executingPlayer]["publicWarpCount"] + 1
- playerData[executingPlayer]["warps"][warpName]["isPublic"] = true
- savePlayerData(executingPlayer)
- sendMessage("Successfully set the warp named " .. warpName .. " to be public.", executingPlayer, "green")
- end
- function subFunctions.editWarp.setPrivate(params) -- Sets the warp with the given name to be private
- local warpName = ""
- for k,v in pairs(params) do
- warpName = warpName .. v
- end
- warpName = string.lower(warpName)
- local warp = playerData[executingPlayer]["warps"][warpName]
- if not warp then
- return "You dont have a warp with this name."
- end
- if not warp["isPublic"] then
- return "This warp is already private."
- end
- publicWarps[warpName] = nil
- fs.delete(programFolderName .. "/publicWarps/" .. warpName)
- playerData[executingPlayer]["publicWarpCount"] = playerData[executingPlayer]["publicWarpCount"] - 1
- playerData[executingPlayer]["warps"][warpName]["isPublic"] = false
- savePlayerData(executingPlayer)
- sendMessage("Successfully set the warp named " .. warpName .. " to be private.", executingPlayer, "green")
- end
- function subFunctions.editWarp.list() -- lists all warps of the executing player
- listWarps(executingPlayer)
- end
- ------------------------------------------------
- -- Other stuff
- function table.contains(inputTable,value) -- checks if the specified table contains a value
- for k,v in pairs(inputTable) do
- if v == value then
- return true
- end
- end
- return false
- end
- function saveTable(folderName,inputTable) -- saves the specifed table in files inside of the specified folder
- fs.delete(folderName)
- fs.makeDir(folderName)
- local file = false
- for k,v in pairs(inputTable) do
- if type(v) ~= "table" and type(v) ~= "function" then
- if not file then
- file = fs.open(folderName .. "/variables","w")
- end
- vType = type(v)
- if vType == "boolean" then
- if v then
- v = "true"
- else
- v = "false"
- end
- end
- file.writeLine(k .. string.sub(type(k),1,1) .. "=" .. string.sub(vType,1,1) .. v)
- elseif type(v) == "table" then
- saveTable(folderName .. "/" .. k,v)
- end
- end
- if file then
- file.flush()
- file.close()
- end
- end
- function readFile(fileName) -- reads a file created by the save table function and returns the saved table
- local file = fs.open(fileName,"r")
- local returnTable = {}
- if not file then
- return {}
- end
- repeat
- local curLine = file.readLine()
- local equalPos = string.find(curLine or "","=")
- if equalPos then
- local indexType = string.sub(curLine,equalPos-1,equalPos-1)
- local valueType = string.sub(curLine,equalPos+1,equalPos+1)
- local index = string.sub(curLine,1,equalPos-2)
- if indexType == "n" then
- index = tonumber(index)
- elseif indexType == "b" then
- if index == "true" then
- index = true
- else
- index = false
- end
- end
- local value = string.sub(curLine,equalPos+2)
- if valueType == "n" then
- value = tonumber(value)
- elseif valueType == "b" then
- if value == "true" then
- value = true
- else
- value = false
- end
- end
- returnTable[index] = value
- end
- until not curLine
- file.close()
- return returnTable
- end
- function readFolder(folderName)-- reads a folder created by the save table function and returns the saved table
- if not fs.isDir(folderName) then
- return {}
- end
- local returnTable = {}
- for k,v in pairs(fs.list(folderName)) do
- if fs.isDir(folderName .. "/" .. v) then
- if tonumber(v) then
- key = tonumber(v)
- elseif v == "true" or v == "false" then
- key = v == "true"
- else
- key = v
- end
- returnTable[key] = readFolder(folderName .. "/" .. v)
- else
- for k2,v2 in pairs(readFile(folderName .. "/" .. v)) do
- returnTable[k2] = v2
- end
- end
- end
- return returnTable
- end
- -------------------------------------------------
- noError, errorMessage = pcall(startup)
- if noError then
- noError, errorMessage = pcall(main)
- end
- if errorMessage ~= "Terminated" then
- print(noError)
- print(errorMessage)
- local curDate = string.gsub(os.date(),":",".")
- local file = fs.open("crashReports/" .. curDate,"w")
- file.write(errorMessage)
- file.flush()
- file.close()
- term.setTextColor(colors.red)
- print("REBOOTING")
- sendMessage("It looks like the program crashed while executing your command. The program will take 10 seconds to restart, after that please report what you did with \"@giveFeedback\".", executingPlayer, "red")
- sleep(10)
- os.reboot()
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement