Skip to content

Commit

Permalink
♻️ introduce AssetSource annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
bitbrain committed May 10, 2020
1 parent 2cccb7a commit 3b1dd69
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 85 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# Version 0.6.33

* [[#224](https://github.com/bitbrain/braingdx/issues/224)] introduce `@AssetSource` annotation


# Version 0.6.32

* simplify screens by making generic arguments optional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,9 @@
package de.bitbrain.braingdx.assets;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.ParticleEffect;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.maps.tiled.TiledMap;
import de.bitbrain.braingdx.assets.annotations.AssetSource;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
Expand All @@ -39,61 +32,40 @@
* <li>Particles</li>
* <li>TiledMaps</li>
* </ul>
* In order to extend or change the list make use of the {@link SmartAssetLoaderConfiguration}.
*
* @author Miguel Gonzalez Sanchez
*/
public class SmartAssetLoader implements GameAssetLoader {

private final SmartAssetLoaderConfiguration configuration;
private final Class<?> target;
public SmartAssetLoader(Class<?> target) {
this(target, defaultConfiguration());
}

public SmartAssetLoader(Class<?> target, SmartAssetLoaderConfiguration configuration) {
public SmartAssetLoader(Class<?> target) {
this.target = target;
this.configuration = configuration;
}

public static SmartAssetLoaderConfiguration defaultConfiguration() {
final Map<String, Class<?>> mapping = new HashMap<String, Class<?>>();
mapping.put("Textures", Texture.class);
mapping.put("Sounds", Sound.class);
mapping.put("Musics", Music.class);
mapping.put("BitmapFonts", BitmapFont.class);
mapping.put("Fonts", FreeTypeFontGenerator.class);
mapping.put("Particles", ParticleEffect.class);
mapping.put("TiledMaps", TiledMap.class);
return new SmartAssetLoaderConfiguration() {
@Override
public Map<String, Class<?>> getClassMapping() {
return mapping;
}
};
}

@Override
public void put(Map<String, Class<?>> assets) {
// for every sub-class, check for the given type
for (Class<?> subclass : target.getDeclaredClasses()) {
String categoryName = subclass.getSimpleName();
Class<?> assetClassType = configuration.getClassMapping().get(categoryName);
if (assetClassType != null) {
putMembers(subclass, assets, assetClassType);
} else {
Gdx.app.log("WARN", "Asset category " + categoryName + " not defined in SmartAssetLoaderConfiguration!");
}
putMembers(subclass, assets, subclass.getAnnotation(AssetSource.class));
}
putMembers(target, assets, target.getAnnotation(AssetSource.class));
}

private void putMembers(Class<?> subclass, Map<String, Class<?>> assets, Class<?> assetClassType) {
private void putMembers(Class<?> subclass, Map<String, Class<?>> assets, AssetSource source) {
for (Field field : subclass.getFields()) {
if (field.getAnnotation(AssetSource.class) != null) {
source = field.getAnnotation(AssetSource.class);
}
if (source == null) {
Gdx.app.error("ERROR", "Field " + field.getName() + " does has a missing asset source. Ignoring!");
continue;
}
try {
Object path = field.get(null);
if (path instanceof String) {
assets.put((String) path, assetClassType);
Gdx.app.log("INFO", "Registering asset: path=" + path + ", class=" + assetClassType.getName());
assets.put(source.directory() + "/" + path, source.assetClass());
Gdx.app.log("INFO", "Registering asset: path=" + path + ", class=" + source.assetClass().getName());
} else {
Gdx.app.log("WARN", "Invalid property type in '" + subclass.getName() + "::" + field.getName() + "! Only java.lang.String is allowed.");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package de.bitbrain.braingdx.assets.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AssetSource {
String directory() default "";
Class<?> assetClass();
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/* Copyright 2017 Miguel Gonzalez Sanchez
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package de.bitbrain.braingdx.assets;

import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.ParticleEmitter;
import com.badlogic.gdx.maps.tiled.TiledMap;
import de.bitbrain.braingdx.assets.annotations.AssetSource;

public interface SampleInvalidAssets {

String field1 = "texture-field1";
@AssetSource(directory = "textures", assetClass = Texture.class) String field2 = "texture-field2";

@AssetSource(directory = "textures", assetClass = Texture.class)
interface Textures {
String field1 = "texture-field1";
String field2 = "texture-field2";
}

interface Musics {
String field1 = "musics-field1";
String field2 = "musics-field2";
}

@AssetSource(directory = "sounds", assetClass = Sound.class)
interface Sounds {
String field1 = "sounds-field1";
String field2 = "sounds-field2";
int invalid = 39;
}

@AssetSource(directory = "maps", assetClass = TiledMap.class)
interface TiledMaps {
String field1 = "tmx-field1";
String field2 = "tmx-field2";
}

@AssetSource(directory = "particles", assetClass = ParticleEmitter.class)
interface Particles {
String field1 = "particles-field1";
String field2 = "particles-field2";
}

@AssetSource(directory = "fonts", assetClass = BitmapFont.class)
interface Fonts {
String field1 = "fonts-field1";
String field2 = "fonts-field2";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,51 @@

package de.bitbrain.braingdx.assets;

import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.ParticleEmitter;
import com.badlogic.gdx.maps.tiled.TiledMap;
import de.bitbrain.braingdx.assets.annotations.AssetSource;

public interface SampleValidAssets {

@AssetSource(directory = "textures", assetClass = Texture.class)
String field1 = "texture-field1";

@AssetSource(directory = "textures", assetClass = Texture.class)
interface Textures {
String field1 = "texture-field1";
String field2 = "texture-field2";
}

@AssetSource(directory = "music", assetClass = Music.class)
interface Musics {
String field1 = "musics-field1";
String field2 = "musics-field2";
}

@AssetSource(directory = "sounds", assetClass = Sound.class)
interface Sounds {
String field1 = "sounds-field1";
String field2 = "sounds-field2";
int invalid = 39;
}

@AssetSource(directory = "maps", assetClass = TiledMap.class)
interface TiledMaps {
String field1 = "tmx-field1";
String field2 = "tmx-field2";
}

@AssetSource(directory = "particles", assetClass = ParticleEmitter.class)
interface Particles {
String field1 = "particles-field1";
String field2 = "particles-field2";
}

@AssetSource(directory = "fonts", assetClass = BitmapFont.class)
interface Fonts {
String field1 = "fonts-field1";
String field2 = "fonts-field2";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@

import com.badlogic.gdx.Application;
import com.badlogic.gdx.Gdx;
import de.bitbrain.braingdx.assets.SmartAssetLoader.SmartAssetLoaderConfiguration;
import org.assertj.core.api.Assertions;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import java.util.HashMap;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.*;

/**
* Test for {@link SmartAssetLoader}.
*/
Expand All @@ -36,31 +39,34 @@ public class SmartAssetLoaderTest {
@Before
public void beforeTest() {
assets = new HashMap<String, Class<?>>();
Gdx.app = Mockito.mock(Application.class);
Application application = mock(Application.class);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
String tag = (String) invocationOnMock.getArguments()[0];
String message = (String) invocationOnMock.getArguments()[1];
throw new RuntimeException("Unexpected error log found: tag=" + tag + ", message=" + message);
}
}).when(application).error(anyString(), anyString());
Gdx.app = application;

}

@Test
public void testDefaultTypes() {
SmartAssetLoader loader = new SmartAssetLoader(SampleValidAssets.class);
loader.put(assets);
Assertions.assertThat(assets).hasSize(12);
}

@Test
public void testDefaultTypesWithAsdfTypes() {
SmartAssetLoaderConfiguration config = SmartAssetLoader.defaultConfiguration();
config.getClassMapping().put("AsdfType", Object.class);
SmartAssetLoader loader = new SmartAssetLoader(CustomSampleValidAssets.class, config);
loader.put(assets);
Assertions.assertThat(assets).hasSize(2);
assertThat(assets).hasSize(12);
}

@Test
public void testDefaultTypes_MissingType() {
SmartAssetLoaderConfiguration config = SmartAssetLoader.defaultConfiguration();
config.getClassMapping().put("AsdfType2", Object.class);
SmartAssetLoader loader = new SmartAssetLoader(CustomSampleValidAssets.class, config);
public void testProducesErrors_WithInvalidAssets() {
Application application = mock(Application.class);
doNothing().when(application).error(anyString(), anyString());
Gdx.app = application;
SmartAssetLoader loader = new SmartAssetLoader(SampleInvalidAssets.class);
loader.put(assets);
Assertions.assertThat(assets).hasSize(0);
assertThat(assets).hasSize(10);
verify(application, times(3)).error(anyString(), anyString());
}
}

0 comments on commit 3b1dd69

Please sign in to comment.