How do I deserialize the Minecraft player.dat? - java

I'm trying to make a plugin for Velocity to sync player data among different sub servers.
I want to deserialize the player.dat which is saved in the /world/playerdata/ directory, then upload ut to MySQL. When a player connect a different sub server, I'll read the data in MySQL and send the data to the targeted sub server to make the player data synchronous.

It's solved by myself.
We can use NBTCompressedStreamTools, which you need to know about NMS, like this
File playerDataFolder = new File(getDataFolder().getParentFile().getParentFile(), "world\\playerdata\\");
File playerDat = new File(playerDataFolder, player.getUniqueId().toString() + ".dat");
try {
FileInputStream inputStream = new FileInputStream(playerDat);
NBTTagCompound nbt = NBTCompressedStreamTools.a(inputStream);
}catch (Exception e) {
e.printStackTrace();
}

Related

Save a variable when the server is off

In fact I am making a Minecraft plugin and I was wondering how some plugins (without using DB) manage to keep information even when the server is off.
For example if we make a grade plugin and we create a different list or we stack the players who constitute each. When the server will shut down and restart afterwards, the lists will become empty again (as I initialized them).
So I wanted to know if anyone had any idea how to keep this information.
If a plugin want to save informations only for itself, and it don't need to make it accessible from another way (a PHP website for example), you can use YAML format.
Create the config file :
File usersFile = new File(plugin.getDataFolder(), "user-data.yml");
if(!usersFile.exists()) { // don't exist
usersFile.createNewFile();
// OR you can copy file, but the plugin should contains a default file
/*try (InputStream in = plugin.getResource("user-data.yml");
OutputStream out = new FileOutputStream(usersFile)) {
ByteStreams.copy(in, out);
} catch (Exception e) {
e.printStackTrace();
}*/
}
Load the file as Yaml content :
YamlConfiguration config = YamlConfiguration.loadConfiguration(usersFile);
Edit content :
config.set(playerUUID, myVar);
Save content :
config.save(usersFile);
Also, I suggest you to make I/O async (read & write) with scheduler.
Bonus:
If you want to make ONE config file per user, and with default config, do like that :
File oneUsersFile = new File(plugin.getDataFolder(), playerUUID + ".yml");
if(!oneUsersFile.exists()) { // don't exist
try (InputStream in = plugin.getResource("my-def-file.yml");
OutputStream out = new FileOutputStream(oneUsersFile)) {
ByteStreams.copy(in, out); // copy default to current
} catch (Exception e) {
e.printStackTrace();
}
}
YamlConfiguration userConfig = YamlConfiguration.loadConfiguration(oneUsersFile);
PS: the variable plugin is the instance of your plugin, i.e. the class which extends "JavaPlugin".
You can use PersistentDataContainers:
To read data from a player, use
PersistentDataContainer p = player.getPersistentDataContainer();
int blocksBroken = p.get(new NamespacedKey(plugin, "blocks_broken"), PersistentDataType.INTEGER); // You can also use DOUBLE, STRING, etc.
The Namespaced key refers to the name or pointer to the data being stored. The PersistentDataType refers to the type of data that is being stored, which can be any Java primitive type or String. To write data to a player, use
p.set(new NamespacedKey(plugin, "blocks_broken"), PersistentDataType.INTEGER, blocksBroken + 1);

Java - Updating / Changing serialized classes

I am creating a program for a small business. This program is meant to have smaller modules that, when developed, will be attatched to the rest of the program. It contains an "Article" and a "Category" class, which is contained in lists in a "ArticleDatabase" class.
This class is serialized and saved to a file to the harddrive.
The Register module is complete, and the "Receipt" class, is likewise contained within lists in a "RegisterDatabase" class, which is serialized and saved to a separate file.
System settings, are saved in the same manner.
However, now i am designing a Invoice module, and found out that i need to add a field to the "Article" class, and to the System data.
The register is now being used, and contains actual data that needs to be saved, and therefore i can't just change the class, since this gives an InvalidClassException when i load.
Since i know that this will be a common problem in the future too, i need some advice on how to tackle this problem.
How can i setup a system i which i can save a file from a class, and load the data into an updated or new version of this class, or should i approach this in an entirely new way?
I have tried loading the data form the old file in to a duplicate class with the needed fields addded, but reconfiguring the program to use the new files instead is a very cumbersome task, and if i have to do this every now and again, a lot of time will be wasted doing this.
The methods used for saving loading are as follows:
public void saveArticleDB() throws IOException {
// Write to disk with FileOutputStream
FileOutputStream f_out = new FileOutputStream("articles.data");
// Write object with ObjectOutputStream
ObjectOutputStream obj_out = new ObjectOutputStream(f_out);
obj_out.writeObject(MyMain.articleDB);
}
public ArticleDB loadArticleDB() throws IOException {
try {
FileInputStream f_in = new FileInputStream("articles.data");
ObjectInputStream obj_in = new ObjectInputStream(f_in);
Object obj = obj_in.readObject();
if (obj instanceof ArticleDB) {
return (ArticleDB) obj;
} else return null;
} catch (FileNotFoundException e) {
new MessageDialog("Article DB - File not found");
return null;
} catch (InvalidClassException e) {
new MessageDialog("Article DB - Class didnt match");
return null;
} catch (ClassNotFoundException e) {
new MessageDialog("Article DB - Class not found");
return null;
}
}
The classes that delivers data to the save file, implements Serializable, and thats the only code used regarding the saving and loading of the class.
This is my first attempt with serializing, saving and loading, which means i am quite new to this, and therefore know/understand very few of the concepts regarding these subjects.
Advice is much appreciated :-)

Error getting list of files from a particular directory on apache server

I am getting error on fetching the list of files from apache server using serverFileList(). Android is crashing on making of object of ApacheURLLister class. I am beginner in Android Development. Please tell me how to fetch list of files from the server?
Public List serverFileList(){
URL url;
List serverDir = null;
try {
url = new URL("http://192.168.137.1/temp/");
ApacheURLLister lister = new ApacheURLLister();
serverDir = lister.listAll(url);
}
catch (Exception e) {
e.printStackTrace();
Log.e("ERROR ON GETTING FILE","Error is " +e);
}
return serverDir;
}
You cannot just simply pull list of files on the server. You need to give name of particular file to be fetched therefore you have to write code in such a way that you specify which file is to be fetched from server. This can be resolved also through server sided scripting

Java Code to fetch data from a website and write it to a text file

I'm a student in my high school's AP Computer Science course, and as a final project I have to make a stock management app.
Part of this entails a process where every time the Stock app is opened, it gets the data (stock names, symbols, and current prices) on Yahoo! Finance, and writes it to a text file called Results.txt. Later, throughout the program, this file is repeatedly referred to in order to fetch names and prices.
I have code using Scanner to read a file, shown below, so I think I should be to refer to the data later, but I don't know how to go about getting the data and writing it to a file.
What java code can I use so that every time my front end code runs, it'll start by accessing Yahoo Finance and writing the stock data to the file for me to use?
Here is my method to read data from a file, into an ArrayList of Strings, line by line
public ArrayList<String> readFile(File f){
ArrayList<String> lines = new ArrayList<String>();
try{
a = new Scanner(f);
}catch(FileNotFoundException e){
System.out.println("File not found");
}
while(a.hasNextLine())
lines.add(a.nextLine());
return lines;
}
F will be a file passed to it, either the results file or a transaction history file, and I intend for it to return an arraylist of lines to me. Does this work well?
For more easier usage, I recommend you write serializable object into file.
I guess that you use the java-yahoo-finance to implement your job.
In a Maven project:
Add following dependency,
<dependency>
<groupId>com.yahoofinance-api</groupId>
<artifactId>YahooFinanceAPI</artifactId>
<version>1.3.0</version>
</dependency>
Fetch data from web and write into file
Stock stock = YahooFinance.get("INTC");
File file = new File(RESULT_PATH);
if (!file.exists()){
file.createNewFile();
}
MyStock myStock = new MyStock();
myStock.setName(stock.getName());
myStock.setSymbols(stock.getSymbol());
myStock.setPrice(stock.getQuote().getPrice().doubleValue());
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(file));
os.writeObject(myStock);
os.close();
Since Stock is not serializable, we create a MyStock class.
class MyStock implements Serializable{
private String name;
private String symbols;
private double price;
// setter and getter
}
read from file
MyStock stock = null;
try {
ObjectInputStream is = new ObjectInputStream(new FileInputStream(new File(RESULT_PATH)));
stock = (MyStock)is.readObject();
}catch (Exception e){
e.printStackTrace();
}
return stock;
Once you obtain the MyStock object here, you can directly handle it.

Android/Java - ClassNotFoundException for ServerSocket and Socket communication

I'm developing an app where the phone (Android program) is the client trying to send data through a socket to a Java receiver program on my computer.
So far I've been able to send simple strings or whatever, but now I'm trying to send custom objects that I create. I should note that both programs are separate Eclipse projects, and I seem to be having trouble including the same custom class "Order" on the server side (even though I have Order.java in the src folder of the server project).
Some code, for reference:
Server:
private void run() throws Exception {
ServerSocket mySS = new ServerSocket(4443);
while(true) {
Socket SS_accept = mySS.accept();
InputStream is = SS_accept.getInputStream();
ObjectInputStream ois = new ObjectInputStream(is);
Order order = (Order) ois.readObject();
if (order!=null){
java.util.List<String> items = order.getOrders();
int chair = order.getChair();
int table = order.getTable();
double price = order.getPrice();
System.out.println("Table: "+ table + " || Chair: " +chair);
for(String food: items) {
System.out.println(food);
}
System.out.println("Price: $"+price);
}
is.close();
SS_accept.close();
mySS.close();
}
And the relevant part of the client:
try {
mySocket = new Socket(serverService.ipAddress, serverService.port);
os = mySocket.getOutputStream();
oos = new ObjectOutputStream(os);
} catch(Exception e) {
Toast.makeText(PlaceOrder.this, "Error - not connected to server.", Toast.LENGTH_SHORT).show();
}
try {
oos.writeObject(order);
Toast.makeText(PlaceOrder.this, "Order Submitted!", Toast.LENGTH_SHORT).show();
refreshOrderPage(); //refresh page, allow waiter to make more orders
oos.close();
os.close();
mySocket.close();
} catch (Exception e) {
Toast.makeText(PlaceOrder.this, "Error - not connected to server.", Toast.LENGTH_SHORT).show();
}
Any ideas why I'm getting this error when trying to send objects through sockets?
Thanks.
You should probably set the serialVersionUID in the class, then build a jar with the shared classes and include that jar in both projects.
However, given you are using different JVMs (Oracle and Dalvik) there's no guarantee that the byte-level encoding is the same. You should either manually override the serialization using readObject/writeObject or use a different object encoding system that is guaranteed to be identical independent of the environment.
A stack trace would help, but almost certainly you're serializing an object on one side, sending it to the other, and the other side doesn't have a class definition with which it can reconstruct the object. In this case, it sounds like maybe your Server doesn't know about the com.foo.Order class.
You can also serialize object to some string format (json, yaml, xml) and pass it. It would much easier to maintain, I suppose.

Categories

Resources