Initial commit (basic backend stuff)
This commit is contained in:
16
src/main/java/de/siphalor/was/Start.java
Normal file
16
src/main/java/de/siphalor/was/Start.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package de.siphalor.was;
|
||||
|
||||
import de.siphalor.was.content.lang.I18n;
|
||||
|
||||
public class Start {
|
||||
public static void main(String[] args) {
|
||||
WhatAStorage was = WhatAStorage.getInstance();
|
||||
was.reload();
|
||||
was.start();
|
||||
|
||||
I18n.setLang("de_de", was.getContentManager());
|
||||
System.out.println(I18n.get("test.hello-world"));
|
||||
|
||||
was.run();
|
||||
}
|
||||
}
|
||||
129
src/main/java/de/siphalor/was/WhatAStorage.java
Normal file
129
src/main/java/de/siphalor/was/WhatAStorage.java
Normal file
@@ -0,0 +1,129 @@
|
||||
package de.siphalor.was;
|
||||
|
||||
import de.siphalor.was.content.ContentManager;
|
||||
import de.siphalor.was.content.lang.I18n;
|
||||
import de.siphalor.was.content.pack.FileContentPack;
|
||||
import de.siphalor.was.content.pack.JarContentPack;
|
||||
import de.siphalor.was.content.product.ProductManager;
|
||||
import de.siphalor.was.content.quest.QuestManager;
|
||||
import de.siphalor.was.state.MainMenuState;
|
||||
import de.siphalor.was.state.State;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class WhatAStorage {
|
||||
public static final String TITLE = "What a Storage";
|
||||
private static final WhatAStorage INSTANCE = new WhatAStorage();
|
||||
|
||||
public static WhatAStorage getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private final ContentManager contentManager;
|
||||
private final JarContentPack mainPack;
|
||||
private final ProductManager productManager;
|
||||
private final QuestManager questManager;
|
||||
|
||||
private Frame frame;
|
||||
private State state;
|
||||
|
||||
private long lastTick;
|
||||
private long minTickTime = 1000 / 60;
|
||||
private Canvas canvas;
|
||||
|
||||
private WhatAStorage() {
|
||||
contentManager = new ContentManager();
|
||||
mainPack = new JarContentPack("", "content");
|
||||
contentManager.addPack(mainPack);
|
||||
productManager = new ProductManager();
|
||||
questManager = new QuestManager();
|
||||
}
|
||||
|
||||
public ContentManager getContentManager() {
|
||||
return contentManager;
|
||||
}
|
||||
|
||||
public ProductManager getProductManager() {
|
||||
return productManager;
|
||||
}
|
||||
|
||||
public QuestManager getQuestManager() {
|
||||
return questManager;
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
contentManager.clear();
|
||||
|
||||
contentManager.addPack(mainPack);
|
||||
|
||||
File[] packDirs = Path.of("packs").toFile().listFiles(File::isDirectory);
|
||||
for (File dir : packDirs) {
|
||||
contentManager.addPack(new FileContentPack(dir.getName(), dir.toPath()));
|
||||
}
|
||||
|
||||
I18n.reload(contentManager);
|
||||
|
||||
productManager.clear();
|
||||
questManager.clear();
|
||||
productManager.reload(contentManager);
|
||||
questManager.reload(contentManager);
|
||||
|
||||
System.out.println("Reloaded game content");
|
||||
}
|
||||
|
||||
public void start() {
|
||||
frame = new Frame(TITLE);
|
||||
frame.setVisible(true);
|
||||
frame.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
super.windowClosing(e);
|
||||
frame.dispose();
|
||||
}
|
||||
});
|
||||
frame.addComponentListener(new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
super.componentResized(e);
|
||||
canvas.setSize(frame.getSize());
|
||||
state.onResize(frame.getWidth(), frame.getHeight());
|
||||
}
|
||||
});
|
||||
canvas = new Canvas();
|
||||
canvas.setSize(frame.getSize());
|
||||
frame.add(canvas);
|
||||
|
||||
changeState(new MainMenuState(canvas.getWidth(), canvas.getHeight()));
|
||||
}
|
||||
|
||||
public void run() {
|
||||
long time, timeDelta = minTickTime;
|
||||
lastTick = System.currentTimeMillis();
|
||||
|
||||
while (frame.isVisible()) {
|
||||
time = System.currentTimeMillis();
|
||||
timeDelta = time - lastTick - minTickTime;
|
||||
|
||||
if (timeDelta >= 0) {
|
||||
state.tick();
|
||||
state.render(canvas.getGraphics());
|
||||
lastTick = time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void changeState(State newState) {
|
||||
if (state != null) {
|
||||
state.leave();
|
||||
}
|
||||
state = newState;
|
||||
state.enter();
|
||||
state.onResize(canvas.getWidth(), canvas.getHeight());
|
||||
}
|
||||
}
|
||||
41
src/main/java/de/siphalor/was/assets/AssetsManager.java
Normal file
41
src/main/java/de/siphalor/was/assets/AssetsManager.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package de.siphalor.was.assets;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class AssetsManager {
|
||||
private static final Map<String, Image> imageCache = new HashMap<>();
|
||||
|
||||
public static final Image MISSINGNO = getImage("assets/missingno.png");
|
||||
|
||||
@Nullable
|
||||
public static InputStream getResource(@NotNull String path) {
|
||||
return Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
|
||||
}
|
||||
|
||||
public static Image getImage(@NotNull String path) {
|
||||
Image image = imageCache.get(path);
|
||||
if (image == null) {
|
||||
InputStream inputStream = getResource(path);
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
image = ImageIO.read(inputStream);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
image = MISSINGNO;
|
||||
}
|
||||
} else {
|
||||
image = MISSINGNO;
|
||||
}
|
||||
imageCache.put(path, image);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
}
|
||||
77
src/main/java/de/siphalor/was/content/ContentManager.java
Normal file
77
src/main/java/de/siphalor/was/content/ContentManager.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package de.siphalor.was.content;
|
||||
|
||||
import de.siphalor.was.content.pack.ContentPack;
|
||||
import de.siphalor.was.content.resource.Resource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ContentManager {
|
||||
private final List<ContentPack> packs = new LinkedList<>();
|
||||
|
||||
public ContentManager() {
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
packs.clear();
|
||||
}
|
||||
|
||||
public void addPack(ContentPack pack) {
|
||||
packs.add(pack);
|
||||
}
|
||||
|
||||
public Collection<ContentPack> getPacks() {
|
||||
return packs;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Stream<Resource> getResources(@NotNull String location, @NotNull String type) {
|
||||
return packs.stream().flatMap(pack -> pack.getResources(location, type)).distinct();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Optional<Resource> getResource(@NotNull String location) {
|
||||
Resource resource;
|
||||
for (ContentPack pack : packs) {
|
||||
resource = pack.getResource(location);
|
||||
if (resource != null) {
|
||||
return Optional.of(resource);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Stream<Resource> getAllOfResource(@NotNull String location) {
|
||||
return packs.stream().flatMap(pack -> Stream.ofNullable(pack.getResource(location)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Optional<Image> getImage(@NotNull String location) {
|
||||
return getResource(location).map(resource -> {
|
||||
InputStream inputStream = resource.getInputStream();
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
return ImageIO.read(inputStream);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
50
src/main/java/de/siphalor/was/content/lang/I18n.java
Normal file
50
src/main/java/de/siphalor/was/content/lang/I18n.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package de.siphalor.was.content.lang;
|
||||
|
||||
import de.siphalor.was.content.ContentManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class I18n {
|
||||
public static final String DEFAULT = "en_us";
|
||||
private static final Lang DEFAULT_LANG = new Lang(DEFAULT);
|
||||
|
||||
@Nullable
|
||||
private static Lang lang;
|
||||
|
||||
public static void setLang(@NotNull String code, @NotNull ContentManager contentManager) {
|
||||
if (lang == null || !lang.getCode().equals(code)) {
|
||||
lang = new Lang(code);
|
||||
lang.load(contentManager);
|
||||
}
|
||||
}
|
||||
|
||||
public static void reload(@NotNull ContentManager contentManager) {
|
||||
DEFAULT_LANG.load(contentManager);
|
||||
if (lang != null) {
|
||||
lang.load(contentManager);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String get(@NotNull String key) {
|
||||
String val;
|
||||
if (lang != null) {
|
||||
val = lang.get(key);
|
||||
if (val == null) {
|
||||
val = DEFAULT_LANG.get(key);
|
||||
}
|
||||
} else {
|
||||
val = DEFAULT_LANG.get(key);
|
||||
}
|
||||
|
||||
if (val == null) {
|
||||
return key;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String format(@NotNull String key, @Nullable Object... args) {
|
||||
return String.format(get(key), args);
|
||||
}
|
||||
}
|
||||
53
src/main/java/de/siphalor/was/content/lang/Lang.java
Normal file
53
src/main/java/de/siphalor/was/content/lang/Lang.java
Normal file
@@ -0,0 +1,53 @@
|
||||
package de.siphalor.was.content.lang;
|
||||
|
||||
import de.siphalor.was.content.ContentManager;
|
||||
import de.siphalor.was.content.resource.Resource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
|
||||
public class Lang {
|
||||
private final String code;
|
||||
private final Properties properties = new Properties();
|
||||
|
||||
public Lang(@NotNull String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void load(@NotNull ContentManager contentManager) {
|
||||
properties.clear();
|
||||
contentManager.getAllOfResource("lang/" + code + ".lang").forEachOrdered(resource -> {
|
||||
InputStream inputStream = resource.getInputStream();
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
properties.load(inputStream);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (properties.isEmpty()) {
|
||||
System.out.println("Failed to load lang file for " + code);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String get(@NotNull String key) {
|
||||
return (String) properties.get(key);
|
||||
}
|
||||
}
|
||||
16
src/main/java/de/siphalor/was/content/pack/ContentPack.java
Normal file
16
src/main/java/de/siphalor/was/content/pack/ContentPack.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package de.siphalor.was.content.pack;
|
||||
|
||||
import de.siphalor.was.content.resource.Resource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public interface ContentPack {
|
||||
@NotNull
|
||||
Stream<Resource> getResources(@NotNull String location, @NotNull String type);
|
||||
@Nullable
|
||||
Resource getResource(@NotNull String location);
|
||||
@NotNull
|
||||
String getId();
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package de.siphalor.was.content.pack;
|
||||
|
||||
import de.siphalor.was.content.resource.FileResource;
|
||||
import de.siphalor.was.content.resource.Resource;
|
||||
import de.siphalor.was.util.Util;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class FileContentPack implements ContentPack {
|
||||
private final String id;
|
||||
private final Path base;
|
||||
|
||||
public FileContentPack(@NotNull String id, @NotNull Path base) {
|
||||
this.id = id;
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Stream<Resource> getResources(@NotNull String location, @NotNull String type) {
|
||||
final String extension = "." + type;
|
||||
Path dir = base.resolve(Path.of(location));
|
||||
if (dir.toFile().isDirectory()) {
|
||||
try {
|
||||
return Files.find(dir, Integer.MAX_VALUE, (fPath, fileAttributes) -> fileAttributes.isRegularFile() && fPath.endsWith(extension)).map(path ->
|
||||
new FileResource(Util.pathToId(id, path.relativize(base).toString()), path.toFile())
|
||||
);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getResource(@NotNull String location) {
|
||||
File file = base.resolve(Path.of(location)).toFile();
|
||||
if (file.isFile()) {
|
||||
return new FileResource(Util.pathToId(id, location), file);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
109
src/main/java/de/siphalor/was/content/pack/JarContentPack.java
Normal file
109
src/main/java/de/siphalor/was/content/pack/JarContentPack.java
Normal file
@@ -0,0 +1,109 @@
|
||||
package de.siphalor.was.content.pack;
|
||||
|
||||
import de.siphalor.was.content.resource.FileResource;
|
||||
import de.siphalor.was.content.resource.CallbackResource;
|
||||
import de.siphalor.was.content.resource.Resource;
|
||||
import de.siphalor.was.util.Util;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class JarContentPack implements ContentPack {
|
||||
private final String id;
|
||||
private final String baseLocation;
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public JarContentPack(String id) {
|
||||
this(id, "");
|
||||
}
|
||||
|
||||
public JarContentPack(String id, String baseLocation) {
|
||||
this(id, baseLocation, Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
|
||||
public JarContentPack(String id, String baseLocation, ClassLoader classLoader) {
|
||||
this.id = id;
|
||||
this.baseLocation = baseLocation;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
// Inspired from this: https://stackoverflow.com/a/48190582/7582022
|
||||
@Override
|
||||
@NotNull
|
||||
public Stream<Resource> getResources(@NotNull String location, @NotNull String type) {
|
||||
final String extension = "." + type;
|
||||
try {
|
||||
URL url = classLoader.getResource(baseLocation + "/" + location);
|
||||
|
||||
if (url != null) {
|
||||
if ("file".equals(url.getProtocol())) {
|
||||
Path basePath = Path.of(url.toURI());
|
||||
return Files.find(basePath, Integer.MAX_VALUE, (path, attributes) -> attributes.isRegularFile() && path.getFileName().getName(0).toString().endsWith(extension)).map(path ->
|
||||
new FileResource(Util.pathToId(id, basePath.relativize(path).toString()), path.toFile())
|
||||
);
|
||||
} else if ("jar".equals(url.getProtocol())) {
|
||||
// The url path section begins with "file:" and ends with an exclamation mark and the path inside the jar
|
||||
// URLs also encode symbols with dollar sign so we need to decode them
|
||||
String urlPath = url.getPath();
|
||||
String jarPath = URLDecoder.decode(urlPath.substring(5, urlPath.indexOf('!')), StandardCharsets.UTF_8);
|
||||
|
||||
JarFile jarFile = new JarFile(jarPath);
|
||||
Enumeration<JarEntry> entries = jarFile.entries();
|
||||
|
||||
final String absLocation = baseLocation + "/" + location + "/";
|
||||
final int absLength = absLocation.length();
|
||||
|
||||
ArrayList<Resource> resources = new ArrayList<>();
|
||||
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
String name = entry.getName();
|
||||
if (name.startsWith(absLocation) && name.length() != absLocation.length()) {
|
||||
resources.add(new CallbackResource(Util.pathToId(id, name.substring(absLength)), () -> classLoader.getResourceAsStream(name)));
|
||||
}
|
||||
}
|
||||
return resources.stream();
|
||||
}
|
||||
}
|
||||
} catch (IOException | URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Resource getResource(@NotNull String location) {
|
||||
try {
|
||||
URL url = classLoader.getResource(baseLocation + "/" + location);
|
||||
if (url != null) {
|
||||
if ("file".equals(url.getProtocol())) {
|
||||
return new FileResource(Util.pathToId(id, location), new File(url.toURI()));
|
||||
} else if ("jar".equals(url.getProtocol())) {
|
||||
return new CallbackResource(Util.pathToId(id, location), () -> classLoader.getResourceAsStream(baseLocation + "/" + location));
|
||||
}
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
14
src/main/java/de/siphalor/was/content/product/Product.java
Normal file
14
src/main/java/de/siphalor/was/content/product/Product.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package de.siphalor.was.content.product;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface Product {
|
||||
@NotNull
|
||||
String getPropertySpecifier();
|
||||
|
||||
int getDepth();
|
||||
boolean testY(int y);
|
||||
|
||||
@NotNull
|
||||
ProductType<?> getType();
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package de.siphalor.was.content.product;
|
||||
|
||||
import de.siphalor.was.content.ContentManager;
|
||||
import de.siphalor.was.util.ResourceManager;
|
||||
import de.siphalor.was.content.product.dynamic.DynamicProductType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ProductManager implements ResourceManager<ProductType<?>> {
|
||||
private final Map<String, ProductType<?>> productTypes = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
productTypes.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(@NotNull ContentManager contentManager) {
|
||||
contentManager.getResources("products", "properties").forEach(resource -> {
|
||||
InputStream inputStream = resource.getInputStream();
|
||||
if (inputStream != null) {
|
||||
productTypes.put(resource.getId(), DynamicProductType.from(inputStream));
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProductType<?> get(String id) {
|
||||
return productTypes.get(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package de.siphalor.was.content.product;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public abstract class ProductType<T extends Product> {
|
||||
|
||||
public ProductType() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public abstract T getProduct(String[] values);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package de.siphalor.was.content.product.dynamic;
|
||||
|
||||
import de.siphalor.was.content.product.Product;
|
||||
import de.siphalor.was.content.product.ProductType;
|
||||
import de.siphalor.was.util.Util;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.function.IntPredicate;
|
||||
|
||||
public class DynamicProduct implements Product {
|
||||
private ProductType<?> type;
|
||||
private final String[] properties;
|
||||
private int depth = 1;
|
||||
@NotNull
|
||||
private IntPredicate yPredicate = Util.dummyIntPredicate();
|
||||
|
||||
public DynamicProduct(String[] properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getPropertySpecifier() {
|
||||
return String.join("_", properties);
|
||||
}
|
||||
|
||||
public void setDepth(int depth) {
|
||||
this.depth = depth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDepth() {
|
||||
return depth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testY(int y) {
|
||||
return yPredicate.test(y);
|
||||
}
|
||||
|
||||
// This function exists to resolve the circular references of ProductType <-> Product on creation
|
||||
void setType(ProductType<?> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ProductType<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setYPredicate(@NotNull IntPredicate yPredicate) {
|
||||
this.yPredicate = yPredicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DynamicProduct{" +
|
||||
"properties=" + Arrays.toString(properties) +
|
||||
", depth=" + depth +
|
||||
", yPredicate=" + yPredicate +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package de.siphalor.was.content.product.dynamic;
|
||||
|
||||
import de.siphalor.was.content.product.ProductType;
|
||||
import de.siphalor.was.util.Util;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
import java.util.function.IntPredicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DynamicProductType extends ProductType<DynamicProduct> {
|
||||
private final Map<String, DynamicProduct> variations;
|
||||
private final String[] properties;
|
||||
|
||||
public DynamicProductType(List<DynamicProduct> variations, String[] properties) {
|
||||
this.variations = new HashMap<>();
|
||||
variations.forEach(p -> {
|
||||
p.setType(this);
|
||||
this.variations.put(p.getPropertySpecifier(), p);
|
||||
});
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DynamicProductType from(@NotNull InputStream inputStream) {
|
||||
Properties propertiesFile = new Properties();
|
||||
|
||||
try {
|
||||
propertiesFile.load(inputStream);
|
||||
|
||||
String[] propNames = ((String) propertiesFile.get("properties")).split(",");
|
||||
|
||||
if (propNames.length > 0) {
|
||||
// propNameList = propNames without blank elements & all elements trimmed
|
||||
List<String> propNameList = new ArrayList<>(propNames.length);
|
||||
List<List<ProductPrototype>> properties = new ArrayList<>(propNames.length);
|
||||
for (String propName : propNames) {
|
||||
propName = propName.trim();
|
||||
if (propName.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
propNameList.add(propName);
|
||||
if (propertiesFile.containsKey(propName + ".variants")) {
|
||||
String[] variants = ((String) propertiesFile.get(propName + ".variants")).split(",");
|
||||
List<ProductPrototype> propertyVariants = new ArrayList<>(variants.length);
|
||||
for (String variant : variants) {
|
||||
variant = variant.trim();
|
||||
propertyVariants.add(makePrototype(propertiesFile, propName, variant));
|
||||
}
|
||||
properties.add(propertyVariants);
|
||||
} else {
|
||||
// if there are no variants assume true/false flag
|
||||
properties.add(List.of(
|
||||
makePrototype(propertiesFile, propName, "true"),
|
||||
makePrototype(propertiesFile, propName, "false")
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
List<ProductPrototype> prototypes = properties.stream().reduce((pts1, pts2) -> {
|
||||
return pts1.stream().flatMap(pt -> {
|
||||
return pts2.stream().map(pt::combine);
|
||||
}).collect(Collectors.toList());
|
||||
}).get();
|
||||
|
||||
List<DynamicProduct> products = prototypes.stream().map(pt -> {
|
||||
DynamicProduct product = new DynamicProduct(pt.value.split(";"));
|
||||
pt.apply(product);
|
||||
return product;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
return new DynamicProductType(products, propNameList.toArray(String[]::new));
|
||||
}
|
||||
} catch (IOException | NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return new DynamicProductType(List.of(new DynamicProduct(Util.emptyArray())), Util.emptyArray());
|
||||
}
|
||||
|
||||
private static ProductPrototype makePrototype(Properties propertiesFile, String property, String variant) {
|
||||
ProductPrototype prototype = new ProductPrototype(variant);
|
||||
String base = property + "." + variant + ".";
|
||||
if (propertiesFile.containsKey(base + "depth")) {
|
||||
prototype.depth = Integer.parseInt((String) propertiesFile.get(base + "depth"));
|
||||
}
|
||||
if (propertiesFile.containsKey(base + "y")) {
|
||||
String val = (String) propertiesFile.get(base + "y");
|
||||
switch (val.charAt(0)) {
|
||||
case '>': {
|
||||
int i = Integer.parseInt(val.substring(1));
|
||||
prototype.yPredicate = value -> value > i;
|
||||
break;
|
||||
}
|
||||
case '<': {
|
||||
int i = Integer.parseInt(val.substring(1));
|
||||
prototype.yPredicate = value -> value < i;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
int i = Integer.parseInt(val);
|
||||
prototype.yPredicate = value -> value == i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return prototype;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicProduct getProduct(String[] values) {
|
||||
return variations.get(String.join("_", values));
|
||||
}
|
||||
|
||||
private static class ProductPrototype {
|
||||
String value;
|
||||
|
||||
Integer depth = null;
|
||||
IntPredicate yPredicate = null;
|
||||
|
||||
public ProductPrototype(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void apply(DynamicProduct product) {
|
||||
if (depth != null)
|
||||
product.setDepth(depth);
|
||||
if (yPredicate != null)
|
||||
product.setYPredicate(yPredicate);
|
||||
}
|
||||
|
||||
public ProductPrototype combine(ProductPrototype prototype) {
|
||||
ProductPrototype result = new ProductPrototype(value + ";" + prototype.value);
|
||||
if (prototype.depth != null)
|
||||
result.depth = prototype.depth;
|
||||
else
|
||||
result.depth = depth;
|
||||
if (result.yPredicate != null)
|
||||
result.yPredicate = prototype.yPredicate;
|
||||
else
|
||||
result.yPredicate = yPredicate;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DynamicProductType{" +
|
||||
"properties=" + String.join(" & ", properties) +
|
||||
", variations=\n" + variations.values().stream().map(Object::toString).collect(Collectors.joining(System.lineSeparator())) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
36
src/main/java/de/siphalor/was/content/quest/Quest.java
Normal file
36
src/main/java/de/siphalor/was/content/quest/Quest.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package de.siphalor.was.content.quest;
|
||||
|
||||
import de.siphalor.was.content.product.Product;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class Quest {
|
||||
@NotNull
|
||||
private final Type type;
|
||||
private final int reward;
|
||||
@NotNull
|
||||
private final Product product;
|
||||
|
||||
public Quest(@NotNull Type type, int reward, @NotNull Product product) {
|
||||
this.product = product;
|
||||
this.reward = reward;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Product getProduct() {
|
||||
return product;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getReward() {
|
||||
return reward;
|
||||
}
|
||||
|
||||
enum Type {
|
||||
IN, OUT
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package de.siphalor.was.content.quest;
|
||||
|
||||
public interface QuestGenerator {
|
||||
/**
|
||||
* Restarts this generator
|
||||
*/
|
||||
void restart();
|
||||
|
||||
/**
|
||||
* Returns the next {@link Quest} but doesn't advance
|
||||
* @return the next {@link Quest}
|
||||
* @see QuestGenerator#next()
|
||||
*/
|
||||
Quest peek();
|
||||
|
||||
/**
|
||||
* Returns the next {@link Quest} and advances
|
||||
* @return the next {@link Quest}
|
||||
* @see QuestGenerator#peek()
|
||||
*/
|
||||
Quest next();
|
||||
|
||||
/**
|
||||
* Returns whether another {@link Quest} can be generated
|
||||
* @return whether the generator is at its end
|
||||
* @see QuestGenerator#restart()
|
||||
*/
|
||||
boolean hasNext();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package de.siphalor.was.content.quest;
|
||||
|
||||
import de.siphalor.was.WhatAStorage;
|
||||
import de.siphalor.was.content.ContentManager;
|
||||
import de.siphalor.was.util.ResourceManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class QuestManager implements ResourceManager<QuestGenerator> {
|
||||
private final Map<String, QuestGenerator> questGenerators = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
questGenerators.clear();
|
||||
}
|
||||
|
||||
public void reload(@NotNull ContentManager contentManager) {
|
||||
contentManager.getResources("quests", "csv").forEach(resource -> {
|
||||
InputStream inputStream = resource.getInputStream();
|
||||
if (inputStream != null) {
|
||||
questGenerators.put(resource.getId(), StaticQuestGenerator.fromCsv(inputStream, WhatAStorage.getInstance().getProductManager()));
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public QuestGenerator get(String id) {
|
||||
return questGenerators.get(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package de.siphalor.was.content.quest;
|
||||
|
||||
import de.siphalor.was.content.product.Product;
|
||||
import de.siphalor.was.content.product.ProductManager;
|
||||
import de.siphalor.was.content.product.ProductType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class StaticQuestGenerator implements QuestGenerator {
|
||||
@NotNull
|
||||
private final List<Quest> quests;
|
||||
private int index = 0;
|
||||
|
||||
public StaticQuestGenerator(@NotNull List<Quest> quests) {
|
||||
this.quests = quests;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static StaticQuestGenerator fromCsv(@NotNull InputStream inputStream, @NotNull ProductManager productManager) {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
String line;
|
||||
|
||||
List<Quest> quests = new ArrayList<>();
|
||||
|
||||
try {
|
||||
while ((line = reader.readLine()) != null) {
|
||||
try {
|
||||
String[] parts = line.split(",");
|
||||
if (parts.length >= 3) {
|
||||
Quest.Type type = Quest.Type.valueOf(parts[0].toUpperCase(Locale.ENGLISH));
|
||||
ProductType<?> productType = productManager.get(parts[1]);
|
||||
if (productType != null) {
|
||||
int reward = Integer.parseInt(parts[2]);
|
||||
|
||||
Product product = productType.getProduct(Arrays.copyOfRange(parts, 3, parts.length));
|
||||
|
||||
if (product != null) {
|
||||
quests.add(new Quest(type, reward, product));
|
||||
} else {
|
||||
System.out.println("Invalid product in quest: " + line);
|
||||
}
|
||||
} else {
|
||||
System.out.println("Invalid product in quest: " + parts[2]);
|
||||
}
|
||||
} else {
|
||||
System.out.println("Invalid line in quests file: " + line);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Failed to load quest in csv file in line: " + line);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return new StaticQuestGenerator(quests);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Failed to load quest csv file:");
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restart() {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Quest peek() {
|
||||
return quests.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Quest next() {
|
||||
return quests.get(index++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return index < quests.size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package de.siphalor.was.content.resource;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class CallbackResource extends Resource {
|
||||
Supplier<InputStream> supplier;
|
||||
|
||||
public CallbackResource(String id, Supplier<InputStream> supplier) {
|
||||
super(id);
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable InputStream getInputStream() {
|
||||
return supplier.get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package de.siphalor.was.content.resource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class FileResource extends Resource {
|
||||
private final File file;
|
||||
|
||||
public FileResource(String id, File file) {
|
||||
super(id);
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
try {
|
||||
return new FileInputStream(file);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/main/java/de/siphalor/was/content/resource/Resource.java
Normal file
20
src/main/java/de/siphalor/was/content/resource/Resource.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package de.siphalor.was.content.resource;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public abstract class Resource {
|
||||
private final String id;
|
||||
|
||||
protected Resource(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public abstract InputStream getInputStream();
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
5
src/main/java/de/siphalor/was/game/Storage.java
Normal file
5
src/main/java/de/siphalor/was/game/Storage.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package de.siphalor.was.game;
|
||||
|
||||
public class Storage {
|
||||
|
||||
}
|
||||
35
src/main/java/de/siphalor/was/state/GameState.java
Normal file
35
src/main/java/de/siphalor/was/state/GameState.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package de.siphalor.was.state;
|
||||
|
||||
import de.siphalor.was.assets.AssetsManager;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class GameState extends State {
|
||||
private BufferedImage main;
|
||||
|
||||
public GameState(int width, int height) {
|
||||
super(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics graphics) {
|
||||
graphics.drawImage(main, 0, 0, getWidth(), getHeight(), (img, infoflags, x, y, width, height) -> false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResize(int width, int height) {
|
||||
super.onResize(width, height);
|
||||
main = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
redrawBg(main.getGraphics());
|
||||
}
|
||||
|
||||
public void redrawBg(Graphics graphics) {
|
||||
graphics.drawImage(AssetsManager.getImage("assets/menu/bg.png"), 0, 0, getWidth(), getHeight(), (img, infoflags, x, y, width, height) -> false);
|
||||
}
|
||||
}
|
||||
31
src/main/java/de/siphalor/was/state/MainMenuState.java
Normal file
31
src/main/java/de/siphalor/was/state/MainMenuState.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package de.siphalor.was.state;
|
||||
|
||||
import de.siphalor.was.assets.AssetsManager;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public class MainMenuState extends State {
|
||||
private boolean bgDirty = true;
|
||||
|
||||
public MainMenuState(int width, int height) {
|
||||
super(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics graphics) {
|
||||
if (bgDirty) {
|
||||
graphics.drawImage(AssetsManager.getImage("assets/bg.png"), 0, 0, getWidth() - 1, getHeight() - 1, (img, infoflags, x, y, width, height) -> false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResize(int width, int height) {
|
||||
super.onResize(width, height);
|
||||
bgDirty = true;
|
||||
}
|
||||
}
|
||||
37
src/main/java/de/siphalor/was/state/State.java
Normal file
37
src/main/java/de/siphalor/was/state/State.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package de.siphalor.was.state;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public abstract class State {
|
||||
private int width, height;
|
||||
|
||||
public State(int width, int height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
onResize(width, height);
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void enter() {
|
||||
|
||||
}
|
||||
|
||||
public void leave() {
|
||||
|
||||
}
|
||||
|
||||
public abstract void tick();
|
||||
public abstract void render(Graphics graphics);
|
||||
|
||||
public void onResize(int width, int height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
39
src/main/java/de/siphalor/was/util/Pair.java
Normal file
39
src/main/java/de/siphalor/was/util/Pair.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package de.siphalor.was.util;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Pair<A, B> {
|
||||
private final A first;
|
||||
private final B second;
|
||||
|
||||
public static <A, B> Pair<A, B> of(A first, B second) {
|
||||
return new Pair<>(first, second);
|
||||
}
|
||||
|
||||
public Pair(A first, B second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public A getFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
public B getSecond() {
|
||||
return second;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Pair<?, ?> pair = (Pair<?, ?>) o;
|
||||
return Objects.equals(first, pair.first) &&
|
||||
Objects.equals(second, pair.second);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(first, second);
|
||||
}
|
||||
}
|
||||
11
src/main/java/de/siphalor/was/util/ResourceManager.java
Normal file
11
src/main/java/de/siphalor/was/util/ResourceManager.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package de.siphalor.was.util;
|
||||
|
||||
import de.siphalor.was.content.ContentManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface ResourceManager<T> {
|
||||
void clear();
|
||||
void reload(@NotNull ContentManager contentManager);
|
||||
|
||||
T get(String id);
|
||||
}
|
||||
37
src/main/java/de/siphalor/was/util/Util.java
Normal file
37
src/main/java/de/siphalor/was/util/Util.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package de.siphalor.was.util;
|
||||
|
||||
import java.util.function.IntPredicate;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class Util {
|
||||
private static final Predicate<?> DUMMY_PREDICATE = o -> true;
|
||||
private static final IntPredicate DUMMY_INT_PREDICATE = value -> true;
|
||||
|
||||
private static final Object[] EMPTY_ARRAY = new Object[0];
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Predicate<T> dummyPredicate() {
|
||||
return (Predicate<T>) DUMMY_PREDICATE;
|
||||
}
|
||||
|
||||
public static IntPredicate dummyIntPredicate() {
|
||||
return DUMMY_INT_PREDICATE;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T[] emptyArray() {
|
||||
return (T[]) EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
public static String pathToId(String packId, String path) {
|
||||
int dot = path.lastIndexOf('.');
|
||||
if (dot >= 0) {
|
||||
path = path.substring(0, dot);
|
||||
}
|
||||
path = path.replace('/', '.').replace('\\', '.');
|
||||
if (packId.isEmpty()) {
|
||||
return path;
|
||||
}
|
||||
return packId + "." + path;
|
||||
}
|
||||
}
|
||||
BIN
src/main/resources/assets/missingno.png
Normal file
BIN
src/main/resources/assets/missingno.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 342 B |
34
src/main/resources/content/lang/en_us.lang
Normal file
34
src/main/resources/content/lang/en_us.lang
Normal file
@@ -0,0 +1,34 @@
|
||||
test.hello-world = Hello World!
|
||||
|
||||
quests.normal = Normal
|
||||
|
||||
products.paper = Paper
|
||||
products.paper.color = Color
|
||||
products.paper.color.green = Green
|
||||
products.paper.color.blue = Blue
|
||||
products.paper.color.white = White
|
||||
# These paper formats are not equivalent but at least kind of similar in the amount they're used
|
||||
products.paper.format = Format
|
||||
products.paper.format.a3 = Ledger
|
||||
products.paper.format.a4 = Legal
|
||||
products.paper.format.a5 = Letter
|
||||
|
||||
products.wood = Wood
|
||||
products.wood.type = Type
|
||||
products.wood.type.beech = Beech
|
||||
products.wood.type.oak = Oak
|
||||
products.wood.type.pine = Pine
|
||||
products.wood.form = Form
|
||||
products.wood.form.pieces = Pieces
|
||||
products.wood.form.boards = Boards
|
||||
products.wood.form.beams = Beams
|
||||
|
||||
products.stone = Stone
|
||||
products.stone.type = Type
|
||||
products.stone.type.granite = Granite
|
||||
products.stone.type.marble = Marble
|
||||
products.stone.type.sandstone = Sandstone
|
||||
products.stone.weight = Weight
|
||||
products.stone.weight.light = Light
|
||||
products.stone.weight.medium = Medium
|
||||
products.stone.weight.heavy = Heavy
|
||||
3
src/main/resources/content/products/paper.properties
Normal file
3
src/main/resources/content/products/paper.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
properties = color, format
|
||||
color.variants =white, green, blue
|
||||
format.variants = a3, a4, a5
|
||||
4
src/main/resources/content/products/stone.properties
Normal file
4
src/main/resources/content/products/stone.properties
Normal file
@@ -0,0 +1,4 @@
|
||||
properties = type, weight
|
||||
type.variants = marble, granite, sandstone
|
||||
weight.variants = light, medium, heavy
|
||||
weight.heavy.y = 1
|
||||
4
src/main/resources/content/products/wood.properties
Normal file
4
src/main/resources/content/products/wood.properties
Normal file
@@ -0,0 +1,4 @@
|
||||
properties = type, form
|
||||
type.variants = pine, beech, oak
|
||||
form.variants = boards, pieces, beams
|
||||
form.beams.depth = 3
|
||||
47
src/main/resources/content/quests/normal.csv
Normal file
47
src/main/resources/content/quests/normal.csv
Normal file
@@ -0,0 +1,47 @@
|
||||
in,paper,200,white,a4
|
||||
in,paper,300,blue,a5
|
||||
in,wood,200,pine,boards
|
||||
in,wood,500,beech,beams
|
||||
in,wood,200,oak,pieces
|
||||
in,paper,200,blue,a5
|
||||
in,paper,200,blue,a5
|
||||
in,stone,400,marble,medium
|
||||
in,stone,500,granite,heavy
|
||||
in,stone,200,sandstone,light
|
||||
out,paper,1000,blue,a5
|
||||
out,wood,1200,oak,pieces
|
||||
out,stone,1000,marble,medium
|
||||
out,paper,1500,white,a5
|
||||
in,wood,400,oak,beams
|
||||
in,wood,600,oak,pieces
|
||||
in,wood,200,beech,pieces
|
||||
in,stone,400,granite,light
|
||||
in,paper,200,blue,a3
|
||||
in,paper,200,blue,a5
|
||||
in,wood,600,oak,pieces
|
||||
in,wood,600,beech,beams
|
||||
in,stone,200,sandstone,heavy
|
||||
in,stone,600,granite,heavy
|
||||
in,wood,400,beech,boards
|
||||
in,wood,200,beech,pieces
|
||||
out,wood,1000,beech,pieces
|
||||
out,paper,1200,blue,a5
|
||||
out,stone,1500,granite,heavy
|
||||
out,wood,1000,beech,beams
|
||||
out,stone,1300,sandstone,heavy
|
||||
in,stone,400,granite,heavy
|
||||
in,stone,600,marble,medium
|
||||
in,stone,400,granite,light
|
||||
in,stone,400,granite,light
|
||||
in,paper,400,white,a4
|
||||
in,stone,400,granite,light
|
||||
in,wood,600,beech,boards
|
||||
in,wood,600,pine,boards
|
||||
in,stone,400,sandstone,light
|
||||
out,paper,1000,white,a4
|
||||
out,stone,1200,marble,medium
|
||||
out,wood,1100,beech,boards
|
||||
out,paper,1500,white,a4
|
||||
out,wood,1000,pine,boards
|
||||
out,stone,1200,sandstone,light
|
||||
out,wood,1100,pine,boards
|
||||
|
2
src/test/java/Tests.java
Normal file
2
src/test/java/Tests.java
Normal file
@@ -0,0 +1,2 @@
|
||||
public class Tests {
|
||||
}
|
||||
Reference in New Issue
Block a user