Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a default filesystem loader for OpenAssetFunc #8

Open
mcarpenter622 opened this issue Jun 15, 2024 · 2 comments
Open

Provide a default filesystem loader for OpenAssetFunc #8

mcarpenter622 opened this issue Jun 15, 2024 · 2 comments

Comments

@mcarpenter622
Copy link

It was a bit of a pain trying to figure out how to load an MP3 from the file system. I ended up with something like this
`

type TEST struct {
bytes.Reader
}

func (TEST) Close() error {
return nil
}

l.OpenAssetFunc = func(path string) io.ReadCloser {
	v, _ := os.ReadFile(path)
	var result TEST
	result.Reader = *bytes.NewReader(v)
	return &result
}

`

@quasilyte
Copy link
Owner

quasilyte commented Jun 15, 2024

For your example, I think it can be simplified a bit. Unless you really want to eagerly read the file. Since there is caching, either way would work. OpenAssetFunc is called only once per every path.

l.OpenAssetFunc = func(path string) io.ReadCloser {
	// May want to check for an error just in case.
	f, _ := os.Open(path)
	return f
}

For games that have 100% of their assets embedded, it would look like this:

//go:embed all:_data
var gameAssets embed.FS

func OpenAsset(path string) io.ReadCloser {
    f, err := gameAssets.Open("_data/" + path)
    if err != nil {
        panic(err)
    }
    return f
}

For games that may want to have external resources it can be a bit more complicated. I would suggest adding some magic prefix to the resource paths, so OpenAsset may understand that:

func MakeOpenAssetFunc(dataFolder string) func(path string) io.ReadCloser {
	return func(path string) io.ReadCloser {
		if strings.HasPrefix(path, "$") {
			// An external file.
			f, err := os.Open(filepath.Join(dataFolder, path[len("$"):]))
			if err != nil {
				panic(err)
			}
			return f
		}
		// An embedded file.
		f, err := gameAssets.Open("_data/" + path)
		if err != nil {
			panic(err)
		}
		return f
	}
}

OpenAsset = MakeOpenAssetFunc("path/to/data/dir")

By using a closure approach, the open asset func can have some "state" like data dir location, etc. Although it might be a global variable too.

@mcarpenter622
Copy link
Author

mcarpenter622 commented Jun 15, 2024

So I tried that:

l.OpenAssetFunc = func(path string) io.ReadCloser {
	// May want to check for an error just in case.
	f, _ := os.Open(path)
	return f
}

But it doesnt work with an infinite loop mp3. Length in that function returns -1.

func LoopMP3(stream io.ReadSeeker) io.ReadSeeker {
	mp3Stream := stream.(*mp3.Stream)
	fmt.Println(mp3Stream.Length())

	return audio.NewInfiniteLoop(mp3Stream, mp3Stream.Length())
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants