Jump to content
  • Home
  • Files
  • Docs
Topics
  • All Content

  • This Topic
  • This Forum

  • Advanced Search
  • Existing user? Sign In  

    Sign In



    • Not recommended on shared computers


    • Forgot your password?

  • Sign Up
  • All Activity
  • Home
  • Mod Developer Central
  • Modder Support
  • [1.6.2] Creating and registering your own ResourcePack class
Currently Supported: 1.16.X (Latest) and 1.15.X (LTS)
Sign in to follow this  
Followers 0
Akjosch

[1.6.2] Creating and registering your own ResourcePack class

By Akjosch, October 4, 2013 in Modder Support

  • Reply to this topic
  • Start new topic

Recommended Posts

Akjosch    4

Akjosch

Akjosch    4

  • Tree Puncher
  • Akjosch
  • Members
  • 4
  • 17 posts
Posted October 4, 2013

Ok, so I'm trying to do something which should be simple: Creating my own ResourcePack class. The currently available net.minecraft.client.resources.AbstractResourcePack just doesn't cut it for the following reasons (and I'd prefer to leave that alone so not to break anything else):

 

  • It's client-side only.
  • At least one of its implementations (FolderResourcePack) considers a directory to not be a valid resource (see: hasResourceName() checking for isFile()). Mind you, an archive file (which is basically the same thing: both are containers for resources) is accepted just fine, which is beyond silly.
  • There's no way to specify that your resource location is something with wildcards in it, or at least a filtered directory or archive.

 

Now, that's all fine. Implementing my own class which implements ResourcePack is easy enough. However, I have no way to tell that my mod wants to use this specific ResourcePack instead of the default FMLFolderResourcePack or FMLFileResourcePack (Or is there? I couldn't find it). At least not without changing the code of FMLModContainer's getCustomResourcePackClass() method, which means a coremod + ASM tricksery, which I loathe to do.

 

The other idea I had was to implement and inject my own ModContainer, derived from and almost identical to FMLModContainer, using (and triggered by) my own annotation instead of @cpw.mods.fml.common.Mod, but I still don't see how to achieve that. This time I get foiled, it seems, by ModContainerFactory's build() method, which has "@Mod" hardcoded as the only annotation it cares about. Again, only fixable by hacking around core Forge classes, not something I'm a fan of.

 

Do I really have to turn every single mod where I'd like to do something as trivial as use my own ResourcePack class into a coremod? Is there a better, more elegant method? My ideal solution would be a simple annotation alongside @Mod and @NetworkMod:

 

@ResourcePack(class="my.CustomResourcePack")

 

Side note: Tagged as 1.6.2 since that's what I'm using, but looking at the Forge code nothing much changed in 1.6.4 about my problems.

 

-------------------

Thinking about it a bit more, can I just modify Minecraft.getMinecraft().defaultResourcePacks (I know it's private ...) at some point before the last call to refreshResources(), or modify it and call the method myself, or will it horribly break things?

  • Quote

ItemBlock is not a Block

ItemStack is not an Item

Damage value is not metadata

 

Stop confusing them.

Share this post


Link to post
Share on other sites

Mazetar    271

Mazetar

Mazetar    271

  • World Shaper
  • Mazetar
  • Forge Modder
  • 271
  • 1343 posts
Posted October 4, 2013

I have no good replies for you, but I wanted to give you a heads up that there may be sever changes to the way such packs works in the upcoming 1.7 update.

 

For your last paragraph:

You can use Reflection to change a private member to public if that would help?

Else you could use a coremod and take advantage of the ASM library to modify the class at runtime (no direct base edits!)

 

 

 

  • Quote

If you guys dont get it.. then well ya.. try harder...

Share this post


Link to post
Share on other sites

Akjosch    4

Akjosch

Akjosch    4

  • Tree Puncher
  • Akjosch
  • Members
  • 4
  • 17 posts
Posted October 4, 2013

I have no good replies for you, but I wanted to give you a heads up that there may be sever changes to the way such packs works in the upcoming 1.7 update.

 

Yeah ... would be nice to have it running for 1.6 though. Given how long some mods are taking to upgrade from 1.5 already, I'm not in a hurry.

 

You can use Reflection to change a private member to public if that would help?

Else you could use a coremod and take advantage of the ASM library to modify the class at runtime (no direct base edits!)

 

Forge already changes "private" class members to "public" at Minecraft startup (and before the mods load), so it works by simply changing them to "public" in your development environment and making sure you don't include anything which isn't in your packages when you make the distribution.

 

... and changing the functionality via ASM hacks is what I'm trying to avoid doing. ;)

  • Quote

ItemBlock is not a Block

ItemStack is not an Item

Damage value is not metadata

 

Stop confusing them.

Share this post


Link to post
Share on other sites

GotoLink    381

GotoLink

GotoLink    381

  • World Shaper
  • GotoLink
  • Members
  • 381
  • 2012 posts
Posted October 4, 2013

Personally, i would use

Minecraft.getMinecraft().mcResourcePackRepository.setRepositoryEntries(array);

to add a custom ResourcePackRepositoryEntry which override updateResourcePack() to call your custom ResourcePack.

 

As a side note, there is no "last call to refreshResources()". Minecraft itself does it regularly.

So you can do that anytime, i assume.

 

It's client-side only.

And how is that a drawback for a ResourcePack ? A server doesn't need multiple versions of the same thing...

  • Quote

Share this post


Link to post
Share on other sites

Akjosch    4

Akjosch

Akjosch    4

  • Tree Puncher
  • Akjosch
  • Members
  • 4
  • 17 posts
Posted October 4, 2013

It's client-side only.

And how is that a drawback for a ResourcePack ? A server doesn't need multiple versions of the same thing...

 

Well yes, yes they do. Examples:

 

  • Localisation of server messages (depending on client's language setting)
  • Server-generated resources (again, depending on client's capabilities, localisation or settings)
  • Dynamically extending instead of replacing resources, which is the whole point of the exercise of having directories and wildcards as valid resource locations.

  • Quote

ItemBlock is not a Block

ItemStack is not an Item

Damage value is not metadata

 

Stop confusing them.

Share this post


Link to post
Share on other sites

GotoLink    381

GotoLink

GotoLink    381

  • World Shaper
  • GotoLink
  • Members
  • 381
  • 2012 posts
Posted October 4, 2013

Localisation handled by the server ?  :o

Are you crazy ?

This would mean different packet length for each receiving part depending on the receiver settings...this a f* nightmare !

Let that to client, please...

Or next time you are going to try handling the rendering on server side.:P

  • Quote

Share this post


Link to post
Share on other sites

Akjosch    4

Akjosch

Akjosch    4

  • Tree Puncher
  • Akjosch
  • Members
  • 4
  • 17 posts
Posted October 4, 2013

Some test reports:

 

Well, hooking up my resource pack in FMLClientHandler.instance().resourcePackList and FMLClientHandler.instance().resourcePackMap in pre-init, followed by Minecraft.getMinecraft().refreshResources() works to a point - the FallbackResourceManager calls it up. However, it then tries to construct a SimpleResource, which needs an InputStream, which won't work and makes no sense with a directory.

 

Time to implement my own ResourceManager and convince Minecraft to use that for my mods ... Which will be kinda hard given it only uses one, in Minecraft.getMinecraft().mcResourceManager- Yay. Fun. Anybody got an easier, more straightforward idea?

 

  • Quote

ItemBlock is not a Block

ItemStack is not an Item

Damage value is not metadata

 

Stop confusing them.

Share this post


Link to post
Share on other sites

Akjosch    4

Akjosch

Akjosch    4

  • Tree Puncher
  • Akjosch
  • Members
  • 4
  • 17 posts
Posted October 5, 2013

Test #2, time to implement my own InputStream which can deal with directories (and handles zip files as directories as well). Wish me luck. ;)

 

package my.package;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

/**
* An InputStream supporting files and directories.
* <p>
* It works in one of several modes, depending on what the argument to the constructor was.
* <p>
* If the argument is a directory, it'll behave like a zero-length input stream. In addition,
* isDirectory() will return <i>true</i>, isFile() will return <i>false</i>. The specific files
* and directories are available through the default Iterable interface returned by
* the interface() method.
* <p>
* If the argument is an archive file (currently only ZIP files supported), it'll behave like
* a directory, but also allow for direct reading of the file same as a FileInputStream would
* and return <i>true</i> for isFile().
* <p>
* If the argument is any other file, this class behaves like a FileInputStream. In particular,
* iterator() returns <i>null</i>.
*/
public class DirectoryInputStream extends InputStream implements Iterable<InputStream>
{
private File baseFile = null;
private ZipFile zipFile = null;
private InputStream baseInputStream = null;

public DirectoryInputStream(String name) throws FileNotFoundException
{
	this(name != null ? new File(name) : null);
}

public DirectoryInputStream(File file) throws FileNotFoundException
{
	String name = (file != null ? file.getPath() : null);
        if (name == null) {
            throw new NullPointerException();
        }
        baseFile = file;
        try
        {
		zipFile = new ZipFile(file);
	}
        catch (ZipException ze)
        {
        	// This is clearly not a zip file. 
	}
        catch (IOException ioe)
        {
        	// Neither is this
	}
        if( baseFile.isFile() )
        {
        	baseInputStream = new FileInputStream(baseFile);
        }
   }

public boolean isFile()
{
	return baseFile.isFile();
}

public boolean isDirectory()
{
	return baseFile.isDirectory() || null != zipFile;
}

@Override
public int read() throws IOException
{
	return( null != baseInputStream ? baseInputStream.read() : -1 );
}

@Override
public int read(byte[] b) throws IOException
{
	return( null != baseInputStream ? baseInputStream.read(b) : -1 );
}

@Override
public int read(byte[] b, int off, int len) throws IOException
{
	return( null != baseInputStream ? baseInputStream.read(b, off, len) : -1);
}

@Override
public long skip(long n) throws IOException
{
	return( null != baseInputStream ? baseInputStream.skip(n) : 0);
}

@Override
public int available() throws IOException
{
	return( null != baseInputStream ? baseInputStream.available() : 0);
}

@Override
public void close() throws IOException
{
	if( null != baseInputStream )
	{
		baseInputStream.close();
	}
	if( null != zipFile )
	{
		zipFile.close();
	}
}

@Override
public synchronized void reset() throws IOException
{
	if( null != baseInputStream )
	{
		baseInputStream.reset();
	}
}

@Override
public Iterator<InputStream> iterator()
{
	if( baseFile.isDirectory() )
	{
		Iterator<InputStream> it = new Iterator<InputStream>()
		{
			private int currentIndex = 0;
			private File[] files = baseFile.listFiles();

			@Override
			public boolean hasNext()
			{
				return currentIndex + 1 < files.length;
			}

			@Override
			public InputStream next()
			{
				++ currentIndex;
				try {
					if( files[currentIndex].isDirectory() )
					{
						return new DirectoryInputStream(files[currentIndex]);
					}
					else
					{
						return new FileInputStream(files[currentIndex]);
					}
				}
				catch (FileNotFoundException e)
				{
					// Shouldn't happen
					return null;
				}
			}

			@Override
			public void remove()
			{
				// We don't supply remove()
			}
		};
		return it;
	}
	else if( null != zipFile )
	{
		// TODO: Make sure we don't accidentally return non-working InputStreams, like
		// for directories, and not crash and burn either when we encounter one.
		Iterator<InputStream> it = new Iterator<InputStream>()
		{
			private Enumeration<? extends ZipEntry> entries = zipFile.entries();

			@Override
			public boolean hasNext()
			{
				return entries.hasMoreElements();
			}

			@Override
			public InputStream next()
			{
				ZipEntry zipEntry = entries.nextElement();
				try
				{
					return zipFile.getInputStream(zipEntry);
				}
				catch (IOException e)
				{
					// Shouldn't happen. Did someone close the file on us?
					return null;
				}
			}

			@Override
			public void remove()
			{
				// We don't supply remove()
			}
		};
		return it;
	}
	else
	{
		return null;
	}
}

}

 

Input, as usual, very much appreciated.

  • Quote

ItemBlock is not a Block

ItemStack is not an Item

Damage value is not metadata

 

Stop confusing them.

Share this post


Link to post
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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  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.

    • Insert image from URL
×
  • Desktop
  • Tablet
  • Phone
Sign in to follow this  
Followers 0
Go To Topic Listing



  • Recently Browsing

    No registered users viewing this page.

  • Posts

    • NovaViper
      1.16.4 Forge Crashing On Start

      By NovaViper · Posted 8 minutes ago

      Do you know what version of Java that forge supports? The version that's bundled with the Minecraft Launcher is 15 oddly
    • DaemonUmbra
      1.16.4 Forge Crashing On Start

      By DaemonUmbra · Posted 12 minutes ago

      There is no way you could know you have the same problem from what the original user posted... response split to its own thread Your issue is using Java 15, and only certain versions of Forge are currently compatible.
    • NovaViper
      1.16.4 Forge Crashing On Start

      By NovaViper · Posted 51 minutes ago

      I'm having the same issue as OP on 1.16.4, here's my log:debug.log My machine is running Manjaro 20.1 with OpenJRE 15
    • DaemonUmbra
      I don't know how forge works

      By DaemonUmbra · Posted 1 hour ago

      You can This is accomplished by putting the mods in the server's mods folder.   You must install Forge to .minecraft (the default location) unless you are doing something funny with your launcher. This is NOT how you make separate instances of Forge.
    • DaemonUmbra
      Forge Installer Not Opening

      By DaemonUmbra · Posted 1 hour ago

      If you have Java installed correct you should be able to just double click the installer and Java will handle running it.
  • Topics

    • NovaViper
      2
      1.16.4 Forge Crashing On Start

      By NovaViper
      Started 51 minutes ago

    • Mark74
      7
      I don't know how forge works

      By Mark74
      Started 5 hours ago

    • BlakeRowsGood
      1
      Forge Installer Not Opening

      By BlakeRowsGood
      Started 3 hours ago

    • MKR0902
      1
      1.12.2 Forge Server Not starting with command arguements

      By MKR0902
      Started 4 hours ago

    • Amazinwave
      1
      Amazinwave

      By Amazinwave
      Started 5 hours ago

  • Who's Online (See full list)

    • NovaViper
    • Thompson5893
    • S-Spirit
    • Ludicroussilent
    • Danebi
    • DaemonUmbra
    • SonataSapphire
    • OttersMeep
  • All Activity
  • Home
  • Mod Developer Central
  • Modder Support
  • [1.6.2] Creating and registering your own ResourcePack class
  • Theme

Copyright © 2019 ForgeDevelopment LLC · Ads by Longitude Ads LLC Powered by Invision Community