If I remember correctly, I believe one of the rules, or maybe the faq, states something like, "This is not a java school, so make sure you know enough java." I think it's clear that you might not know enough java to accomplish the task you have set out to do (or not, I can't really say based solely on these two snippets of code that you seemed to have selected and modified), but whatever the case may be, I find this rule, or suggestion, whatever it is, to be really stupid in some cases. With that said, if you wish to save the data to the world, then with the code you have provided, I see no Event Handlers to do this with. I'm not sure if you know how to subscribe to event handlers with forge, but if you have your mod running in literally any capacity, then you should have done this with some methods in your main mod class container, otherwise how on earth is your mod gonna' work? So, I'm going to assume that you have gotten your mod to work in some capacity, if you haven't then please look into some more basic mod development, but I might also be able to help you out a little. Anyways, there is an event you can set up with one of your methods called "FMLServerStoppedEvent". I could have the wrong one, so you should probably look into the difference between "FMLServerStoppedEvent", and "FMLServerStoppingEvent", but either should work. The essential idea is to use this event with one of your methods, that way when the server stops, you can have a method called that will save all of your team data. Basically, you're going to want to write into your main mod class something that looks a little like this: @EventHandler
public void serverStopHandler(FMLServerStoppedEvent event)
{
//Code to save team data
}And, in case you haven't done this yet, you're of course going to use the FMLServerStartingEvent to load this data into your mod, so you can do something similar to the above. But if you already have a method to load the mod data, then this shouldn't be needed. Now, there are a number of mechanisms that you can use to save your data, one such method being to write the data into an nbtdata file and save it to the world folder, or writing it to some forgecaps and loading those forge caps through some other means. However, by far the simplest thing you could do would be to use a Buffer object to write and read data to and from a raw binary file saved directly to your server folder so it can be easily accessed. The first idea to accomplish this task would be to create a file that will contain your team save data if none exists, then open this file and either read your save data from it, or write your save data to it. Creating your file is as simple as importing the java.io.File class, creating a new instance of the file class with whatever name you want, for example, new File("teamsavedata.bin"), and using a FileOutputStream to write the bytes to the file, or if you need to read the bytes from the file, you should specifically use the java.io.Files class's Files.readAllBytes method. This takes a file path as one of its arguments. This can be acquired after you create an instance of java.io.File, you can simply use the toPath(), method on that instance. It is important that you use the readAllBytes method because it is not only very simple, but it returns the data in the file as a byte array, which fits the implementation of the ByteBuffer function. Now, the ByteBuffer function is what I think best for you to use to serialize (aka store as a series of numbers or bytes) the information contained within any simple class. NOTE: SIMPLE CLASS. Your Team class isn't exactly simple, but I will get into what you should do about that after I demonstrate serialization here. Now, the ByteBuffer class is very simple, but it does have some caveats that I will get into soon here. But for now, let's move on to actually serializing your data so that it can be written to your save data file. First off, you're going to want to add the methods "toBytes", and "fromBytes" into your Team class. These methods should take a ByteBuffer as an output and input respectively. That should be all they need. Now, ByteBuffers work by reading data from a byte array and spitting out the data. I think this is going to be best shown with some code, so lets imagine we have some class we want to turn into bytes, and it has a boolean, a double, and a float as it's variables. If you were to implement the above into this class, it should look something like this. public class MyClass {
float floatValue;
double doubleValue;
boolean booleanValue;
// Gets the required size of the Buffer to store our information
// This can really be replaced with some big number like 1000 if you don't want to have to deal with size serialization
// However, the above isn't exactly recommended if you care about good code
private int getSize() {
return 4 + 8 + 1; // Size of a float (4 bytes) plus the size of a double (8 bytes) plus the size of a boolean (1 byte)
}
// Takes all class values and writes them to a ByteBuffer so it can be written to a file
public ByteBuffer toBytes() {
ByteBuffer retValue = ByteBuffer.allocate(this.getSize());
retValue.putFloat(floatValue);
retValue.putDouble(doubleValue);
retValue.put(booleanValue ? 1 : 0);
}
// Takes the ByteBuffer created from the contents of the file and sets all class values accordingly
public void fromBytes(ByteBuffer buf) {
floatValue = buf.getFloat();
doubleValue = buf.getDouble();
booleanValue = buf.get() == 1 ? true : false;
}
}Now, it is important to note that the ByteBuffer function, although easy to implement, it is very primitive, and with more complex data types such as strings and lists, it can be much harder to use than the netty ByteBuf class. The ByteBuf class is practically the same as the ByteBuffer class, except it has much more versatility. You would probably want to use this class for handling your data as opposed to the ByteBuffer class. I just use the ByteBuffer class here because it is a bit easier to demonstrate and describe specifically in examples. If you want to use the ByteBuf class, you need to instantiate and instance of ByteBuf by doing something like Unpooled.buffer() if you are creating an empty buffer, and Unpooled.wrappedBuffer(fileByteArray) if you are creating a ByteBuf with a byte array already put into it. Now, I believe the ByteBuf class is intended to be used for networking serialization rather than file stream serialization, but it's just too good not to use here, so although this is a bit of an inappropriate usage of the class, things should still be fine. Simply just use ByteBuf in the same way as described for ByteBuffer above. Make sure to use the right methods when handling data. With all that said, you should be practically done here and ready to write your code to handle saving and loading your custom data. You will have to take the liberty with how you are going to handle serializing your data. I will give you some quick pointers here for how to do that. STRINGS These guys can be a bit annoying to deal with, but the best way to do it is, if you are using a ByteBuf, to write the size of the string first, then write the characters of the string to the array, which can be done with the writeCharSequence method. String are implicitly CharSequences, so you shouldn't have to worry about casting, and use Charset.defaultCharset as your second argument. When reading the string data, read the integer first, which is the size of the string, then use the string size with the readCharSequence function. You might need to instantiate a new instance of String to convert a CharSequence to a string. LISTS/ARRAYS These can be serialized much the same way as strings, with the only difference being that you aren't serializing an array of chars, but an array of specific data types. Basically, read or write the size of the list to the ByteBuf, then iterate over either the size of the list and individually serialize or deserialize each object instance individually. OTHER CLASSES If there is another class that you wish to serialize or deserialize, then if it doesn't have the built in methods for converting to or from bytes, just find a way around storing them as data by any means. If you have no choice, then you will have to build your own functions to serialize and deserialize other classes you wish to use. Some classes may be convertible into arrays that can be serialize or deserialized, such example being UUIDs, which if I remember correctly, can be converted into an array of bytes through a built in function and such an array can then be serialized. Hopefully you find this helpful enough to be able to figure out what you need to do now on your own. If you do not fully understanding something that I have mentioned here, then please use the tools at your disposal to understand it better. If you are still struggling and need some pointers or additional advice, please reply to the thread with any questions or concerns you may have. I did not go fully into detail here, but rather just provided some pointers on what to do. I will clarify again, if you do not understanding something here, do not be frustrated, as I didn't put nearly enough effort into this reply in order to fully describe the topic at hand. Remember to pray before running your code. Little know fact, but all great programmers carry a bible, a cross, and some holy water just in case they run into any errors of biblical proportion that requires divine intervention in order to solve. Please let me know if this helps or not.
By
Jackson Perr · 15 minutes ago 15 min
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.