
M_Sc_Student
Members-
Posts
8 -
Joined
-
Last visited
Everything posted by M_Sc_Student
-
Hello everyone, In my mod I have a block, with a GUI that shows a List of things. Now I want to create additional GUIS to create, delete and search List Elements. These Functions will have buttons in that GUI. I started to implement a way of changing the GUI by giving a GUIid and running some methods when I press the buttons. But I feel like there should be a better way to do it, because the class will be extremely big and not well splitted up in the different functions. Is it possible to have new GuiContainers and Containers for the Slots that will start properly on a button press? I will probably need Messages or new Tile Entities for that, but I have no idea how to continue from these ideas. Secondly, I implemented a quite simple way to scroll through my list in the GUI, because the list has a very dynamic length I only created the Slots in the Container that are visible at the time for the client. It's just to show the items, without any interaction possibilities. But I don't know if this is the right way to do it. I find it difficult to remain the dynamic of the list, while the Slots need an id of an inventory and the position in the GUI. The position can change whenever the Client scrolls and I thought the slot ID is dependant on the Client as well, to reduce communication between Server and Client. The items are saved in WorldSavedData and the Client only gets it when the player wants to see it. And that should be no big problem, since the CLient isn't able to do anything with these Item Slots. At the moment the Client looks at his local List and puts it himself in the Slots. But whenever you click on any of these slots, all the slots get empty, which isn't the worst thing that can happen. It's just a bit ugly. I tried to forbid any interaction through a Custom Slot class, but that didn't really work. I would be thankful for any advice See ya tomorrow
-
No, it wouldn't. The issue is not the get method. The issue is that you are using one data structure from two threads. But the fact that it is two threads is just an implementation detail. When not playing single player but on a dedicated server these two threads run on completely distinct machines so the static field is suddenly not shared anymore. Relying on the fact that it is shared in any way is a bad idea. I don't rely on that, though. Whenever I want to change the data structure from the Client, I would send a message to the Server and change it in the onMessage-method. In this case I only see the issue with different Threads. Normal DataStructures don't even have that problem with multiple Threads afaik, unless e.g. you don't take care of your Singletons. But maybe I'm missing something. You can, yes. But it would be more efficient if you were to only encode the data you actually need on the client directly into the ByteBuf. I think that greatly depends on the use-case. If I send the whole Data-Structure, I can view every detail on the client and can let the player "Search"&"Filter" stuff, without any other communication. Then if he wants to answer to one entry I could use a different message that only checks the relevant things etc. But I will think about it a bit more and maybe I can reduce the data for the RefreshMessage answer.
-
Okay thanks. I had to look into "loadData" to see why it says "load" instead of "get", because that made me think that it costs time to do it. It uses a FileInputStream, but only if the SavedData is null, so I guess only the very first time it takes a bit longer. Okay, so we are talking about Thread-safety. I will definitely change it. Just theoretically, would it help to make getInstance and/or some other methods synchronized ? And Why? One last question, is it recommended to use the NBTTagCompound in the DataMessage like I stated in my third code block ? Sorry if I ask too much and thanks again for your answers.
-
Hi! I saw your source code in a tutorial when I googled WorldSavedData and my load-method is actually inspired by your get-method. You are probably right about the static field being a bad choice, but let me explain one thing real quick. This data structure can get huge, depending on how many players want to trade and create offers. Its basicly a List of objects with multiple Strings, coordinates, Itemstacks and potentially a bunch of other stuff. And my first thought was "loading it from the mapstorage over and over again seems like a big overhead, if I have it accessible in the RAM already without any additional loading.". I don't doubt that you are right with your advice, but can you lead me to some examples where I can see what this static field can break in minecraft (+mods)? This stuff is great to justify decisions in the documentation, y'know? I write my master thesis about this project (not in English btw.) To the "automatic synching": I tested it again with a new world, and it's not synced - it was not a side effect on the static field, but that I used an old world and maybe I even created some data on the client. So I don't know what I did yesterday, but it's clearly not synced I just saw some "readfromNBT" in my Client-log yesterday and "writeToNBT" in the server-log, so I thought it was sending it to the client on joining, but it's gone now. But even with the static field it works very well at the moment, even on dedicated. I click on the "refresh"-Button, it sends the refreshmessage, receives the DataMessage and refreshes the List. Thank you very much for your answer.
-
Hi everyone, I recently learned about WorldSavedData for global data structures and I have some questions about it. First of all is there any serious downside to using some kind of Singleton for my WorldSavedData? I know that Singletons have some serious downsides when not handled correctly. I deleted the creation of the Singleton in the getInstance(), because we now have a load-method which creates it. public static DataManager getInstance(){ return DataManager.instance; } public static void load(World world) { if (instance == null) { instance = (DataManager)world.mapStorage.loadData(DataManager.class, IDENTIFIER); if (instance == null) { instance = new DataManager(IDENTIFIER); world.mapStorage.setData(IDENTIFIER, instance); } } } Not yet sure if I should keep the doublecheck with instance == null. The load method is called in a custom CommonProxy EventHandler. public void onWorldLoad(Load event) { DataManager.load(event.world); } Not exactly sure if I only load that on the ServerProxy. Maybe. And since the Manager is extending WorldSavedData, it has big read and write methods with a lot of Data. I learned already that the Data is automatically synced when the player joins the server (not sure yet, if its because the EventHandler is in CommonProxy). Is there any other important event when it syncs automatically, that I should know about? Is it recommended to simply use the write and read methods to send the Data to the Client when he asks for it? Btw. people said packets are used to send WorldSavedData between server and client. I assume I can simply use Messages(?) simplified example: GUI: @Override protected void actionPerformed(GuiButton button) { if(button.id == 2){ // Refresh Main.network.sendToServer(new RefreshMessage()); } } ------------------------------------------------------------- RefreshMessage: ...stuff... public class RefreshMessage implements IMessage { ...stuff... public static class ServerHandler implements IMessageHandler<RefreshMessage, IMessage> { @Override public IMessage onMessage(RefreshMessage message, MessageContext ctx) { NBTTagCompound tagCompound = new NBTTagCompound(); DataManager.getInstance().writeToNBT(tagCompound); return new DataMessage(tagCompound); } } } ------------------------------------------------------------- DataMessage: ...stuff... public class DataMessage implements IMessage { private NBTTagCompound tagCompound; public DataMessage() { } public DataMessage(NBTTagCompound c) { this.tagCompound = c; } @Override public void fromBytes(ByteBuf buf) { this.tagCompound = ByteBufUtils.readTag(buf); } @Override public void toBytes(ByteBuf buf) { ByteBufUtils.writeTag(buf, this.tagCompound); } public static class ClientHandler implements IMessageHandler<DataMessage, IMessage> { @Override public IMessage onMessage(DataMessage message, MessageContext ctx) { DataManager.getInstance().readFromNBT(message.tagCompound); DataManager.getInstance().markDirty(); return null; } } } That's the smallest Message-class I ever wrote. With my old mod where I used Tile Entities, I simply changed them on the server and then used .getWorldObj().markBlockForUpdate() to send them to the clients, which I can't use anymore. Also it wouldn't be very smart to send the Data to all clients anyway, since it would be a lot of unnecessary traffic. Thanks in advance for all answers. I will come back tomorrow or the day after.
-
Hello everyone. I think I'm asking for some tips and advice for somewhat non-trivial stuff regarding minecraft mods. So I made a Trade mod with IndustrialCraft support. You interact with other players through a GUI in which you can trade items and IC-Energy. All that stuff works quite fine. Also per dedicated Server. I'm rewriting a lot of stuff now to expand the mod. My plan is that players can create offers/demands, that will be visible in a list. So I create a DataManager Singleton that gives me access to the data. This data obviously disappears when the server is restarted. I know with tile entities you can solve that with the whole NBT Compound thing. But my structure isn't a Tile Entity. Are there other "Entity" things that are globally accessible, where I can simply use NBTs to save things and send to the Clients? If not, I could try to connect it with the Trade Block Tile Entity, but I only need one Manager, so maybe the first Trade Block is my manager. But what if the first block is destroyed? should I just copy the Manager to a different entity? What if all trade blocks are destroyed? This connection doesn't seem very smart to me. I could also try to do it in Vanilla Java and convert everything to primitives in a serializable class. Like that I can write the data in a file that is saved in the world folder I think its also not a big problem to handle the communication to the clients who are asking for the data. But here I don't know when exactly to save and load the file. In my understanding the obvious answer is "load when the world is started", "save when the world is closed", but how do I do that from a vanilla class? Right now I think I only have the init()-Events, which doesn't have a world yet. So I'm not sure if this is the best solution either. Maybe I'm just missing a keyword that I could google. I'm thankful for any post, even if it's "You are doing it wrong!", if you can explain me what. I'm here to learn. So thanks, and have a nice day everyone. TL;DR: What is the best way to make a global Data Structure in Minecraft Forge with a unique Data Manager that persists after a World/Minecraft restart? edit: Oh and I forgot to mention, that I'm using Minecraft 1.7.10. - added it to the title.