Bukkit: How to permentately store player and class information? - java

Currently, I'm writing a RPG plugin. I've created a PlayerInfo class that stores the player's UUID, character class like knight and archer, and skills that modify a player's attributes, e.g. vitality would increase a players health, strength would increase a player's physical damage, and so on.
Here's the class so far:
public class PlayerInfo {
public String suuid;
public String charClass;
public int vitality;
public int strength;
public int defense;
public int dexterity;
public int intelligence;
public int faith;
public PlayerInfo() {
}
public PlayerInfo(String UUID, String characterClass, int VIT, int STR, int DEF, int DEX, int INT, int FAI) {
suuid = UUID;
charClass = characterClass;
vitality = VIT;
strength = STR;
defense = DEF;
dexterity = DEX;
intelligence = INT;
faith = FAI;
}
I'd like to say as well that I'm primarily a Python and Javascript programmer. I picked up Java about 2 days ago, so I apologize if my code is unhygienic. I'm still trying to understand the languages and its practices. If you would like, I'd appreciate any advice on that as well. Though, feel free to just answer my base question, as I will be posting to Code Review, too, at some point in the future.
Moving forward...
While working on the basic framework of this plugin, I've realized that the information within the PlayerInfo class is most likely not saved when the server is stopped. I thought that possibly I could write the information, using FileOutputStream and ObjectOutputStream, to a file, and store that in a config folder, and later retrieve it with the Input versions of those modules. However, I ran into an issue when trying to dynamically pick up the path of the jar file, as my server told me that my Access was denied when trying to create the folder and file.
My last issue comes when trying to use the loaded information. My plugin's commands start with /static. If I had a command named /static stats that displayed the users stats, would it be as simple as comparing the user's UUID to the one stored in the save file? For example:
Player player = (Player) sender;
String suuid = player.getUniqueId().toString();
if (character.suuid == suuid) {
// Load stats here...
}
Or is there a different way to go about doing it?
To condense my post down a bit:
How can I store Player and class information effectively, and how can I later retrieve that data to use for information and see if the current player matches a saved object? Is this what stuff like SQL is used for?

Load each player when they connect to the server into a memory (make a new PlayerInfo Object for each of them, using for example a HashMap or a List).
On player disconnect you have to save all the information into a file/database (sql included) which is being restored and loaded again on next connect of the given player.
The information is being lost when server stops, therefore you need to store it somewhere and retrieve it when you need it.
You can create a simple function to retrieve a PlayerInfo based on a HashMap
HashMap<String, PlayerInfo> allplayers = new HashMap<String, PlayerInfo>();
public PlayerInfo getPlayer(Player player){
if(allplayers.containsKey(player.getName())){
return allplayers.get(player.getName());
}else{
return null;
}
}
And to put players into a HashMap
public void addPlayer(Player player){
if(!allplayers.containsKey(player.getName())){
//Load playerInfo
PlayerInfo p = new PlayerInfo(....);
//put into hashmap
allplayers.put(player.getName(), p);
}
}
//saving PlayerInfo can be called on PlayerDisonnect/Server shutdown
public void savePlayer(Player player){
if(allplayers.containsKey(player.getName())){
PlayerInfo p = allplayers.get(player.getName());
//Save information
.....
//remove player from HashMap
allplayers.remove(player.getName());
}
} `

Okay , u can use serialization on your class , and i guess its the way cause u have just the primitives , and then u can byte write ur created serialization file to a sql database , and when u need it , u can again read it back and type cast it to ur class object . Then u can invoke an iterator to loop through the propertises and find matches for ur player with .equals method .

Related

java how to add variables to an object from a string

I have two objects that are being stored in arrays:
Game(String creator, String title, int releaseYear, int NumberSold)
Creator(String name, String gamesWorkedOn)
Game(creator) has multiple creators, so is stored as a string like this: "creator1, creator2, creator3" using commas to separate their values.
Not all games have multiple creators and there are not many different creators in total.
What I am trying to do is loop through an array of Game(games) and extract a creator variable from it and assign it to the Creator(name) and then match any games that creator is mentioned in and assign those title variables to Creator(gamesWorkedOn).
So far I have this:
public static void PopulateCreators(ArrayList<Game> games) {
//populating an array of Creators with games they have worked on
boolean match = false;
String thisCreator;
String gamesWorkedOn;
ArrayList<Creator> creatorArray = new ArrayList<Creator>();
for (int i = 0; i < games.size(); i++) {
thisCreator = games.get(i).getGameCreator();
thisCreator = thisCreator.replaceAll(", ", "\n");
Which gives me this output using a sysout:
Shigeru Miyamoto
Satoshi Tajiri
Yoshiaki Koizumi
Koichi Hayashida
Shigeru Miyamoto
My desired output would be to have something like this:
name = "Shigeru Miyamoto"
gamesWorkedOn = "game1, game2, game3"
I am looking at using a for loop but am unsure on how to implement it here.
Edit:
I forgot to mention a couple of details that I didn't think were important but I will be a bit clearer now. This is a Swing based project I am working on that takes user inputs and stores these arrays which are then saved into a JSON file that is read upon loading of the application and when a user clicks a 'save' button.
What you seem to want to do is map the creators to all the games that they have created or helped create. I'm going to start by creating a simplified version of the problem.
You have a list of:
class Game {
Set<Creator> creators;
}
which you want to convert to:
Map<Creator, Set<Game>> createdGames; // Map of creator name to games created
The first thing to do here is to find all of the unique creators to start adding to the map. This can be done with the stream API.
createdGames = gameList.stream().flatMap(game -> game.creators.stream()).distinct().collect(Collectors.toMap(Function.identity(), v -> new HashSet<>()));
Now you can just loop through all the games again and add the game to a creator's set if they took part in the creation of that game.
for(Game game : gameList) {
for(Creator creator : createdGames.keySet()) {
if(game.creators.contains(creator)) {
createdGames.get(creator).add(game);
}
}
}

Structuring My Java Application

I am planning out a Java application that will store information and pictures about items in my coin collection. For example, each coin will have its own record page. On that page there will be text fields where user-entered information will be shown, along with pictures of that particular coin. The user will have the options to add, remove, and update the records in this application.
My question is, how do I go about storing all of this data? Right now, I have most of the GUI designed and working properly. But I am unsure of the "correct" way to store and organize all the data and images for each record. Should I be pushing this data into an SQL database when the record is created and then pull from it when the user is browsing that record? Or should I create some sort of directory structure where each record has its own directory which contains the images and a text file of all the data fields?
Also, I plan to distribute this application to some of my friends so I want to make sure that everything will work correctly for them without having to install any other software (besides Java).
I am pretty new to writing these kinds of applications as I usually just write command-line scripts. Any help that anybody can provide will be greatly appreciated!
Thank you.
you can have a relational database like MySql with below basic schema.
Tables : Coins, user_entered_infos, Users
Coins - Id(PK), name, image_link
Users - Id(PK), first_name, second_name
user_entered_infos - Id(PK), coin_id(FK), user_id(FK), user_entered_info
In this way you can select for each coin you can select all the user entered information from user_entered_infos table and view it. And when user add or remove from the coin page remove it from the table.
A database may be overkill for your needs and is a whole learning-curve unto itself. You might get what you are after with some Java's built-in object serialization. Serialzation is an easy way to save your objects to a file or pass them to other applications.
Consider the following code a very simple sketch for how you might approach this problem. I'm sure you have much more detailed objects than what I am about to show you, this code's purpose is to give you an general idea for how to serialize an object and save it.
import java.io.*;
import java.util.ArrayList;
public class CoinCollectionApp {
static File collectionFile = new File("path/to/file/coin-collection.obj");
public static void main(String[] args) {
ArrayList<Coin> coins = new ArrayList<>();
Coin lincolnPenny = new Coin("Lincoln penny", 1955, "fine");
coins.add(lincolnPenny);
saveCollection(coins);
}
static void saveCollection(ArrayList<Coin> coinCollection) {
try {
FileOutputStream fout = new FileOutputStream(collectionFile);
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(coinCollection);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
static class Coin implements Serializable {
private static final long serialVersionUID = 1L;
String name;
int year;
String quality;
public Coin(String name, int year, String quality) {
this.name = name;
this.year = year;
this.quality = quality;
}
}
}

Creating a schedule of Game Objects in Java

I'm in the process of developing a stat tracker for Baseball season. I'd like to be able to load an entire schedule ino the program, making each game a relatively simple object.
Creating the game object isn't an issue. What I'm wondering is, what's the best way to implement the schedule? I have, in the team class, an ArrayList schedule.
I need a way to load the schedule info from a text file, loop through it and create a game object for each line. If that's not the best way to create 162 objects efficiently, please let me know.
Cheers
EDIT:
The game class is really very simple:
public class Game implements Serializable{
Date gameDate;
Team team;
public int runsScored, runsAllowed;
public ArrayList<BallPlayer> lineup = new ArrayList<BallPlayer>();
public ArrayList<Pitcher> pitchers = new ArrayList<Pitcher>();
public Pitcher starter;
String opponent;
boolean homeAway;
boolean result;
public Game(Team gTeam, Pitcher gStarter, String gOpponent, String homeOrAway, Date gDate){
this.team = gTeam;
this.starter = gStarter;
this.opponent = gOpponent;
if(homeOrAway.equalsIgnoreCase("home")){this.homeAway = true;}
this.runsScored = 0;
this.runsAllowed = 0;
gameDate = gDate;
}
public String getOpponent(){return opponent;}
public void setOpponent(String o){this.opponent = o;}
public boolean getHomeAway(){return homeAway;}
public void setHomeAway(String ho){if(ho.equalsIgnoreCase("home")){this.homeAway = true;}else{this.homeAway = false;}}
}
This is a pretty general question but I thought I would give you some thoughts on how I would initially approach this.
For your models, you could start with something like this:
GameVO (id, home team id (TeamVO), away team id (TeamVO), location id, schedule_id)
TeamVO (id, mascot, name, hometown, etc.)
LocationVO (id, city, state, stadium name, etc.)
PlayerVO(id, position, fname, lname, number, team_id, array_of_stat_ids)
StatVO(id, game_id, player_id, base_hits, home_runs, rbi, strike_out, etc)
ScheduleVO(id, location_id, home_team_id, away_team_id, play_time)
For the text file, I would recommend becoming comfortable with Regular Expressions. Regular expressions allow you to read in strings of data and extract data based on the patterns that you specific. Your text file will either be a fixed-length text-file, comma separated values (CSV), or some other format (first make sure you understand how your data is structured). Once you have identified the patterns that you want to extract, create your regex to match on every line and extract the appropriate values. Here is a good place to practice with your Regex
Finally, when seriallizing your objects take a look at seriallizers like XStream for .NET. I liked the Java version of this library as it allows you to quickly turn java objects into XML/json and back again.

Java OOP: Building Object Trees / Object Families

Been a while since I used Java and was wondering if this was a decent or even correct way of setting this up.
FYI, userResults refers to a JDBI variable that isn't present in the code below.
Feel free to suggest a better method, thanks.
public class Stat
{
private int current;
private int max;
public int getCurrent() {return current;}
public void setCurrent(int current) {this.current = current;}
public int getMax() {return max;}
public void setMax(int max) {this.max = max;}
}
public class Character
{
Stat hp = new Stat();
Stat mp = new Stat();
}
Character thisCharacter = new Character();
// Set the value of current & max HP according to db data.
thisCharacter.hp.setCurrent((Integer) userResults.get("hpColumn1"));
thisCharacter.hp.setMax((Integer) userResults.get("hpColumn2"));
// Print test values
System.out.println (thisCharacter.hp.Current);
System.out.println (thisCharacter.hp.Max);
Correct? Well, does it work? Then it probably is correct.
Wether or not it is a decent way to do it then the answer is "maybe". It is hard to tell from what context this code is in. But there are some things you could keep in mind though:
In which class (or object rather) are the Stat set in? Do you feel is it the responsibility of the class to do this and know what database values to get them from? If not, consider making some kind of a class that does this.
Making chained calls such as thisCharacter.hp.setCurrent(...) is a violation of principle of least knowledge. Sometimes you can't help it, but usually it leads to kludgy code. Consider having something that handles all the logic surrounding the stats. In your code you may need a HealthStatsHandler that have methods such as loadStats(), saveStats(), and mutator actions such as takeDamage(int dmg) and revive(int health).
If you have trouble figuring things out if it has the correct object design, then study up on the SOLID principles. They provide nice guidelines that any developer should follow if they want to have code that is extensible and "clean".
This is not really a tree. It is not possible two have more than one layer of children.
Usually you define an interface let's call it Node where both Stat and Character implements it and the two children of Character would have the type Node.
I would consider creating the Stat objects seperately and passing them into Character, and making the character attributes private as follows:
public class Character
{
private Stat hp;
private Stat mp;
public Stat getHp() {return hp;}
public void setHp(Stat h) {this.hp = h;}
public Stat getMp() {return mp;}
public void setMp(Stat m) {this.mp = m;}
}
// Set the value of current & max HP according to db data.
Stat hp = new Stat();
hp.setCurrent((Integer) userResults.get("hpColumn1"));
hp.setMax((Integer) userResults.get("hpColumn2"));
Character thisCharacter = new Character();
thisCharacter.setHp(hp);
// do the same for mp
One additional simple step would be to create a Character constructor that would take an hp and an mp

problems with RequestForFile() class that is using User class in Java

Okay I'll try to be direct.
I am working on a file sharing application that is based on a common Client/Serer architecture. I also have HandleClient class but that is not particularly important here.
What I wanna do is to allow users to search for a particular file that can be stored in shared folders of other users. For example, 3 users are connected with server and they all have their respective shared folders. One of them wants to do a search for a file named "Madonna" and the application should list all files containing that name and next to that file name there should be an information about user(s) that have/has a wanted file. That information can be either username or IPAddress. Here is the User class, the way it needs to be written (that's how my superiors wanted it):
import java.io.File;
import java.util.ArrayList;
import java.util.Scanner;
public class User {
public static String username;
public static String ipAddress;
public User(String username, String ipAddress) {
username = username.toLowerCase();
System.out.println(username + " " + ipAddress);
}
public static void fileList() {
Scanner userTyping = new Scanner(System.in);
String fileLocation = userTyping.nextLine();
File folder = new File(fileLocation);
File[] files = folder.listFiles();
ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < files.length; i++) {
list.add(i, files[i].toString().substring(fileLocation.length()));
System.out.println(list.get(i));
}
}
public static void main(String args[]) {
System.out.println("Insert the URL of your shared folder");
User.fileList();
}
}
This class stores attributes of a particular user (username, IPAddress) and also creates the list of files from the shared folder of that particular user. the list type is ArrayList, that's how it has to be, again, my superiors told me to.
On the other hand I need another class that is called RequestForFile(String fileName) whose purpose is to look for a certain file within ArrayLists of files from all users that are logged in at the moment of search.
This is how it should look, and this is where I especially need your help cause I get an error and I can't complete the class.
import java.util.ArrayList;
public class RequestForFile {
public RequestForFile(String fileName) {
User user = new User("Slavisha", "84.82.0.1");
ArrayList<User> listOfUsers = new ArrayList();
listOfUsers.add(user);
for (User someUser : listOfUsers) {
for (String request : User.fileList()) {
if (request.equals(fileName))
System.out.println(someUser + "has that file");
}
}
}
}
The idea is for user to look among the lists of other users and return the user(s) with a location of a wanted file.
GUI aside for now, I will get to it when I fix this problem.
Any help appreciated.
Thanks
I'm here to answer anything regarding this matter.
There are lots of problems here such as:
I don't think that this code can compile:
for (String request : User.fileList())
Because fileList() does not return anything. Then there's the question of why fileList() is static. That means that all User objects are sharing the same list. I guess that you have this becuase you are trying to test your user object from main().
I think instead you should have coded:
myUser = new User(...);
myUser.fileList()
and so fileList could not be static.
You have now explained your overall problem more clearly, but that reveals some deeper problems.
Let's start at the very top. Your request object: I think it represents one request for one user with one file definition. But it needs to go looking in the folders of many users. You add the the requesting user to a list, but what about the others. I think that this means that you need another class responsible for holding all the users.
Anyway lets have a class called UserManager.
UserMananger{
ArrayList<User> allTheUsers;
public UserManager() {
}
// methods here for adding and removing users from the list
// plus a method for doing the search
public ArrayList<FileDefinitions> findFile(request) [
// build the result
}
}
in the "line 14: for (String request : User.fileList()) {" I get this error: "void type not allowed here" and also "foreach not applicable to expression type"
You need to let User.fileList() return a List<String> and not void.
Thus, replace
public static void fileList() {
// ...
}
by
public static List<String> fileList() {
// ...
return list;
}
To learn more about basic Java programming, I can strongly recommend the Sun tutorials available in Trials Covering the Basics chapter here.
It looks like you're getting that error because the fileList() method needs to returns something that can be iterated through - which does not include void, which is what that method returns. As written, fileList is returning information to the console, which is great for your own debugging purposes, but it means that other methods can't get any of the information fileList sends to the console.
On a broader note, why is RequestForFile a separate class? If it just contains one method, you can just write it as a static method, or as a method in the class that's going to call it. Also, how will it get lists of other users? It looks like there's no way to do so as is, as you've hard-coded one user.
And looking at the answers, I'd strongly second djna's suggestion of having some class that acts as the controller/observer of all the Users.

Categories