Jump to content

Java "pass-by-reference" and private variables question


jabelar

Recommended Posts

I saw a web page that claims you can directly hardcode the mod info rather than rely on an mcmod.info file.  (http://minecraftforgetutorials.weebly.com/hardcoded-mod-metadata-aka-virtual-mcmodinfo-file.html)

 

The idea is that the FMLPreInitializationEvent event actually has a mod container with such info in it and there are some methods that look like you can access them.

 

Here is the vanilla code for that event:

/*

* Forge Mod Loader

* Copyright © 2012-2013 cpw.

* All rights reserved. This program and the accompanying materials

* are made available under the terms of the GNU Lesser Public License v2.1

* which accompanies this distribution, and is available at

* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html

*

* Contributors:

*    cpw - implementation

*/

 

package cpw.mods.fml.common.event;

 

import java.io.File;

import java.security.CodeSource;

import java.security.cert.Certificate;

import java.util.Properties;

 

import org.apache.logging.log4j.LogManager;

import org.apache.logging.log4j.Logger;

 

import cpw.mods.fml.common.LoaderState.ModState;

import cpw.mods.fml.common.FMLModContainer;

import cpw.mods.fml.common.ModContainer;

import cpw.mods.fml.common.ModMetadata;

import cpw.mods.fml.common.discovery.ASMDataTable;

 

public class FMLPreInitializationEvent extends FMLStateEvent

{

    private ModMetadata modMetadata;

    private File sourceFile;

    private File configurationDir;

    private File suggestedConfigFile;

    private ASMDataTable asmData;

    private ModContainer modContainer;

 

    public FMLPreInitializationEvent(Object... data)

    {

        super(data);

        this.asmData = (ASMDataTable)data[0];

        this.configurationDir = (File)data[1];

    }

 

    @Override

    public ModState getModState()

    {

        return ModState.PREINITIALIZED;

    }

 

    @Override

    public void applyModContainer(ModContainer activeContainer)

    {

        this.modContainer = activeContainer;

        this.modMetadata = activeContainer.getMetadata();

        this.sourceFile = activeContainer.getSource();

        this.suggestedConfigFile = new File(configurationDir, activeContainer.getModId()+".cfg");

    }

 

    public File getSourceFile()

    {

        return sourceFile;

    }

 

    public ModMetadata getModMetadata()

    {

        return modMetadata;

    }

 

    public File getModConfigurationDirectory()

    {

        return configurationDir;

    }

 

    public File getSuggestedConfigurationFile()

    {

        return suggestedConfigFile;

    }

 

    public ASMDataTable getAsmData()

    {

        return asmData;

    }

 

    public Properties getVersionProperties()

    {

        if (this.modContainer instanceof FMLModContainer)

        {

            return ((FMLModContainer)this.modContainer).searchForVersionProperties();

        }

 

        return null;

    }

 

    /**

    * Get a logger instance configured to write to the FML Log as a parent, identified by modid. Handy for mod logging!

    * Configurations can be applied through the <code>config/logging.properties</code> file, specifying logging levels

    * for your ModID. Use this!

    *

    * @return A logger

    */

    public Logger getModLog()

    {

        Logger log = LogManager.getLogger(modContainer.getModId());

        return log;

    }

 

 

    /**

    * Retrieve the FML signing certificates, if any. Validate these against the

    * published FML certificates in your mod, if you wish.

    *

    * Deprecated because mods should <b>NOT</b> trust this code. Rather

    * they should copy this, or something like this, into their own mods.

    *

    * @return Certificates used to sign FML and Forge

    */

    @Deprecated

    public Certificate[] getFMLSigningCertificates()

    {

        CodeSource codeSource = getClass().getClassLoader().getParent().getClass().getProtectionDomain().getCodeSource();

        Certificate[] certs = codeSource.getCertificates();

        if (certs == null)

        {

            return new Certificate[0];

        }

        else

        {

            return certs;

        }

    }

}

 

 

Now the web page claims than in your preInit method you can edit the mod info like

event.getModMetadata().description = "The MinecraftForgeTutorials Tutorial Mod description"; // Description setting

 

However, this seems strange to me because the getModMetadata() method returns a value from a private variable in the event class.  So I don't see how you can edit further attributes of what is returned -- basically I thought you need to have a set method in order to set private variables in a class.

 

I guess I've dabbled in too many computer languages because I realize I'm not confident in my understanding of this.  But can you really manipulate a private variable outside the class if it is returned from a method in the class?

 

Also, the recommended method didn't work for me anyway, so I'm doubly suspicious of the recommendation ...

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

Hi,

 

The answer is both yes and no :P See http://stackoverflow.com/questions/40480/is-java-pass-by-reference for a good description of how Java passes even references by value.

 

While you cannot change what the variable in the other location refers to (you cannot reassign it), as long it is not a primitive type you CAN change the values that it holds.

 

For example, if the method returned a private list, I can clear the list and it will be cleared in the other class as well, but if I reassign the list to a new list, the old list and variable holding the list in the other class are not affected.

 

Hope that helps,

coolAlias

Link to comment
Share on other sites

Hi,

 

The answer is both yes and no :P See http://stackoverflow.com/questions/40480/is-java-pass-by-reference for a good description of how Java passes even references by value.

 

While you cannot change what the variable in the other location refers to (you cannot reassign it), as long it is not a primitive type you CAN change the values that it holds.

 

For example, if the method returned a private list, I can clear the list and it will be cleared in the other class as well, but if I reassign the list to a new list, the old list and variable holding the list in the other class are not affected.

 

Hope that helps,

coolAlias

 

Thanks.  That is along the lines of my understanding of the pass-by-value idea of Java, except that the passing of a private variable still seems strange to me.

 

So I think you're saying:

 

If Class A has private variable privVar1 and if I pass it to a method in Class B, then Class B can modify the value in Class A if it wanted to.  Similarly, if Class B had a private variable and returned it in a method called by Class A that Class A could then modify the value in Class B if it wanted to.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

The access modifier of the variable in question is irrelevant as soon as you return it. For example:

 

public class A {
private List list;

public getList() {
return list;
}
}

public class B {

A a = new A();

public void someMethod() {
List l = a.getList();

// I can now modify the list to my heart's content, and all changes
// will be reflected in the instance of "A"'s list as well (other than reassignment)

l.add("I'm in a's list, too!!!");
l = new List();
l.add("I'm no longer modifying a's list");
}

Now the A object 'a' has a list with one String, and the B class has a list with one String, but both strings are different. Whenever you return a field from a class, if that field is an Object with modifiable fields, you have just opened up your private field to modification of this sort.

Link to comment
Share on other sites

Thanks.  I definitely understand it now.  Seems like a dangerous sort of approach compared to some other programming languages where you would at least be explicit with pointers and such to distinguish whether you just want a copy versus access to the actual field in the other class.

 

Okay, since it sounds like you CAN edit the private variables once they are passed in a return of a method, then what do you think of the idea of hard-coding the mod info as suggested in the web link at the top of this thread?  I tried it briefly but didn't see it work ... but maybe I'll play around more with it.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

Pointers are equally as dangerous, since they give you access to the same memory location you can just as readily alter supposedly private data. In C++, if you give me a pointer to a List, whether by reference or value, I can now change your List just the same as the Java example I showed you. If you pass me the pointer by reference, I can not only change your list, but I can change where your private field points! In Java, the second (and far more dangerous of the two), is not possible.

 

In Java, therefore, you can not actually change the private field, you can only change data that it contains if the field itself has methods or public fields that can be changed (like in the case of List).

 

Anyway, you are probably overthinking this; why are you so concerned about the mod info?

Link to comment
Share on other sites

Anyway, you are probably overthinking this; why are you so concerned about the mod info?

 

I just try things and if they don't work then I have to understand since it means I must be missing something.

 

In this case it is really interesting -- I tried overwriting the modmetadata with credits and description and it didn't work (in the launcher mod list it just complained about missing mod info file).  So then I got worried about my understanding of Java because I thought it should work.  After discussing with you I got confident that it should have worked after all, so I looked at it again...

 

It turns out that there is another field called autogenerated which needs to be set to false in order for it to skip looking for mcmod.info file.  Once I set that it worked!!

 

So basically I didn't like having something that I thought should work not work, but I also admit that I find the mcmod.info file annoying.

 

So for anyone that is interested (I'll post something else about this, maybe a tutorial), you CAN hardcode the mod info as long as you set the autogenerated to false.  For example:

 

 

    @EventHandler

    public void preInit(FMLPreInitializationEvent event)

    { 

        event.getModMetadata().autogenerated = false ; // stops it from complaining about missing mcmod.info

        event.getModMetadata().credits = "jabelar";

        event.getModMetadata().description = "The wildest animals that ever inhabited Minecraft";

 

        proxy.preInit();

    }

 

 

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

I used to find the mcmod.info annoying too and started to hard code my mod info that way, but i realized there might possibly be some other programs that depend on the mcmod.info file. maybe a launcher that uses the file to detect mods or get info about it? i think of it as a pseudo-manifest file. anyway,  i thought it might not be a good idea to get rid of the mcmod.info and ended up putting the file back just to be safe. there's almost no difference anyway and it's sort of the standard thing to have already

Link to comment
Share on other sites

I used to find the mcmod.info annoying too and started to hard code my mod info that way, but i realized there might possibly be some other programs that depend on the mcmod.info file. maybe a launcher that uses the file to detect mods or get info about it? i think of it as a pseudo-manifest file. anyway,  i thought it might not be a good idea to get rid of the mcmod.info and ended up putting the file back just to be safe. there's almost no difference anyway and it's sort of the standard thing to have already

 

Thanks for the feedback.  Yeah, there is usually a side effect when doing something unorthodox. 

 

I'll probably continue to hardcode until it becomes an issue.  For now my mods are mostly just for personal use, but maybe if they start being used publicly I'll need to do the work to ensure compatibility.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.