Java download causes lag spike with really small files - java

EDIT: I've decided to remove the Minecraft tag. While this IS a Minecraft mod's code, the code I'm having trouble with has to do with functions within core Java, and not anything in Minecraft itself.
So, I posted a question last night about me writing a function of a Minecraft mod to allow us to implement our own capes and thanks to some of you I was able to get that working. I've crammed down the code from there and found a way to make it as small as possible while producing the same outcome. I've also found out how to read files directly from a download stream instead of copying the file. Great? Well, no. Now that I'm able to properly test everything and read my files, I've run into another problem. While everything works fine, it causes a lag spike of upwards to 2-4 seconds whenever my code is running. I've looked around and found issues about slow downloads, but nothing about the application completely freezing for a small period of time. Since this is run whenever a player first appears on-screen, this can get repetitive. I'm trying to fix the code and have rearranged it countless times in different ways and it just won't go away.
Here's the code. In short, it checks if the player has an official Mojang cape on their account. If they don't, then instead it runs my code to check if they have one of our custom capes, and exactly when this is run, is when the game has a lag spike. Note that if the player has a cape from Mojang my code is never run and I've tried disabling my code and just running the code that downloads their Mojang cape for use, so I know that part doesn't cause lag, it's specifically just my code. Even if they don't have a custom cape under my code it always causes lag. I can't think of why; the files are very small!
... While writing this, I decided to test something, and so I disabled the player.cloakUrl variable setting lines in my getCustomCapes method. Surely enough the lag still happened so I reckon the lag is caused by the lines that check if the player UUID matches one in the downloaded .txt files. I'm confident the lines of code that check and download from the .txt files are the culprits to the lag here. Note that I'm reading from streamed online files rather than saving them to the computer permanently since they don't need to. They're read every time this code is called and it needs to stay that way.
Without further ado here's the code.
EDIT: I've tried to add .close() commands to the streams with no success.
public static void getSkin(final GameProfile profile, EntityPlayer player) {
final Map<Type, MinecraftProfileTexture> map = Maps.<Type, MinecraftProfileTexture>newHashMap();
// (Here's where some skin-related code would be but I cut it out for easier reading,
// it has nothing to do with this situation so don't worry about that.)
if (map.containsKey(Type.CAPE))
{
MinecraftProfileTexture texture = (MinecraftProfileTexture)map.get(Type.CAPE);
player.cloakUrl = texture.getUrl();
return;
} else {
getCustomCapes(profile, player); //Commenting this fixes the lag, proving it's my code that causes it.
}
}
public static void getCustomCapes(final GameProfile profile, EntityPlayer player) {
InputStream staff;
InputStream contest;
try {
contest = new URL("https://www.dropbox.com/s/kvvkfk6emms3qg5/contest.txt?dl=1").openStream();
StringWriter contestUUIDs = new StringWriter();
IOUtils.copy(contest, contestUUIDs, StandardCharsets.UTF_8);
if (contestUUIDs.toString().contains(profile.getId().toString()))
{
player.cloakUrl = "https://www.dropbox.com/s/a4d3agty57sd4a8/contest.png?dl=1";
// Commenting out the above line doesn't seem to help any, as stated before.
return;
}
staff = new URL("https://www.dropbox.com/s/q6f4729i2zu02nz/staff.txt?dl=1").openStream();
StringWriter staffUUIDs = new StringWriter();
IOUtils.copy(staff, staffUUIDs, StandardCharsets.UTF_8);
if (staffUUIDs.toString().contains(profile.getId().toString()))
{
player.cloakUrl = "https://www.dropbox.com/s/42jn5r7fs6k5f4l/staff.png?dl=1";
// Commenting out the above line doesn't seem to help any, as stated before.
return;
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

What an old thread, huh? So, after getting a little more experience I decided to head back to this to say I've found the solution. Here's how I fixed it: Thread magic! ug_ suggested this to me a while ago it seems, but I simply didn't understand at the time. I used some methods to start a thread with special variables that set the player's properties when it's done, removing the lag. Also, I rewrote the way the cape .txts work to be a little more efficient. You may notice there's one file now, and that one controls everything instead of each list having its own file. Here's my code. First, the above get skin methods have been scraped out almost entirely, and I added a new one since creating a GameProfile sends requests to Mojang's API, causing a little bit of lag, so I made it so this thread can also generate profiles:
public static void getSkin(final GameProfile profile, EntityPlayer player) {
ThreadFetchSkins skinThread = new ThreadFetchSkins();
skinThread.start(player, profile, mc);
}
public static void getSkinFromUUIDAndName(UUID uuid, String username, EntityPlayer player) {
ThreadFetchSkins skinThread = new ThreadFetchSkins();
skinThread.start(uuid, username, player, mc);
}
And then, here's the thread.
public class ThreadFetchSkins extends Thread {
public static TreeMap<UUID, String> customCapes = new TreeMap<UUID, String>();
private EntityPlayer thePlayer;
private GameProfile theProfile;
private Minecraft mc;
private boolean createProfile = false;
private UUID id;
private String name;
public ThreadFetchSkins() {
setName("Cape data download thread");
setDaemon(true);
}
public void run() {
if(createProfile) {
theProfile = new GameProfile(id, name);
}
final Map<Type, MinecraftProfileTexture> map = Maps.<Type, MinecraftProfileTexture>newHashMap();
theProfile.getProperties().clear();
theProfile.getProperties().putAll(SkinManager.getProfileProperties(theProfile));
map.putAll(mc.sessionService.getTextures(theProfile, false));
//Removed "secure" textures grab
if (map.containsKey(Type.SKIN))
{
MinecraftProfileTexture texture = (MinecraftProfileTexture)map.get(Type.SKIN);
thePlayer.skinUrl = texture.getUrl();
String grab = texture.getMetadata("model");
// Currently returns null for steve skin
thePlayer.modelAlex = !(grab == null);
thePlayer.worldObj.obtainEntitySkin(thePlayer);
}
if (map.containsKey(Type.CAPE))
{
MinecraftProfileTexture texture = (MinecraftProfileTexture)map.get(Type.CAPE);
thePlayer.cloakUrl = texture.getUrl();
thePlayer.worldObj.obtainEntitySkin(thePlayer);
}
else {
grabCustomCapes();
}
}
public void grabCustomCapes() {
try {
URL capeDownload = new URL("https://www.dropbox.com/s/q6f4729i2zu02nz/capes.txt?dl=1");
String capeFolder = Minecraft.getMinecraftDir().getPath() + "/NFCCapes";
FileUtils.forceMkdir(new File(capeFolder));
FileUtils.copyURLToFile(capeDownload, new File(capeFolder + "/capes.txt"));
InputStream fileOS = new FileInputStream(capeFolder + "/capes.txt");
BufferedReader buf = new BufferedReader(new InputStreamReader(fileOS));
String line = buf.readLine();
customCapes.clear();
while(line != null) {
String[] data = line.split(";");
customCapes.put(UUID.fromString(data[1]), data[2]);
line = buf.readLine();
}
fileOS.close();
FileUtils.getFile(capeFolder).delete();
if(customCapes.get(theProfile.getId()) != null) {
thePlayer.cloakUrl = customCapes.get(theProfile.getId());
thePlayer.worldObj.obtainEntitySkin(thePlayer);
}
} catch (MalformedURLException e) {
e.printStackTrace();
return;
} catch (IOException e) {
e.printStackTrace();
return;
}
}
public void start(EntityPlayer player, final GameProfile profile, Minecraft minecraft) {
thePlayer = player;
theProfile = profile;
mc = minecraft;
super.start();
}
public void start(UUID uuid, String username, EntityPlayer player, Minecraft minecraft) {
id = uuid;
name = username;
thePlayer = player;
mc = minecraft;
createProfile = true;
super.start();
}
}

Related

jnotify - anything else to use instead of Thread.Sleep when file is detected

I am really needing some help on this.
I have adopted the JNOTIFY approach to detecting any new files in a directory. When the file arrives the Listener informs that a new file is in the location.
#BeforeTest(alwaysRun=true)
public void Polling() throws Exception {
ListenToNotifications.checkFolderPickup();
}
I have attempted this where I addded a call to my Setup function in order to call my setup function after the file is detected.
//snippet from Listener Class from checkFolderPickup();
public void fileCreated(int wd, String rootPath, String name) {
print("New File just created " + rootPath + " : " + name);
Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );
try {
BaseTest.setup();
} catch (Exception e) {
e.printStackTrace();
}
}
My question is //Thread.sleep(1000000) i feel this is not a safe approach and I wanted to know if there is any other approach that I could possibly use instead of a Thread.Sleep, because this function will have to be executed once each time a new file is available and the old file will be deleted eventually and so on, I cannot make the Sleep to short , it will just ignore and continue with Base.Setup()
public static void checkFolderPickup() throws Exception {
...removed other code
boolean watchSubtree = true;
int watchID = JNotify.addWatch(path, mask, watchSubtree, new Listener());
//Thread.sleep(1000000);
Thread.sleep(20000);
boolean res = JNotify.removeWatch(watchID);
if (!res) {
// invalid watch ID specified.
}
}
I basically need my framework to keep polling that directory and each time it will execute the base setup process and follow a workflow, delete the file then poll again and so on.
Can anyone please advise?
You don't need any other modules , you can use custom expected condition:##
using:
import java.io.File;
define the method inside any pageobject class:
private ExpectedCondition<Boolean> newfilepresent() {
return new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver driver) {
File f = new File("D:\\workplace");
return f.listFiles().length>1;
}
#Override
public String toString() {
return String.format("wait for new file to be present within the time specified");
}
};
}
we created a custom expected condition method now use it as:
and in code wait like:
wait.until(pageobject.filepresent());
Output:
Failed:
Passed
Once you register a watch on a directory with JNotify, it will continue to deliver events for files in that directory. You should not remove the watch if you wish to continue to receive events for that directory.

Locating and playing video files in Processing

I'm pretty new to programming using Processing, and cannot find a way to have Processing open and play a video file. I have looked at a few previous questions regarding getting Processing to play videos using Java, but every time I try the code, I get a RuntimeException: Could not load movie file x. I have tried storing the video in different locations on my computer and with different resolutions and encoding, with the same result each time. Here is the code I believe is the closest to working:
import processing.video.*;
Movie myMovie;
void setup() {
fullScreen();
myMovie = new Movie(this, "hollywood_test.mp4");
myMovie.play();
}
void draw() {
image(myMovie,0,0);
}
void movieEvent(Movie m) {
m.read();
}
If anybody knows how I can get Processing to look in the right place to find the video, or if I've made a mistake with the code, it would be greatly appreciated.
The easy way here might be to just open a fileSelector
void fileSelected(File selection) {
if (selection == null) {
println("Window was closed or the user hit cancel.");
} else {
//not sure about the loadimage for a mp4
myMovie= loadImage (selection.getAbsolutePath());
println("User selected " + selection.getAbsolutePath());
}
}
void load_image(){
selectInput("Select a file to process:", "fileSelected");
}
void setup{
fullscreen();
load_image();
myMovie.play();
}
void draw(){
load_image();
image(myMovie,0,0);
}

Store and manage (de)serialized objects properly and how to work with them after deserialisation

I want to load and render multiple objects to a gameworld using data from a class with a save/load functionality using (de)serialization, but i cant figure out how to properly reintroduce them to the program since they contain transient objects that are nessesary to render/display them.
The first time i run my program, it tries to load data from a txt file called 'Data.txt' that doesnt exist. The program creates a new Data.txt file, adds a Campfire object called 'campfire'to it and saves it. As long as the program runs it will be rendered to the screen (this part works fine). After closing the program and restarting it its supposed to check for the file, find it and load the ArrayList 'data' with the previously saved/serialized campfire object from it. Then it adds another Object of the same type to it and renders both of them. This part throws a NullPointerException in the render method of my Campfire class.
This is the Main class:
public class MainClass extends ApplicationAdapter{
public static SpriteBatch batch;
private Data data;
private Campfire campfire;
#Override
public void create () {
batch = new SpriteBatch();
data = new Data();
data.load();
campfire = new Campfire();
data.addCampfire(campfire);
System.out.println(data.getSize());
data.save();
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
data.render(batch);
batch.end();
}
The class that loads all the files:
public class Data {
private String filename;
private ArrayList<Campfire> data;
public Data() {
data = new ArrayList<Campfire>();
filename = "Data.txt";
}
public void save(){
try {
FileOutputStream file = new FileOutputStream (filename);
ObjectOutputStream out = new ObjectOutputStream (file);
out.writeObject(data);
out.close();
file.close();
}catch (IOException e) {e.printStackTrace();}
}
public void load() {
try {
FileInputStream file = new FileInputStream (filename);
ObjectInputStream in = new ObjectInputStream(file);
data = (ArrayList<Campfire>)in.readObject();
in.close();
file.close();
}
catch (IOException io) {System.out.println("File not found.");}
catch (ClassNotFoundException ex) {System.out.println("Cant load from file.");}
}
public void addCampfire(Campfire object) {
data.add(object);
}
public void render(SpriteBatch batch) {
for(int i = 0;i < data.size(); i++) {
Campfire camp = data.get(i);
camp.render(batch);
//data.get(i).render(batch);
}
}
public Campfire get(int index) {
return data.get(index);
}
public void set(int index, Campfire object) {
data.set(index, object);
}
public int getSize() {
return data.size();
}
And this is the class that throws the NullPointerException in render():
public class Campfire implements Serializable{
private transient Texture img;
private int id;
public Campfire() {
img = new Texture("campfire.png");
}
public void render(SpriteBatch batch) {
batch.draw(img, 200,200, 2000,2000);
}
The reason for this is that the Texture 'img' is nonexistent since i need to use the transient keyword with it and therefore it will not be saved/loaded to/from the data file.
i need a different way to create objects based on the array list i am loading from. I cant work with the objects in the arrayList because they cant be rendered (the transient keyword has to be assigned to the Texture() object - its not serializable). I have watched plenty of tutorials and read a good amount on articles about this topic, but i cant find one that mentions how i can reintroduce the object so i can make use of its functions that rely on not (de)serializable parts of it.
So heres my question:
Is there a better way than my attempt (creating the object again and then assigning the deserialized values to it? I have no clue how to properly load and work with the 'data' ArrayList after the deserialization process and i am thankful for every advice on how to reintroduce them to the program.
Thanks in advance,
M
I would recommend not using java serialization for this. It can have advantages in terms of the size of its serialized format, but in my experience it is a little bit of a pain to work with. You have encountered this pain, because you cannot serialize that Texture object because it is not Serializable. You avoided the issue by marking it as transient, which is a mistake. There are probably workarounds for working with objects that you do not own - registering some handler, but tbh I do not know the details because I avoid it.
Instead, go for a nice friendly format like json. This will mean that your serialized data file will be a bit bigger, but, you can open it up and read it and see what you have saved.
And... libgdx comes with some tools for it. See their wiki page on usage here
There are alternatives - like googles gson library as well, but why not just stick with libgdx's tools - I have found them to be pretty solid.
Just an extra warning - if you are using some sort of code obfuscation/minimization tool in Android, you will need to configure that to not rename any object that you serialize, because it does rely on the package and object names for deserialization. It is also something to be aware of if you save a game state - then change the names/packages of your objects and then try to load that game state.

How to set a single entity invisible to a player?

After much research and much time wasted, I still can't find out how to hide an entity to a player.
What I'm trying to do is create a disguise command. I've now gotten everything worked out, except the issue is that the entity is still visible, and once stationary you can't interact with anything because the mob's hitbox is in the way. I want to hide the entity from the player so that you can do this. I know with players you can use Player#hidePlayer(), but this does not work with entities. I've tried using solutions such as this, but it gave an error while following the example. (And many things were depreciated, so I assumed it was out of date. I'm using Spigot 1.11.2). Any help would be very much appreciated.
PS: If you're wondering why I don't just use an already made plugin, it's because none of them work from what I've found.
To accomplish what you want, you must use packets to cancel what the player sees.
I strongly recommend ProtocolLib, have it in your server and use in your plugin.
Bearing that in mind, Bukkit user Comphenix has developed a class for protocollib to hide entities. You can find it in github.
Comphenix also provides an example of usage, as you can see below:
public class ExampleMod extends JavaPlugin {
private EntityHider entityHider;
private static final int TICKS_PER_SECOND = 20;
#Override
public void onEnable() {
entityHider = new EntityHider(this, Policy.BLACKLIST);
}
#Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (sender instanceof Player) {
final Player player = (Player) sender;
final Sheep sheep = player.getWorld().spawn(player.getLocation(), Sheep.class);
// Show a particular entity
entityHider.toggleEntity(player, sheep);
getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
#Override
public void run() {
entityHider.toggleEntity(player, sheep);
}
}, 10 * TICKS_PER_SECOND);
}
return true;
}
}

Problem understanding Serializable

just started using the Serializable-thingy, I want to save a couple of lists and some other objects, but I can't seem to get some things right.
I have some JLists with their own "DefaultListModel" that I use to sort things in the list, I call the class SortModel, when I run the program I do this:
SortModel sortModel = new SortModel();
JList jList = new JList(sortModel);
Then later when the program runs, objects are added and sorted according to the specified needs, now, when I save the lists and load them again, they're empty.
I also save a object of a class that holds the background for the program (user chooses one themself), after saving it I need to add it again to the program (the object, background is stored in it), I need to add it to the program again not only load it "as it where", plus I have some objects that I added on that object with their own listeners. After I somehow succeeded in loading it, the objects are there but I can't use them, so I figure listeners don't get saved?
* explaining edit
The class that is the program extends JFrame, nothing funny about that I think.
The "background obect" (call it map) extends JComponent, I add this to (let's call it program for now...) the program and it pops up with the image which it holds. Onto this map I then add objects that also extends JComponent (call them dots), the dots are assigned their own listeners before they're added, the listeners might not be "real" listeners, but they act the same way, they're "MouseAdapter" does that makes any difference?.
/explaining edit *
* code edit *
code for saving:
FileOutputStream fOut = new FileOutputStream("testFile.mpd");
ObjectOutputStream outSt = new ObjectOutputStream(fOut);
outSt.writeObject(savedMap);
"testFile.mpd" is what it sounds like, I'm quite sure the .mpd shouldn't matter, you can make up your own formats, right? :) (main-class is called Mappedoodle, .mpd sounds reasonable, no?)
"savedMap" is an object of said Mappedoodle and holds all lists and other information needed to be saved.
code for loading:
FileInputStream fIn = new FileInputStream("testFile.mpd");
ObjectInputStream inSt = new ObjectInputStream(fIn);
Mappedoodle openedMap = (Mappedoodle)inSt.readObject();
The information in openedMap is used (well... it should be...) to overwrite certain things in the program.
* /code edit *
Adding everything back onto this object, even adding everything back into the lists wouldn't be so hard since that's just some more lists and a few loops, but I feel like I just don't really get Serializable ^^ so, someone care to try to explain why not everything gets saved? And if it is, why I can't access it? But if I can, how? :)
I don't know what more code should be relevant, please tell me what more information you would need to help me solve this, pasting the whole program would be really messy since it's 11 classes and quite a few lines.
Thanks <3
The code you must show us must be sufficient to demonstrate your error, and I unfortunately must state that yours doesn't. For instance if I use your code in a very simple example (something I recommend that you do), you'll see that it works. My test code:
Mappedoodle.java
import java.io.Serializable;
public class Mappedoodle implements Serializable {
private static final long serialVersionUID = -1760231235147491826L;
private String text;
private int value;
public Mappedoodle(String text, int value) {
this.text = text;
this.value = value;
}
public String getText() {
return text;
}
public int getValue() {
return value;
}
#Override
public String toString() {
return text + ", " + value;
}
}
MappedoodleSerialize.java
import java.io.*;
public class MappedoodleSerialize {
public static void main(String[] args) {
Mappedoodle savedMap = new Mappedoodle("Fubar", 200);
FileOutputStream fOut;
try {
// your code below
fOut = new FileOutputStream("testFile.mpd");
ObjectOutputStream outSt = new ObjectOutputStream(fOut);
outSt.writeObject(savedMap);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
MappedoodleDeSerialize.java
import java.io.*;
public class MappedoodleDeSerialize {
public static void main(String[] args) {
try {
// your code below
FileInputStream fIn = new FileInputStream("testFile.mpd");
ObjectInputStream inSt = new ObjectInputStream(fIn);
Mappedoodle openedMap = (Mappedoodle) inSt.readObject();
System.out.println(openedMap);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
}
}
}
This bit of code compiles, runs and outputs as expected. Your error must lie in code that you've not shown us.
This problem was solved 5 years ago, the solution is lost due to bad memory though.

Categories