Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation since 07/05/25 in all areas

  1. Source code posted via the release section of GitHub, instead of the actual git repository, as god intended.
  2. Hello together, As i recently had gotten my hands on some empty disposable vapes with surprisingly powerful processors, I had started to wonder if I could run a ClassiCube server on them. I quickly noticed however, that all the existing server software either used java or the absolutely inefficient and non-portable mess that is dotnet (even if mono is supposedly supported on armel targets but i never managed to get it to work). Despite the simplicity of the protocol, no one had apparently ever written a plain C server implementation before. So, I started writing my own server software and I have gotten to a point where most features work now while the memory and RAM footprints are kept pretty low. Here is my Codeberg repository Now, my question simply is, how can I possibly eventually get my server software added to the list of compatible server software and what are the concrete requirements that it needs to be able to fulfill to be added? Kind regards, Minki
  3. It was my decision to privatize the subreddit. A few years back, there was a movement for several subreddits to privatize as a protest against the changes Andrew mentioned. We agreed that Reddit is a burning garbage pile and never made it public since then. Nonetheless, I've updated the message to give more context.
  4. Have you heard of something called 'Tact'?
  5. i am now glod menbie
  6. Because it doesn’t, never has, and likely never will. There’s very little benefit to the relatively large complexity increase.
  7. i can relate in some parts, normally my readmes are made with a litle help of GPT because my english sucks and im not very good with words but GPTing the post is indeed funny Congrats about your first command btw :D
  8. the command itself looks really simple, all it does is it prints a wall of text, or fetches a text file and then prints what's from that text file. I think I can believe that you made it with the help of ChatGPT, but damn why do you have to let ChatGPT write the post for you? Having ChatGPT write the post is the funniest funny of the funnies I've seen today congrats bro
  9. Did you use ChatGPT to make the plugin and this post?
  10. [transmission started] You might want to create a server, and you've also read some tutorials involving the server creation guide, and how to get new players, but what you realize as a major part is, you need custom content. This custom content would mean some unique game mode, or some cool maps that distinct yourself from being a regular free build server. This is where plugins come in. What are plugins? Plugins are custom code written by you or someone else, and when loaded, will execute code to modify the server's behavior (which can include, but is not limited to, triggering additional actions upon events being called, registering a new command, registering a new TopStat (/top), modifying what the TabList looks like, etc). How are they made? Plugins are .dll files (dynamic-link libraries), aka program extensions that are compiled from source files, which in other words are human-readable text/code. Generally, these source files are written in C#, but there is also options for writing these plugins in other .NET programming languages. The DLL file is produced by a compiler, which could be the built-in server compiler on MCGalaxy (using the /Compile command), your IDE (the code editor), or the dotnet command line tools. In this tutorial, we will be looking at using the server and using Visual Studio 2019 to compile code. NOTE: MCGalaxy is targeted at .NET framework 4.0, which is an older .NET framework. Meaning, you cannot use newer syntaxes/features unless you re-target MCGalaxy and self-compile the server software, which is strongly not recommended. If you have Visual Studio 2019 Community or Professional installed on your personal computer, and given that you are hosting the server on your personal computer, the server will look and use the compiler from Visual Studio, however. Now with the two major questions answered, let's get to the process. Setting up your workspace.Before we start talking about the code structure of how plugins are written, let's get the software required set up. IDEs (Integrated development environment) are software used to write your code on, you can say they are a more advanced text editor, given we are really just editing plain text files that have a fancy file extension (in this case, the file extension is .cs). The following software are what I recommend for using to write your code on. 1) Visual Studio 2019 (Windows users only) 2) SharpDevelop (Windows users only) 3) MonoDevelop (Linux users only) 4) Visual Studio Code (Cross platform, there's also a web version but it has limited functionalities) In this tutorial, we will only be using Visual Studio 2019, so unfortunately if you would like to use the other software, you will need to ask someone else for assistance to that software. How to install Visual Studio 2019: Unfortunately, Microsoft is a poop head who decided to remove the installation packages for Visual Studio 2019 from their website. So, you will need to source the installer from somewhere else. Chocolatey happens to have sourced the installer to VS 2019, which you can find from this link: https://community.chocolatey.org/packages?q=visual%20studio%202019 You can choose any edition of Visual Studio, because there are already keys online that can be repeatedly used to give you access to any edition. (It's not like Microsoft is trying to make money off the older edition anyways, why do you think they removed it from their website?). I found the keys https://gist.github.com/ansarizafar/7234695e0837c92283144699c3f27532 Chocolatey is a package manager, which is simply software that manages the installations of other software. However, the process to install it is slightly confusing. For our case, we are not setting this up as an organization, and it is assumed that you're using Windows. So, you can open the installation page for Choloatey https://chocolatey.org/install and then select the Individual option. Then, you will open Windows Powershell in Administrator mode, copy and paste the line of code from the website (where it says Set-Execution-Policy) into Powershell, and press enter. Once Chocolatey installs, navigate back to the Chocolatey package search web page, and copy the command to the edition of Visual Studio you would like to install, and paste that into Windows Powershell, and press enter. After this finishes, you're all good to go! Installing Git Version Control / GitHub Desktop (optional) Version control is used to synchronize the copy of the code from your computer to a remote server. This allows for you and other people to collaborate together. The popular options for the remote servers are GitHub and GitLabs. You can use your IDE's built in Git features, the git command line tools, or GitHub Desktop to synchronize your code. Both the IDE Git features and GitHub Desktop features are very self explanatory and easy to navigate through, so I will save time on explaining that part. 1) We will be creating an account on either GitLab or GitHub first. 2) Once you've verified your email, we are now going to create a repository, which is basically our project. 2a) You might want to make this repository private so no one else besides you and your invited members see the code. 3) Change your working directory to the folder you want to set up your project in (cd [directory]), then use git clone [url] to set up the repository. 3a) You might be asked to authenticate yourself. If you are using GitHub, you can put in your username, but then for the password, you will need to paste in your GitHub API Token, which you can get here: https://github.com/settings/tokens. You should select repo and read:org. Make sure you SAVE THIS TOKEN TO SOMEWHERE SAFE, PREFERABLY YOUR PASSWORD MANAGER. This can allow dangerous people to access your repositories, which is not good. 3b) If you are using GitHub, it is recommended you also install this software, as it will save your time from having to paste in your token each time: https://cli.github.com/. When this is installed, all you need to do is to follow steps 1-2, but you will need to type gh auth login and then type gh repo clone. Read https://cli.github.com/manual/ for how GitHub CLI works. 4) voila! Your repository is set up. Just a few important commands to remember: 1) git add . - Adds all your changed files 2) git commit -m "your message here" - Creates a commit with "your message here" being the summary of what you've changed. You can think of commits as 3) git push - Sends your commits to the server. You will run these three commands in order each time you would like to make a change to the Git repository. PLEASE NOTE ABOUT MERGE CONFLICTS! If someone else updated the code, you will need to make sure their changes do not conflict with what you're syncing to the remote. Read https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line for more info. Creating your solution, and the CSharp project (.csproj) If you are using MonoDevelop/SharpDevelop/Visual Studio 2019, you will see an option for creating a new project/solution. You will need to click on that, and then give a name to your project, and click "Create". Then, you'll need to download the MCGalaxy_.dll file, and reference it. In Visual Studio 2019, you can reference the file by expanding the project, right click References, and click "Add Reference". Then, you'll select the location to the DLL file. What we are doing here is adding MCGalaxy's main code as a package. This will allow for the IDE to help you with auto-filling methods, and giving hints to the method parameters related to specific parts of the software. It will also allow you to compile the software. Writing the codeIf you do not know how to write code, or if you know how to write code but this is your first time touching C#, that's fine. Please take a look at the below resources available to you: https://www.w3schools.com/cs/index.php https://www.codecademy.com/learn/learn-c-sharp https://essentialcsharp.com/ The fundamental concepts covered in the two websites are very important to what we will be doing. Starting off with a plugin We will be creating an example plugin called "NotifyPlayer", which will alert players if our mascot, John ClassiCube has problem with the player because that player has "cubed" too much. Below is the file "NotifyPlayer.cs": In the above screenshot, we have done the following: 1) Defined our namespace, JohnClassiCubeLand. Namespaces often times help organize our code, and say if we have a large program/plugin we are making, then the namespace generally stays the same for all files in the program/plugin. You can also section your code to multiple namespaces, e.g. JohnClassiCubeLand.HeIsAngry, for if John ClassiCube is really mad at one of our players, and a part of the plugin (if it's multi-file) decides he wants to chop up the player. Note that most times, plugins are single-filed. The reason why this is the case is because a) This allows us to reference other plugins, and b) Many smaller plugins/projects can be compiled quickly with the built-in /compile command, which will save our time from having to locate the compiled DLL and then drag and drop it to our server's plugins folder. In this case, the code can have multiple classes in one single file, and/or have regions defined allowing us to collapse/expand different sections of the code. Example of using regions: 2) We have created the class NotifyPlayer. However, as you see in the screenshot, the class name is underlined red, and on the bottom of the IDE we see there are 3 errors. The reason why this is happening can be explained by the concept of Inheritance. Inheritance comes into play The idea of inheritance or metamorphism can be explained by giving you this analogy: Suppose we are creating a video game and we need to create two objects in the game, a car and a horse. It is agreed that both the car and the horse are vehicles, because they move, but it's just that the way they move are different. Hence, in programming, we can represent both the car and the horse as vehicles, but because the way they move are different, and the noises they make are also different, we need to have a way to define how they function. That is where interfaces and abstract classes come in! This analogy can be associated to what we are doing. There are many plugins on the server, and while not all of them do the same thing, they all need to register and unregister things upon being loaded and unloaded. Therefore, the Plugin abstract class is created for the management of the plugins, and serves as the parent class of them. Using Visual Studio, pressing Ctrl + . will bring up a context menu, and clicking Implement abstract class should fill the body of the NotifyPlayer class with the following code: public override string name => throw new System.NotImplementedException(); public override void Load(bool auto) { throw new System.NotImplementedException(); } public override void Unload(bool auto) { throw new System.NotImplementedException(); } I want you to notice two things: 1) All of these throws exceptions, which we'll replace with what is needed to make the plugin work, and 2) The exceptions all have System. in front of them. The reason why this is happening is because, at least for my file, the using statements were all deleted. In any circumstance, you can choose to include the using statement at the very top of the file, or you can choose to retrieve a method/use anything from a class by typing Namespace.Class instead. Below is how the above code was fixed. public override string name { get { return "NotifyPlayer"; } } public override string creator { get { return "75"; } } public override void Load(bool auto) { } public override void Unload(bool auto) { }Explanations to what I've done above: 1) We're using get return because we're overriding a string, and the parent class, Plugin, is expecting a getter method so it can retrieve the name of the plugin. You can also use a fat arrow lambda expression (=>) instead to do the same thing, which would be public override string name => "NotifyPlayer"; Lambdas are complex expressions that are used to create anonymous functions, and that is out of the scope of this guide. You can view more about them here: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions. Please do note that lambdas are not compilable via the standard MCGalaxy compilers. 2) I have also overridden the creator property, which allows us to put the author name (sadly it's not John ClassiCube himself). This will mention our name if the plugin fails to load or unload. I also want you to notice this property was not included in by default, as over the years properties like welcome, MCGalaxy_version, Help, and creator have become optional. These are called virtual properties/methods, which can be viewed here: https://github.com/ClassiCube/MCGalaxy/blob/86af8c8f270f9cfb90798890e829de374c9e412a/MCGalaxy/Scripting/Plugin.cs 3) Given that the properties mentioned in (2) are optional/virtual, the property name, and the methods Load and Unload are required/abstract methods, which can be seen from the above link to the Plugin.cs file. By typing the override keyword however, you will be able to see all available options to override from. Now, let's start with what we want to do with the plugin. We want to let the player know upon joining the server whether or not that John ClassiCube is mad at them, we want there to be a command for the player to check the reason(s) why John ClassiCube is mad at the player, and give the options for staff member, and even JohnClassiCube himself (who is AndrewPH in disguise, who in reality does not even exist!) to add/delete/view the reason why the player is now on John ClassiCube's not-so-good player list. Events I've updated the Load and Unload methods with the following things: public override void Load(bool auto) { OnPlayerConnectEvent.Register(HandlePlayerConnect, Priority.Low); Command.Register(new CmdJohnClassiCubeNotifications()); } public override void Unload(bool auto) { OnPlayerConnectEvent.Unregister(HandlePlayerConnect); Command.Unregister(Command.Find("JohnClassiCubeNotifications")); } private void HandlePlayerConnect(Player p) { } I've done the following: 1) I registered the OnPlayerConnectEvent. Different events, and what they do are all outlined in MCGalaxy's events folder: https://github.com/ClassiCube/MCGalaxy/tree/86af8c8f270f9cfb90798890e829de374c9e412a/MCGalaxy/Events These events allow you to perform an action when a player performs certain action, for example, running a command, sending a chat message, moving, joining another level. Hooking into events would allow you to do a certain action based on what is provided to you. In our case, we will be notifying the player of them having a notification from John ClassiCube. 2) We've registered and unregistered a Command class that we will be making soon. Registering a command is simple, all we are doing is passing a newly instantiated command to the Register method. Unregistering the command though will require us to find the loaded instance first. For this bit, I will need to give you one note: Do NOT unregister new CmdJohnClassiCubeNotifications(); This will not work because Unregister acts like removing items from a list. This newly instantiated object is not the same as the one we registered before! One way to avoid using Command.Find is to store CmdJohnClassiCubeNotifications into a static variable, and unregister that variable instead. Storing user's data Because we need to store the player's notifications, we will need some way to write each player's notifications into the server files. Thankfully, with MCGalaxy, we are given a built in feature, namely PlayerExtList and also PlayerList. These two classes allows us to retrieve data from a text file. PlayerList stores player names into a text file, with each line having one player. You can use Contains, Add, Remove to manipulate the data. Each time Add or Remove is called, you must call the Save method so it can update the data to the text file, if not it will be stored only temporarily in memory. PlayerExtList stores player names and some corresponding data into a text file, with each line being the player's name, followed by a space, and some data. You can use Contains, Update, Get, Remove to manipulate the data. Each time Update or Remove is called, you must call the Save method so it can update the data to the text file, if not it will be stored only temporarily in memory. TL;DR PlayerList retrieves data from a text file and creates a temporary List to store the data, and allows you to do read/write to the list, and you need to call Save() each time for the data to be updated to the text file. PlayerList retrieves data from a text file and creates a temporary Dictionary to store the data, and allows you to do read/write to the Key-value pairs, and you need to c all Save() each time for the data to be updated to the text file. So, now we will be setting up a PlayerExtList to store each player's notifications. public class NotifyPlayer : Plugin { public override string name { get { return "NotifyPlayer"; } } public override string creator { get { return "75"; } } public const string PATH = "plugins/NotifyPlayer/"; public const string PATH_NOTIFICATIONS = PATH + "notifications.txt"; public static PlayerExtList notificationsList; public override void Load(bool auto) { notificationsList = PlayerExtList.Load(PATH_NOTIFICATIONS); OnPlayerConnectEvent.Register(HandlePlayerConnect, Priority.Low); Command.Register(new CmdJohnClassiCubeNotifications()); } public override void Unload(bool auto) { OnPlayerConnectEvent.Unregister(HandlePlayerConnect); Command.Unregister(Command.Find("JohnClassiCubeNotifications")); } private void HandlePlayerConnect(Player p) { string data = notificationsList.Get(p.name); if (!string.IsNullOrEmpty(data)) p.Message("You have &e{0}&S notifications from John ClassiCube. &WView it immediately, or else. &T/jccn", data.Split(',').Length); } }WOW! That was a lot of changes. I will take some time to explain to you what each line does. We've created two constant variables. Constant variables are read-only, compile time variables that store data that can only be read and not modifiable during run time, and does not require a object reference (meaning it's basically static!). These two variables are the paths to our plugin's folder, and the notifications text file to store data I added a public static PlayerExtList which stores player notifications. It is public static because it needs to be accessible outside of the class without being instantiated in an object. I added one line before registering the OnPlayerConnectEvent handler, which is PlayerExtList.Load. This will retrieve the data and load it into memory, or if the text file does not exist, it will create a new empty text file and instantiate an empty list of Key-value pairs. I updated the body of HandlePlayerConnect, and it will now check for if a player has notifications and alert the player upon connect to view the notifications. We're using a extension method from MCGalaxy, namely Split, to split the string by chopping it by where there is a comma (,), and then getting the number of items there are. The notifications in the text file would then look like this: 75+ Notification1,Notification2,Notification3Custom Command Now it's the time to create our command! public class CmdJohnClassiCubeNotifications : Command2 { public override string name { get { return "JohnClassiCubeNotifications"; } } public override string shortcut { get { return "jccn"; } } public override CommandPerm[] ExtraPerms { get { return new[] { new CommandPerm(LevelPermission.Operator, "can set and view all players' notifications") }; } } public override string type { get { return CommandTypes.Information; } } public string[] GetNotifications(string player) { string data = NotifyPlayer.notificationsList.Get(player); if (string.IsNullOrEmpty(player)) return null; else return data.Split(','); } public void NotificationPrinter(Player p, string notification) { p.Message("- &f" + notification); } public override void Use(Player p, string message, CommandData data) { string[] args = message.SplitSpaces(3); if (args[0].CaselessEq("add")) { if (!CheckExtraPerm(p, data, 1)) return; if (3 > args.Length) { p.Message("You need more parameters."); return; } string matched = PlayerInfo.FindMatchesPreferOnline(p, args[1]); if (string.IsNullOrEmpty(matched)) return; List<string> notifications = new List<string>(GetNotifications(matched)); notifications.Add(args[2]); NotifyPlayer.notificationsList.Update(matched, notifications.Join(",")); NotifyPlayer.notificationsList.Save(); p.Message("Notification was added."); } else if (args[0].CaselessEq("del")) { if (!CheckExtraPerm(p, data, 1)) return; if (3 > args.Length) { p.Message("You need more parameters."); return; } string matched = PlayerInfo.FindMatchesPreferOnline(p, args[1]); if (string.IsNullOrEmpty(matched)) return; List<string> notifications = new List<string>(GetNotifications(matched)); string notification = Matcher.Find(p, args[2], out int matches, notifications, null, null, "notification"); bool removed = false; if (notification != null) { notifications.Remove(notification); NotifyPlayer.notificationsList.Update(matched, notifications.Join(",")); NotifyPlayer.notificationsList.Save(); removed = true; } p.Message("{0} rmoved the notification from {1}.", removed ? "&aSuccessfully" : "&cCould not", p.FormatNick(matched)); } else { //elvis operator string player = message.Length == 0 ? p.name : PlayerInfo.FindMatchesPreferOnline(p, message); if (string.IsNullOrEmpty(player)) return; if (player != p.name && !CheckExtraPerm(p, data, 1)) return; string[] items = GetNotifications(player); Paginator.Output(p, items, (p_, notification) => NotificationPrinter(p_, notification), "JohnClassiCubeNotifications " + player, "notifications", args.Length > 2 ? args[1] : ""); } } public override void Help(Player p) { p.Message("&T/JohnClassiCubeNotifications <player>"); p.Message("&HViews the notifications that you or another player has from John ClassiCube."); p.Message("&T/JohnClassiCubeNotifications add [player] [notification]"); p.Message("&HAdds a notification to the player"); p.Message("&T/JohnClassiCubeNotifications del [player] [notification]"); p.Message("&HDeletes a notification from the player"); } }WOAH! That's so much more stuff to take in. You might be asking, what is all this? Well, let's sort this all through one by one. A. General structure of the code All commands generally will follow the same class header, with it being Cmd[name] : Command or Cmd[name] : Command2. When I say generally, I mean it because there are abstract classes that inherit either Command or Command2, and does something specific. This can be seen with the example of EntityPropertyCmd and RoundsGameCmd, where one is used for changing properties of a bot or a player (e.g. skins and models), or RoundsGameCmd where the command inherits this for unified functionality as a RoundsGame game mode command. The general differences between Command and Command2 is this: Command requires you to override name, type, Use(Player p, string message), and Help(p). Command2 requires you to override name, type, and Help(p), with Use(Player p, string message) being optional, and also allows you to override another optional overload of Use, being Use(Player p, string message, CommandData data). The CommandData object passed provides information about where the command is ran, the coordinates of the Message Block if available, and the rank that the player ran as (in which, we don't check for the rank of the player because the player could be running the command via /sendcmd and extra permissions needs to be bypassed). We're using Command2 because we need to check for extra command permissions using the method CheckExtraPerms to check if the player has staff permissions to manipulate player data. As said earlier, typing just the override keyword will show up the properties and methods you are allowed to override... Help(Player p, string message) is an overridable method for providing additional information for the command if they player types /help command <args>, where the message parameter is <args> most others are self explanatory, so I will just leave it at that B. The Body of the Use Method, and the two helper methods The string.SplitSpaces extension method is also a feature that comes from MCGalaxy. This method allows us to split a string into a string array by chopping it up by where there is a space. It also has an overload to limit the maximum of items we can have in that array. In this case as we specified 3 as the parameter, the method will chop at space A, and space B, and then leave the rest as the 3rd item. Then, we use args[0].CaselessEq(...) to check for if the string caseless equals a certain subcomand. In which, CaselessEq is also a built in method. There is also CaselessStarts, CaselessEnds, CaselessContains for strings. CaselessContains is also available for enumerable lists. We use PlayerInfo.FindMatchesPreferOnline(Player p, string name), which is a built in MCGalaxy method to find the exact name of a player as it is stored in the server database so to find the data matching the exact name of the player, and this method returns null if no players of the name is found, which is why we return when that is the case. You can simply check if it equals null, but I just prefer using string.IsNullOrEmpty because it sounds very fancy. ...and that's mostly it Wrap up That's it! You can view the full code here: https://gist.github.com/SpicyCombo/a9034c4912d82b082378aa08a789e2f2 Now of course, that was not everything. There may be a comment or a follow up post either by me, or some other community in the community. For other developers, a few other topics you can talk about are: //reference and //pluginref, the usage of external libraries and referencing other plugins Manipulating the Database Registering/Unregistering TopStat (which is easy, someone can just post the links down to an example) Custom events (which Venk has done, and I've done so as well.. idk If I'd like to share it though) Other Tidbits1) Reading the GitHub MCGalaxy wiki, and expanding the section "Technical info (for developers)" will provide information on commands to compile and load the plugin using the built-in compiler, and API changes/breakages: https://github.com/ClassiCube/MCGalaxy/wiki/Scripting. You should check here if you see something built in not working, and you need to fix it. 2) If you are using Visual Studio 2019, it's recommended to use the hotkey Ctrl + Shift + S every now and then to save all files in your project. This will avoid surprises if your computer suddenly loses power, this is so your changes are saved before anything out of ordinary happens. Final wordsWith anything in life, the more effort you put into something, the more you will get out of it. If you ever get stuck writing code, or need some concept explained to you, feel free to ask someone in the community for help. The forums, ClassiCube Discord, server owners/developers will be here when you need it. With all that being said, I wish you all, the readers the best of luck, and hope your next project will succeed (with a lot of glory). :D 75 is your Helpful Coding Assistant (HCA) [transmission ended]
  11. GG! now you have a supposedly superior way to have people melt their brains over your avatar having too many pixels for block game!
  12. I am really disappointed how Reddit still alive now
  13. queer people are cool sorry if i have hurt anyone before
  14. While I agree with your thoughts (mostly from experiences on other ports), I think you could've handled this better without the childish tantrum. You are getting ahead of yourself and forgetting that the Vita port was developed on an emulator. There aren't many Vita owners in the community that are active and contributing.
  15. can your read the part where i said people that have no port forwarding support on their router ?????? please read the whole post before replying 🙄
  16. there are already 50 other freebuild servers, when a new server starts it gets 10 players then dies in a few days i miss ephermia anarchy
  17. ngl it does feel like
  18. Really any Minecraft skin can work on classicube, to change skins you have to click your username (which is usually in the top right), you then have the option to upload a skin file, make a skin with skinswatch, or upload a skin using a url.
  19. Hey, as from Venk's response on the ClassiCube Discord, it was my fault earlier for asking you to change the database name from XP to Levels. I confused myself with my own plugins instead. Please use this version of XP.cs and FormatPrefix.cs, which should help solve these problems. I apologize for the confusions! https://gist.github.com/SpicyCombo/7c8355522042370d0dfa291e6f8653e1
  20. ooh thats cool
  21. //reference System.Core.dll /* You will need to replace all "secretcode" values with a random code. - To reward XP from an external plugin/command, use 'Command.Find("XP").Use(p, "secretcode " + [player] + " [xp amount]");' - To make it easier/harder to level up, modify the "0.02" value accordingly. */ using System; using System.Collections.Generic; using MCGalaxy; using MCGalaxy.Commands; using MCGalaxy.SQL; namespace MCGalaxy { public class XP : Plugin { public override string creator { get { return "Venk"; } } public override string MCGalaxy_Version { get { return "1.9.3.0"; } } public override string name { get { return "XP"; } } public override void Load(bool startup) { Command.Register(new CmdXP()); InitDB(); } public override void Unload(bool shutdown) { Command.Unregister(Command.Find("XP")); } ColumnDesc[] createLevels = new ColumnDesc[] { new ColumnDesc("Name", ColumnType.VarChar, 16), new ColumnDesc("XP", ColumnType.Int32), new ColumnDesc("Level", ColumnType.Int32), }; void InitDB() { Database.CreateTable("Levels", createLevels); } } public sealed class CmdXP : Command2 { public override string name { get { return "XP"; } } public override string type { get { return "economy"; } } int GetInt(string s) { return s == "" ? 0 : int.Parse(s); } /// <summary> /// The amount of XP required until the player reaches the next level. /// </summary> int nextLevel(int userLevel) { return calculateLevel(userLevel + 1); } /// <summary> /// Calculates the amount of XP required to reach a specific level. /// </summary> int calculateLevel(int level) { // XP = (Level / 0.02) ^ 2 return (int)(Math.Pow(level / 0.02, 2) / 100); } /// <summary> /// Checks to see whether or not the player has levelled up. /// </summary> int checkLevelUp(int curXP, int number) { // level = floor((0.02 √(curXP + number)) 10) double xp = (0.02 Math.Sqrt(curXP + number)) 10; return (int)Math.Floor(xp); } /// <summary> /// Checks to see whether or not the player has levelled down. /// </summary> int checkLevelDown(int curXP, int number) { if ((curXP - number) <= 0) return 0; // level = floor((0.02 √(curXP + number)) 10) double xp = (0.02 Math.Sqrt(curXP - number)) 10; return (int)Math.Floor(xp); } public override void Use(Player p, string message, CommandData data) { p.lastCMD = "secret"; string[] args = message.SplitSpaces(); if (args[0] == "secretcode") { // To add XP: /xp secretcode [name] [xp] if (args.Length < 3) { Help(p); return; } if (PlayerInfo.FindMatchesPreferOnline(p, args[1]) == null) return; List<string[]> rows = Database.GetRows("Levels", "Name, XP, Level", "WHERE Name=@0", args[1]); int number = int.Parse(args[2]); if (rows.Count == 0) { int curXP = 0; int newLevel = checkLevelUp(curXP, number); Player pl = PlayerInfo.FindExact(args[1]); // Find person receiving XP int curLevel = 0; if (pl != null && curLevel != newLevel) pl.Message("You are now level &b" + newLevel); Database.AddRow("Levels", "Name, XP, Level", args[1], args[2], newLevel); return; } else { int curXP = int.Parse(rows[0][1]); // First row, second column int newLevel = checkLevelUp(curXP, number); Player pl = PlayerInfo.FindExact(args[1]); // Find person receiving XP int curLevel = GetInt(rows[0][2]); if (pl != null && curLevel != newLevel) p1.SetPrefix; pl.Message("You are now level &b" + newLevel); Database.UpdateRows("Levels", "XP=@1", "WHERE NAME=@0", args[1], curXP + number); // Give XP Database.UpdateRows("Levels", "Level=@1", "WHERE NAME=@0", args[1], newLevel); // Give level } } else { string pl = message.Length == 0 ? p.truename : args[0]; List<string[]> rows = Database.GetRows("Levels", "Name,XP,Level", "WHERE Name=@0", pl); int userLevel = rows.Count == 0 ? 0 : int.Parse(rows[0][2]); // User level int curXP = rows.Count == 0 ? 0 : int.Parse(rows[0][1]); // User XP if (message.Length 0 || args[0] p.name) { p.Message("&eYour Information:"); } else { if (PlayerInfo.FindMatchesPreferOnline(p, args[0]) == null) return; p.Message("&b" + args[0] + "&e's Information:"); } if (userLevel == 100) { p.Message("&5Level: &6" + userLevel + " (&bmax level)"); } else { p.Message("&5Level: &6" + userLevel + " (&b" + curXP + "xp/" + nextLevel(userLevel) + "xp&6)"); } } } public override void Help(Player p) { p.Message("&T/XP - &HShows your level and current XP needed to level up."); p.Message("&T/XP [player] - &HShows [player]'s level and current XP needed to level up."); p.Message("&T/XP [secret code] [player] [xp] - &HGives [player] XP."); } } }
  22. Thanks to everyone who helped me. <3
  23. It was not compiling because the plugin is missing the using statement for the Database class. Adding the below line at the top of the file should make it work. I've updated the GitHub Gist. using MCGalaxy.SQL;
  24. You might want to remove the lambda syntax from public override CommandPerm[] ExtraPerms => new[] { new CommandPerm(LevelPermission.Operator, "can set and view all players' notifications") }; since that won't compile on standard MCGalaxy
  25. Who is Goodly?
  26. the next manul monday is on 28/07/2025
  27. EVERYONE (YOU and ME) want the old interface back (or replace 2c2t with 2d2t in the tags)
  28. Reddit added outrageous/hostile fees for developers to utilize their APIs and smeared several app developer names (including ones who previously had great working relationships with Reddit). I'm not in the business of giving them more data to sell to AI companies, and we didn't really ever use the subreddit to begin with.
  29. Computer: Nintendo DS Lite OS: DSOrganize CPU: ARM946E-S@67MHz, and ARM7TDMI@33MHz GPU: Yes. 512k VRAM Memory: 4MB RAM Storage: 32GB microSDHC Display: Dual IPS 256x192 Touch: pressure sensitive resistive i think
  30. Arm thickness is entirely decided by the client and is based on the texture file, the website has no bearing on how the client will display your skin.
  31. No more search :D
  32. If you want to play multiplayer LAN, you will need to run your own server. https://github.com/ClassiCube/MCGalaxy?tab=readme-ov-file#setup Once it's running and you can join it, you can check the wiki for how to do basic things like create new levels. https://github.com/ClassiCube/MCGalaxy/wiki Once your server is up and running, you can import levels from other multiplayer servers by saving the level clientside (Save level... menu option), then moving that level into the server's extra/import folder and using /import [mapname] However it should be noted that if the level you saved has any kind of special gameplay or dialogue, you cannot preserve that by saving it for yourself. It can only be experienced on the server you found it on.
  33. NEVER POST ANYTHING LIKE THIS IN THIS THREAD, EVER Inane single-world replies like "cool" or "wow how did you code that" — That's what reactions are for, use them! Don't ask for tech-support with learning the C Programming Language Mope about how burnt out you are and how you have this great idea but not sure if anyone would like it — Just make things already! Do not boast about griefing, cyber-crime, infiltrating people's accounts and expect praise — We are programmers, not mouth-breathing skiddies Don't post about how you disabled HacksControl, or +hax MOTD toggles — Everyone already knows how to do this, it's a one-line change What's the point of this thread?There's a small group of ClassiCube players who "play" the game by making modified clients, bots, man-in-the-middle proxies and in general: client-side hax. Not just using off-the-shelf cheat clients, but actually writing our own that do cool and unique things. Most of the time, we clump together in a random server for a few hours and show off our recent work, but sometimes we miss something awesome. This thread is for boasting about cool cheats that you have made, sharing source code, tips, tricks, and just yapping about cheats in general. Keep the signal-to-noise ratio high, and be polite and thoughtful. Cool things people already made@Rainb0wSkeppy's bot playing Bad Apple by rapidly placing blocks (not a server-side plugin; this video is speed up about 15% to sync with the original video, filmed on Ephemera Anarchy) https://files.catbox.moe/kccj27.mp4 @jshtab's copy+paste feature in their modified client https://files.catbox.moe/ehehwc.webm Wall of Dangerous and Potentially Interested Programmers@SuperZPMax @morgana @Icee_ @AAA59 @Alland20201 @FavoritoHJS @HarmonyNetwork
  34. localbedshitter i've been working on this bot few months ago. it was written and used at the same time as SuperZPMax's raspian, obviously inspired by the previously mentioned bot. basically, a bot full of various building tools. it's written in c# and i have published its source code on github: https://github.com/danilwhale/localbedshitter this bot features some amount of building shapes and async job execution, so you can use multiple accounts for executing queued jobs.
  35. We should all have some sort of visible marker in our clients that they are cheats/botsGoing to be double-posting to my own thread, but here's a prompt towards some needed discussion, for people who are into that. We should mark our cheats as cheats, especially if we give out source code or binaries. It is polite to allow admins to kick unwelcome cheaters the moment they connect. I have been placing +hax in my AppName for a while now, similar to how plugins advertise themselves. It's not difficult to brand your cheats in this way. If your cheats are based around ClassiCube, it's as quick as adding this little snippet to Game_Load or the GameComponent OnInit function: static void OnInit(void) { String_AppendConst(&Server.AppName, " +hax"); // ... } struct IGameComponent PlusHacks_Component = {OnInit};Simpler still is changing the GAME_APP_NAME macro on src/Constants.h:17 #define GAME_APP_TITLE "ClassiCube 1.3.7 +hax"The same sort of thinking should apply to proxies and especially bots. They should support the CPE handshake if only to set their AppName to something conspicuous. Proposed CPE AppName conventionsFor cheat clients, it should be the vendor of the client, followed by +hax ClassiCube 1.3.7 modified to be a cheat client, should use the AppName: ClassiCube 1.3.7 +hax Some unique vendor which always ignored MOTD controls or HacksControl should include +hax in the name: Mugwort 1.0 +hax For bots, they should be prefixed with Bot followed by the software vendor and/or the author/controller of the bot Bots operated by SuperZPMax should have the AppName: Bot (SuperZPMax) If a bot has a vendor name like "SuperBot" and it is run by a user named Testificate, it should have the AppName Bot/SuperBot (Testificate)
  36. Maybe some people prefer in other servers or just like the custom blocks same people make
  37. In the coming months, New The30s & Co. will proudly unveil our new online store, specialising in herbal remedies. All proceeds will go directly towards support the costs of hosting and up-keeping our servers—so every purchase helps keep us online and thriving. Our herbal range includes:Herbal plants Herbal gummies Herbal brownies ...and a few other leafy surprises. All orders are sent in plain, discreet packaging for your privacy and peace of mind. Delivery will be available across Great Britain. Unfortunately, there is no shipping to Northern Ireland or outside GB at this time. Whether you're a long time player of our server or just curious about our special herbal products, this is your chance to grab something soothing whilst supporting our community. Our products will be crafted with clean, safe ingredients, free from any nasty additives—just how nature intended. ⚠️ Please note: You must be 18 years or older to purchase from the store. Running a server like ours takes resources. Instead of cluttering our space with ads or paywalls, we wanted to give you something back—something physical, funny, and maybe just a little bit cheeky. Praise liberty, New The30s & Co.
  38. Stop wasting time on poop servers and join NewBlood
  39. True, but the people who need to hear that either aren’t going to read this or can’t read.
  40. Then just be nice, that's about it :D
  41. my computer specs: cpu:intel 4004, 740 khz, 4 bits. ram:256 kb (idk the manufacturer) motherboard:aSUS isa-386C case:pegaSUS inc. model P700 power supply:electroBOOM disk:16 mb 100 kb/s os:ms SUS(because i can't afford the real ms dos) keyboard:Northgate OmniKey/101 mouse:Logictech M500 monitor:NEC MultiSync 2A speakers:(none) also,ik the cpu is too old to be compatible with my motherboard,but i just did some very simple and clean cable connections from my 4004 to the socket of my motherboard to make it actually work somewhat properly. here it is if you wanna see it:
  42. Dell Precision M4800 CPU : I7 4910MQ MXM GPU : Quadro M2000M (M2200/T2000 soon ?) Storage : 256GB SSD and 2TB HDD (maybe gonna add another 256GB SSD in the mSATA slot for a RAID 0 with the main SSD) Memory : 20GB DDR3 1600MHz (up to 32 soon) Screen : 1080p (but LVDS type motherboard, I hoped that my model was an eDP one since the dGPU can directly drive the screen without the iGPU in-between) I love it so much, but it would cost nearly a grand to do all the upgrades that i want (not cited in this post) TwT
  43. stop wasting time on classicube and go do your homework
  44. what do you mean? am i supposed to download an earlier version?
  45. Oops my bad! I’ll be sure not to 🤭
  46. I think you forgot survival mode
  47. This is such a late reply from me, apologies. dont moderate me please ;-; But goddamn it I've been waiting for this since like what? 2017. We finally fucking have it. Y a a a a y