The whole logic documentation
This commit is contained in:
@@ -7,7 +7,14 @@ import de.siphalor.was.visual.JFXVisual;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* The main entry point class
|
||||
*/
|
||||
public class Start {
|
||||
/**
|
||||
* The main program entry point
|
||||
* @param args The args given from the console
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
WhatAStorage was = WhatAStorage.getInstance();
|
||||
was.reload();
|
||||
|
||||
@@ -26,33 +26,88 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* The main game class. This is a singleton class.
|
||||
*/
|
||||
public class WhatAStorage {
|
||||
/**
|
||||
* The maximum number of quests at a time
|
||||
*/
|
||||
private static final int MAX_QUESTS = 3;
|
||||
/**
|
||||
* The size of the storage grid
|
||||
*/
|
||||
private static final int GRID_SIZE = 3;
|
||||
|
||||
/**
|
||||
* The window title
|
||||
*/
|
||||
public static final String TITLE = "What a Storage";
|
||||
/**
|
||||
* The singleton instance
|
||||
*/
|
||||
private static final WhatAStorage INSTANCE = new WhatAStorage();
|
||||
|
||||
/**
|
||||
* Gets the singleton instance.
|
||||
* @return The instance
|
||||
*/
|
||||
public static WhatAStorage getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main content manager
|
||||
*/
|
||||
private final ContentManager contentManager;
|
||||
/**
|
||||
* The internal content pack
|
||||
*/
|
||||
private final JarContentPack mainPack;
|
||||
/**
|
||||
* The main product manager
|
||||
*/
|
||||
private final ProductManager productManager;
|
||||
/**
|
||||
* The main quest manager
|
||||
*/
|
||||
private final QuestManager questManager;
|
||||
|
||||
/**
|
||||
* The game's options
|
||||
*/
|
||||
private final Options options;
|
||||
|
||||
/**
|
||||
* The used visual
|
||||
*/
|
||||
private Visual visual;
|
||||
|
||||
/**
|
||||
* Whether the game has been requested to stop
|
||||
*/
|
||||
private boolean stopScheduled;
|
||||
|
||||
/**
|
||||
* The current balance
|
||||
*/
|
||||
private Balance balance;
|
||||
/**
|
||||
* The current quest generator
|
||||
*/
|
||||
private QuestGenerator questGenerator;
|
||||
/**
|
||||
* The current quest list
|
||||
*/
|
||||
private final List<Quest> quests = new ArrayList<>(MAX_QUESTS);
|
||||
/**
|
||||
* The current storage
|
||||
*/
|
||||
private Storage storage;
|
||||
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
*/
|
||||
private WhatAStorage() {
|
||||
contentManager = new ContentManager();
|
||||
mainPack = new JarContentPack("", "content");
|
||||
@@ -62,26 +117,49 @@ public class WhatAStorage {
|
||||
options = new Options();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visual to use. <b>Must be called before {@link WhatAStorage#setup()}</b>
|
||||
* @param visual The visual to use
|
||||
*/
|
||||
public void setVisual(Visual visual) {
|
||||
this.visual = visual;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the content manager.
|
||||
* @return The content manager
|
||||
*/
|
||||
public ContentManager getContentManager() {
|
||||
return contentManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the product manager.
|
||||
* @return The product manager
|
||||
*/
|
||||
public ProductManager getProductManager() {
|
||||
return productManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the quest manager.
|
||||
* @return The quest manager
|
||||
*/
|
||||
public QuestManager getQuestManager() {
|
||||
return questManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the game's options
|
||||
* @return The game's options
|
||||
*/
|
||||
public Options getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads all resources from the packs.
|
||||
*/
|
||||
public void reload() {
|
||||
contentManager.clear();
|
||||
|
||||
@@ -105,6 +183,9 @@ public class WhatAStorage {
|
||||
Util.LOGGER.log(Level.INFO, "Reloaded game content");
|
||||
}
|
||||
|
||||
/**
|
||||
* Setups the game.
|
||||
*/
|
||||
public void setup() {
|
||||
if (visual == null) {
|
||||
throw new IllegalStateException("No visual set for WhatAStorage!");
|
||||
@@ -112,10 +193,16 @@ public class WhatAStorage {
|
||||
visual.setup(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the game. Hands over control to the visual.
|
||||
*/
|
||||
public void run() {
|
||||
visual.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a new game.
|
||||
*/
|
||||
public void startGame() {
|
||||
//questGenerator = questManager.get("example.test");
|
||||
questGenerator = new RandomQuestGenerator();
|
||||
@@ -132,19 +219,27 @@ public class WhatAStorage {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a game stop.
|
||||
*/
|
||||
public void scheduleStop() {
|
||||
stopScheduled = true;
|
||||
visual.onScheduleStop();
|
||||
}
|
||||
|
||||
public boolean isStopScheduled() {
|
||||
return stopScheduled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the balance.
|
||||
* @return The balance
|
||||
*/
|
||||
public Balance getBalance() {
|
||||
return balance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all available language codes.
|
||||
* @return The language codes.
|
||||
*/
|
||||
@NotNull
|
||||
public String[] getLangs() {
|
||||
return contentManager.getResources("lang", "properties").map(resource -> {
|
||||
int index = resource.getId().lastIndexOf('.');
|
||||
@@ -152,15 +247,27 @@ public class WhatAStorage {
|
||||
}).toArray(String[]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new transaction and propagate to the visual.
|
||||
* @param type The transaction type
|
||||
* @param change The money change
|
||||
* @param product The reference product if any
|
||||
*/
|
||||
private void addTransaction(@NotNull Transaction.Type type, int change, @Nullable Product product) {
|
||||
Transaction transaction = balance.add(type, change, product);
|
||||
visual.onBalanceChanged(balance.getBudget(), transaction, balance.getTotalIncome(), balance.getTotalLoss());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the language has been changed.
|
||||
*/
|
||||
public void invalidateI18n() {
|
||||
visual.invalidateI18n();
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the main visual data (storage and budget) should be resend to the visual.
|
||||
*/
|
||||
public void resendVisualGameData() {
|
||||
for (int x = 0; x < storage.getWidth(); x++) {
|
||||
for (int y = 0; y < storage.getHeight(); y++) {
|
||||
@@ -175,6 +282,10 @@ public class WhatAStorage {
|
||||
visual.onBalanceChanged(balance.getBudget(), new Transaction(Transaction.Type.NOOP, 0, ""), balance.getTotalIncome(), balance.getTotalLoss());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets and adds the next quest if possible.
|
||||
* @return Returns whether a quest has been added.
|
||||
*/
|
||||
private boolean nextQuest() {
|
||||
if (quests.size() >= MAX_QUESTS) return false;
|
||||
|
||||
@@ -189,10 +300,18 @@ public class WhatAStorage {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the user requested the next quest.
|
||||
* @return Returns whether a quest has been added
|
||||
*/
|
||||
public boolean userRequestQuest() {
|
||||
return nextQuest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the user abandoned a quest.
|
||||
* @param index The quest's index in the quest list
|
||||
*/
|
||||
public void userAbandonQuest(int index) {
|
||||
if (index >= quests.size()) {
|
||||
Util.LOGGER.log(Level.SEVERE, "Attempted to abandon non-existent quest!");
|
||||
@@ -207,18 +326,46 @@ public class WhatAStorage {
|
||||
if (options.getAutoRefillQuests()) nextQuest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a product can be stored at the given storage location.
|
||||
* @param product The product to check
|
||||
* @param x The storage x position
|
||||
* @param y The storage y position
|
||||
* @return Returns whether the product is legal at that position
|
||||
*/
|
||||
public boolean canStoreProduct(@Nullable Product product, int x, int y) {
|
||||
return product != null && storage.get(x, y).fits(product) && product.testY(y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a quest's product can be stored at the given storage location.
|
||||
* @param questIndex The quest's index in the quest list
|
||||
* @param x The storage x position
|
||||
* @param y The storage y position
|
||||
* @return Returns whether the operation is legal
|
||||
*/
|
||||
public boolean canStoreProduct(int questIndex, int x, int y) {
|
||||
return canStoreProduct(quests.get(questIndex).getProduct(), x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a product can be moved from one storage position to the other.
|
||||
* @param x1 The origin x position
|
||||
* @param y1 The origin y position
|
||||
* @param x2 The destination x position
|
||||
* @param y2 The destination y position
|
||||
* @return Returns whether the operation is legal
|
||||
*/
|
||||
public boolean canMoveProduct(int x1, int y1, int x2, int y2) {
|
||||
return canStoreProduct(storage.get(x1, y1).front(), x2, y2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the user wants to store a quest's product.
|
||||
* @param questIndex The quest's index in the quest list
|
||||
* @param x The storage x position
|
||||
* @param y The storage y position
|
||||
*/
|
||||
public void userStoreProduct(int questIndex, int x, int y) {
|
||||
Quest quest = quests.get(questIndex);
|
||||
if (quest != null && quest.getType() == Quest.Type.IN) {
|
||||
@@ -236,6 +383,13 @@ public class WhatAStorage {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a product can fulfill a quest.
|
||||
* @param questIndex The quest's index in the quest list
|
||||
* @param x The storage x position of the product origin
|
||||
* @param y The storage y position of the product origin
|
||||
* @return Returns whether the operation is legal
|
||||
*/
|
||||
public boolean canDeliverProduct(int questIndex, int x, int y) {
|
||||
Quest quest = quests.get(questIndex);
|
||||
if (quest != null && quest.getType() == Quest.Type.OUT) {
|
||||
@@ -244,6 +398,13 @@ public class WhatAStorage {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that that the user wants to deliver a product
|
||||
* @param questIndex The quest's index in the quest list
|
||||
* @param x The storage x position of the product origin
|
||||
* @param y The storage y position of the product origin
|
||||
* @return Returns whether the operation was successful
|
||||
*/
|
||||
public boolean userDeliverProduct(int questIndex, int x, int y) {
|
||||
if (canDeliverProduct(questIndex, x, y)) {
|
||||
Product product = storage.get(x, y).front();
|
||||
@@ -259,6 +420,12 @@ public class WhatAStorage {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether two quests can resolve against each other.
|
||||
* @param in The first quest's index in the quest list
|
||||
* @param out The first quest's index in the quest list
|
||||
* @return Returns whether the operation is legal
|
||||
*/
|
||||
public boolean canQuestsResolve(int in, int out) {
|
||||
int s = quests.size();
|
||||
if (in < s && in >= 0 && out < s && out >= 0) {
|
||||
@@ -270,6 +437,12 @@ public class WhatAStorage {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the user wants to resolve two quests.
|
||||
* @param in The first quest's index in the quest list
|
||||
* @param out The first quest's index in the quest list
|
||||
* @return Returns whether the operation was successful
|
||||
*/
|
||||
public boolean userResolveQuests(int in, int out) {
|
||||
if (options.getAllowQuestResolving()) {
|
||||
int s = quests.size();
|
||||
@@ -298,6 +471,13 @@ public class WhatAStorage {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the user want to move a product.
|
||||
* @param x1 The origin x position
|
||||
* @param y1 The origin y position
|
||||
* @param x2 The destination x position
|
||||
* @param y2 The destination y position
|
||||
*/
|
||||
public void userMoveProduct(int x1, int y1, int x2, int y2) {
|
||||
Product product = storage.get(x1, y1).front();
|
||||
if (product != null && product.testY(y2)) {
|
||||
@@ -312,6 +492,11 @@ public class WhatAStorage {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the user wants to destroy a product.
|
||||
* @param x The storage x position
|
||||
* @param y The storage y position
|
||||
*/
|
||||
public void userDestroyProduct(int x, int y) {
|
||||
Product product = storage.get(x, y).front();
|
||||
int z = storage.get(x, y).pop();
|
||||
|
||||
@@ -6,13 +6,26 @@ import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* This class controls the game's assets. Assets are all the file in the assets package in the jar. It can mostly be safely assumed that the certain asset files exist.
|
||||
*/
|
||||
public class AssetsManager {
|
||||
|
||||
/**
|
||||
* Returns a new InputStream to the requested asset.
|
||||
* @param path The path beginning from the <code>assets</code> package
|
||||
* @return An optional with the input stream if the asset exists
|
||||
*/
|
||||
@NotNull
|
||||
public static Optional<InputStream> getStream(@NotNull String path) {
|
||||
return Optional.ofNullable(Thread.currentThread().getContextClassLoader().getResourceAsStream("assets/" + path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an URL to the requested asset.
|
||||
* @param path The path beginning from the <code>assets</code> package
|
||||
* @return An optional with the url if the asset exists
|
||||
*/
|
||||
@NotNull
|
||||
public static Optional<URL> getURL(@NotNull String path) {
|
||||
return Optional.ofNullable(Thread.currentThread().getContextClassLoader().getResource(path));
|
||||
|
||||
@@ -10,34 +10,66 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* The main manager that for holding and accessing resources in {@link ContentPack}s.
|
||||
*/
|
||||
public class ContentManager {
|
||||
/**
|
||||
* All contained content packs
|
||||
*/
|
||||
private final List<ContentPack> packs = new LinkedList<>();
|
||||
|
||||
/**
|
||||
* Constructs a new, empty content manager.
|
||||
*/
|
||||
public ContentManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Forgets all known content packs.
|
||||
*/
|
||||
public void clear() {
|
||||
packs.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new content pack to this manager.
|
||||
* @param pack The pack to add
|
||||
*/
|
||||
public void addPack(ContentPack pack) {
|
||||
packs.add(pack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all contained content packs.
|
||||
* @return A collection of all packs
|
||||
*/
|
||||
public Collection<ContentPack> getPacks() {
|
||||
return packs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all resources that exist in all content packs in the given location with the given extension. Finds nested resources.
|
||||
* @param location The base location where to find resources in
|
||||
* @param type The file extension to look for (without the dot)
|
||||
* @return A stream of all matching resources
|
||||
*/
|
||||
@NotNull
|
||||
public Stream<Resource> getResources(@NotNull String location, @NotNull String type) {
|
||||
return packs.stream().flatMap(pack -> pack.getResources(location, type)).distinct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first resource with the given identifier.
|
||||
* @param identifier The resource identifier
|
||||
* @return The found resource or empty if none of the packs contains such a resource
|
||||
* @see ContentManager#getAllOfResource(String)
|
||||
*/
|
||||
@NotNull
|
||||
public Optional<Resource> getResource(@NotNull String location) {
|
||||
public Optional<Resource> getResource(@NotNull String identifier) {
|
||||
Resource resource;
|
||||
for (ContentPack pack : packs) {
|
||||
resource = pack.getResource(location);
|
||||
resource = pack.getResource(identifier);
|
||||
if (resource != null) {
|
||||
return Optional.of(resource);
|
||||
}
|
||||
@@ -45,8 +77,14 @@ public class ContentManager {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all resources with the given identifier in the content packs.
|
||||
* @param identifier The resource identifier to look for
|
||||
* @return A stream of all those resources
|
||||
* @see ContentManager#getResource(String)
|
||||
*/
|
||||
@NotNull
|
||||
public Stream<Resource> getAllOfResource(@NotNull String location) {
|
||||
return packs.stream().flatMap(pack -> Stream.ofNullable(pack.getResource(location)));
|
||||
public Stream<Resource> getAllOfResource(@NotNull String identifier) {
|
||||
return packs.stream().flatMap(pack -> Stream.ofNullable(pack.getResource(identifier)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,26 +6,55 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A singleton class handling all of the translation actions and the currently active language with a fallback language
|
||||
*/
|
||||
public class I18n extends ResourceBundle {
|
||||
/**
|
||||
* The language code of the fallback language
|
||||
*/
|
||||
public static final String DEFAULT = "en_us";
|
||||
|
||||
/**
|
||||
* The fallback language
|
||||
*/
|
||||
private final Lang DEFAULT_LANG = new Lang(DEFAULT);
|
||||
|
||||
/**
|
||||
* The class' instance
|
||||
*/
|
||||
private static final I18n INSTANCE = new I18n();
|
||||
|
||||
/**
|
||||
* Gets the singleton instance
|
||||
* @return the singleton instance
|
||||
*/
|
||||
public static I18n getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* the current language
|
||||
*/
|
||||
@Nullable
|
||||
private Lang lang;
|
||||
|
||||
/**
|
||||
* Returns the current language
|
||||
* @return the currently selected language or the fallback
|
||||
*/
|
||||
public Lang getLang() {
|
||||
if (lang != null)
|
||||
return lang;
|
||||
return DEFAULT_LANG;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current language to the language identified by <code>code</code>. It loads the language using the given {@link ContentManager}
|
||||
* @param code The language's identification code
|
||||
* @param contentManager The content manager to use
|
||||
* @return Returns whether the language was updated
|
||||
*/
|
||||
public boolean setLang(@NotNull String code, @NotNull ContentManager contentManager) {
|
||||
if (lang == null || !lang.getCode().equals(code)) {
|
||||
Lang l = new Lang(code);
|
||||
@@ -37,6 +66,10 @@ public class I18n extends ResourceBundle {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the current and the fallback language language using the given content manager.
|
||||
* @param contentManager The content manager to use
|
||||
*/
|
||||
public void reload(@NotNull ContentManager contentManager) {
|
||||
DEFAULT_LANG.load(contentManager);
|
||||
if (lang != null) {
|
||||
@@ -44,11 +77,22 @@ public class I18n extends ResourceBundle {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates and formats with the translation string.
|
||||
* @param key The translation key
|
||||
* @param args The arguments to use for formatting
|
||||
* @return The formatted string
|
||||
*/
|
||||
@NotNull
|
||||
public String format(@NotNull String key, @Nullable Object... args) {
|
||||
return String.format(getString(key), args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given data by the translation key.
|
||||
* @param key The translation key
|
||||
* @return The associated data or <code>null</code> if none
|
||||
*/
|
||||
@Override
|
||||
@NotNull
|
||||
protected Object handleGetObject(@NotNull String key) {
|
||||
@@ -68,6 +112,10 @@ public class I18n extends ResourceBundle {
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all valid keys existing in the current language or the fallback language.
|
||||
* @return An enumeration of all of these keys
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
public Enumeration<String> getKeys() {
|
||||
|
||||
@@ -11,19 +11,41 @@ import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* A class for holding a language's data
|
||||
*/
|
||||
public class Lang {
|
||||
/**
|
||||
* The language's data
|
||||
*/
|
||||
private final String code;
|
||||
/**
|
||||
* The internally used properties file
|
||||
*/
|
||||
private final Properties properties = new Properties();
|
||||
|
||||
/**
|
||||
* Constructs a new language by its identification code.
|
||||
* @param code The identifying code
|
||||
*/
|
||||
public Lang(@NotNull String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the language's code.
|
||||
* @return The identifying code for this language
|
||||
*/
|
||||
@NotNull
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the language's data using the given content manager.
|
||||
* @param contentManager The content manager to use
|
||||
* @return Returns whether the load was successful
|
||||
*/
|
||||
public boolean load(@NotNull ContentManager contentManager) {
|
||||
properties.clear();
|
||||
contentManager.getAllOfResource("lang/" + code + ".properties").forEachOrdered(resource -> {
|
||||
@@ -50,11 +72,20 @@ public class Lang {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the translation string
|
||||
* @param key The key for the translation
|
||||
* @return Returns the translation data
|
||||
*/
|
||||
@Nullable
|
||||
public String get(@NotNull String key) {
|
||||
return (String) properties.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all of the translation keys
|
||||
* @return Returns all of the translation keys
|
||||
*/
|
||||
@NotNull
|
||||
public Enumeration<String> getKeys() {
|
||||
// This is really ugly but we know™ that the keys will always be strings
|
||||
|
||||
@@ -6,11 +6,31 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* An interface for some kind of content pack
|
||||
*/
|
||||
public interface ContentPack {
|
||||
/**
|
||||
* Returns a stream to all of the resources in the given location and the given file extension. Search is performed recursively.
|
||||
* @param location The location to search
|
||||
* @param type The file extension
|
||||
* @return Returns a stream of all of the resources
|
||||
*/
|
||||
@NotNull
|
||||
Stream<Resource> getResources(@NotNull String location, @NotNull String type);
|
||||
|
||||
/**
|
||||
* Gets the resource with the specified identifier.
|
||||
* @param identifier
|
||||
* @return The resource or <code>null</code> if it doesn't exist
|
||||
*/
|
||||
@Nullable
|
||||
Resource getResource(@NotNull String location);
|
||||
Resource getResource(@NotNull String identifier);
|
||||
|
||||
/**
|
||||
* Returns the id of the content pack
|
||||
* @return The unique identifier
|
||||
*/
|
||||
@NotNull
|
||||
String getId();
|
||||
}
|
||||
|
||||
@@ -11,15 +11,35 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* An implementation of a {@link ContentPack} as a directory.
|
||||
*/
|
||||
public class FileContentPack implements ContentPack {
|
||||
/**
|
||||
* The pack's id
|
||||
*/
|
||||
private final String id;
|
||||
/**
|
||||
* The base path where the pack is located
|
||||
*/
|
||||
private final Path base;
|
||||
|
||||
/**
|
||||
* Constructs a new file content pack.
|
||||
* @param id The pack id
|
||||
* @param base The path to the pack directory
|
||||
*/
|
||||
public FileContentPack(@NotNull String id, @NotNull Path base) {
|
||||
this.id = id;
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all of the resources in the specified location with the specified type
|
||||
* @param location The location to search
|
||||
* @param type The file extension
|
||||
* @return Returns a stream of these resources
|
||||
*/
|
||||
@Override
|
||||
public @NotNull Stream<Resource> getResources(@NotNull String location, @NotNull String type) {
|
||||
final String extension = "." + type;
|
||||
@@ -36,15 +56,24 @@ public class FileContentPack implements ContentPack {
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a single file resource with the given identifier.
|
||||
* @param identifier The resource identifier
|
||||
* @return Returns the file resource or <code>null</code> if it doesn't exist
|
||||
*/
|
||||
@Override
|
||||
public Resource getResource(@NotNull String location) {
|
||||
File file = base.resolve(Path.of(location)).toFile();
|
||||
public Resource getResource(@NotNull String identifier) {
|
||||
File file = base.resolve(Path.of(identifier)).toFile();
|
||||
if (file.isFile()) {
|
||||
return new FileResource(Util.pathToId(id, location), file);
|
||||
return new FileResource(Util.pathToId(id, identifier), file);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pack's id
|
||||
* @return The pack's id
|
||||
*/
|
||||
@Override
|
||||
@NotNull
|
||||
public String getId() {
|
||||
|
||||
@@ -20,25 +20,58 @@ import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* An implementation for a {@link ContentPack} in a loaded jar file.
|
||||
*/
|
||||
public class JarContentPack implements ContentPack {
|
||||
/**
|
||||
* The pack's id
|
||||
*/
|
||||
private final String id;
|
||||
/**
|
||||
* The base package path
|
||||
*/
|
||||
private final String baseLocation;
|
||||
/**
|
||||
* The class loader that's used for resource loading
|
||||
*/
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
/**
|
||||
* Constructs a new jar content pack based at the root package with the current classloader.
|
||||
* @param id The pack's id
|
||||
*/
|
||||
public JarContentPack(String id) {
|
||||
this(id, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new jar content pack based at the given package with the current classloader.
|
||||
* @param id The pack's id
|
||||
* @param baseLocation The base package to load resources from
|
||||
*/
|
||||
public JarContentPack(String id, String baseLocation) {
|
||||
this(id, baseLocation, Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new jar content pack based at the given package with the given classloader.
|
||||
* @param id The pack's id
|
||||
* @param baseLocation The base package to load resources from
|
||||
* @param classLoader The classloader to use
|
||||
*/
|
||||
public JarContentPack(String id, String baseLocation, ClassLoader classLoader) {
|
||||
this.id = id;
|
||||
this.baseLocation = baseLocation;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all the resources in the given package with the given file extension.
|
||||
* @param location The location to search
|
||||
* @param type The file extension
|
||||
* @return A stream of these resources
|
||||
*/
|
||||
// Inspired from this: https://stackoverflow.com/a/48190582/7582022
|
||||
@Override
|
||||
@NotNull
|
||||
@@ -83,16 +116,25 @@ public class JarContentPack implements ContentPack {
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the resource identified by the given id.
|
||||
* @param identifier The resource's id
|
||||
* @return Returns the resource or <code>null</code> if it doesn't exist
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Resource getResource(@NotNull String location) {
|
||||
URL url = classLoader.getResource(baseLocation + "/" + location);
|
||||
public Resource getResource(@NotNull String identifier) {
|
||||
URL url = classLoader.getResource(baseLocation + "/" + identifier);
|
||||
if (url != null) {
|
||||
return new CallbackResource(Util.pathToId(id, location), () -> classLoader.getResourceAsStream(baseLocation + "/" + location));
|
||||
return new CallbackResource(Util.pathToId(id, identifier), () -> classLoader.getResourceAsStream(baseLocation + "/" + identifier));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id of this pack.
|
||||
* @return The pack's id
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
public String getId() {
|
||||
|
||||
@@ -4,29 +4,74 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* An interface for a generic product
|
||||
*/
|
||||
public interface Product {
|
||||
/**
|
||||
* The property specifier. Should contain all property values separated by low dashes.
|
||||
* @return The specifier
|
||||
*/
|
||||
@NotNull
|
||||
String getPropertySpecifier();
|
||||
|
||||
/**
|
||||
* Gets all the property values
|
||||
* @return The values as array
|
||||
*/
|
||||
String[] getProperties();
|
||||
|
||||
/**
|
||||
* Gets this product's depth
|
||||
* @return The depth
|
||||
*/
|
||||
int getDepth();
|
||||
|
||||
/**
|
||||
* Checks whether the product is allowed to go into the specified y layer.
|
||||
* @param y The y layer to test
|
||||
* @return Whether the product is allowed to go into that y layer
|
||||
*/
|
||||
boolean testY(int y);
|
||||
|
||||
/**
|
||||
* Gets the products type.
|
||||
* @return Its type
|
||||
*/
|
||||
@NotNull
|
||||
ProductType<?> getType();
|
||||
|
||||
/**
|
||||
* Checks the two products for equality.
|
||||
* @param product A product to check
|
||||
* @return Whether they match
|
||||
*/
|
||||
boolean equals(Product product);
|
||||
|
||||
/**
|
||||
* Gets the translation key for this product. Usually the same as the products specific.
|
||||
* @return The translation key
|
||||
*/
|
||||
@NotNull
|
||||
default String getTranslationKey() {
|
||||
return "products." + getType().getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this product. This will
|
||||
* @param i18n The resources to load the translation from
|
||||
* @return The localized name
|
||||
*/
|
||||
@NotNull
|
||||
default String getName(@NotNull ResourceBundle i18n) {
|
||||
return i18n.getString(getTranslationKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the localized description for this product. This includes all the properties their values.
|
||||
* @param i18n The resources to load the translations from
|
||||
* @return The localized description
|
||||
*/
|
||||
@NotNull
|
||||
default String getDescription(@NotNull ResourceBundle i18n) {
|
||||
String[] props = getType().getProperties();
|
||||
@@ -46,11 +91,19 @@ public interface Product {
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the resource location for this product
|
||||
* @return The resource location
|
||||
*/
|
||||
@NotNull
|
||||
default String getTextureLocation() {
|
||||
return "textures/products/" + getType().getId() + "/" + getPropertySpecifier() + ".png";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the placeholder texture for products. Why isn't this static?
|
||||
* @return The resource location
|
||||
*/
|
||||
@NotNull
|
||||
static String getPlaceholderTextureLocation() {
|
||||
return "textures/products/package.png";
|
||||
|
||||
@@ -10,14 +10,27 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A class which manages the loading and access to products.
|
||||
*/
|
||||
public class ProductManager implements ResourceManager<ProductType<?>> {
|
||||
/**
|
||||
* Map with all {@link ProductType}s mapped by their ids.
|
||||
*/
|
||||
private final Map<String, ProductType<?>> productTypes = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Removes all loaded products
|
||||
*/
|
||||
@Override
|
||||
public void clear() {
|
||||
productTypes.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all products from the given content manager.
|
||||
* @param contentManager The content manager to load from
|
||||
*/
|
||||
public void reload(@NotNull ContentManager contentManager) {
|
||||
contentManager.getResources("products", "properties").forEach(resource -> {
|
||||
InputStream inputStream = resource.getInputStream();
|
||||
@@ -32,17 +45,31 @@ public class ProductManager implements ResourceManager<ProductType<?>> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a single product type by its id.
|
||||
* @param id The id
|
||||
* @return The associated product type or <code>null</code> if no product type with this id exists
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public ProductType<?> get(String id) {
|
||||
return productTypes.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all loaded product types.
|
||||
* @return All loaded product types
|
||||
*/
|
||||
@NotNull
|
||||
public Collection<ProductType<?>> getTypes() {
|
||||
return productTypes.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random product out of all product types. Randomness is distributed equally over all types not over the product variants.
|
||||
* @param random The random instance to use
|
||||
* @return A random product or <code>null</code> if no products are loaded
|
||||
*/
|
||||
@Nullable
|
||||
public Product randomProduct(Random random) {
|
||||
if (!productTypes.isEmpty()) {
|
||||
|
||||
@@ -5,11 +5,35 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Interface for product types.
|
||||
* @param <T> The base class vor all products of this type
|
||||
*/
|
||||
public interface ProductType<T extends Product> {
|
||||
|
||||
/**
|
||||
* Gets a product of this type with the given values as properties.
|
||||
* @param values Some properties
|
||||
* @return The product or <code>null</code> if no such product exists
|
||||
*/
|
||||
@Nullable T getProduct(@NotNull String[] values);
|
||||
|
||||
/**
|
||||
* Gets the id of this type.
|
||||
* @return The id
|
||||
*/
|
||||
@NotNull String getId();
|
||||
|
||||
/**
|
||||
* Gets all property ids.
|
||||
* @return An array of the property ids
|
||||
*/
|
||||
@NotNull String[] getProperties();
|
||||
|
||||
@NotNull Product randomProduct(Random random);
|
||||
/**
|
||||
* Gets a random product of this type.
|
||||
* @param random The random instance to use
|
||||
* @return A random product
|
||||
*/
|
||||
@NotNull T randomProduct(Random random);
|
||||
}
|
||||
|
||||
@@ -8,62 +8,122 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.IntPredicate;
|
||||
|
||||
/**
|
||||
* An implementation of {@link Product} that dynamically loads its data from a properties file
|
||||
*/
|
||||
public class DynamicProduct implements Product {
|
||||
/**
|
||||
* The product's type
|
||||
*/
|
||||
private ProductType<?> type;
|
||||
/**
|
||||
* The property values
|
||||
*/
|
||||
private final String[] properties;
|
||||
/**
|
||||
* The depth of this product
|
||||
*/
|
||||
private int depth = 1;
|
||||
/**
|
||||
* A function that checks if the product can go into the given y location
|
||||
*/
|
||||
@NotNull
|
||||
private IntPredicate yPredicate = Util.dummyIntPredicate();
|
||||
|
||||
/**
|
||||
* Constructs a new product with the given values as properties.
|
||||
* @param properties The property values
|
||||
*/
|
||||
public DynamicProduct(String[] properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an identifier that uniquely represents the property values
|
||||
* @return A concatenated list of the property values
|
||||
*/
|
||||
@Override
|
||||
@NotNull
|
||||
public String getPropertySpecifier() {
|
||||
return String.join("_", properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the property values
|
||||
* @return The property values
|
||||
*/
|
||||
@Override
|
||||
public String[] getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the depth of this product
|
||||
* @param depth The depth
|
||||
*/
|
||||
public void setDepth(int depth) {
|
||||
this.depth = depth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the product's depth.
|
||||
* @return The depth
|
||||
*/
|
||||
@Override
|
||||
public int getDepth() {
|
||||
return depth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the product can go into the given y layer.
|
||||
* @param y The given y layer
|
||||
* @return Whether the product is allowed to go into it
|
||||
*/
|
||||
@Override
|
||||
public boolean testY(int y) {
|
||||
return yPredicate.test(y);
|
||||
}
|
||||
|
||||
// This function exists to resolve the circular references of ProductType <-> Product on creation
|
||||
/**
|
||||
* Sets the type of this product. This is needed because the {@link DynamicProductType} needs to know all of its products and all products need to know their type
|
||||
* @param type The products type
|
||||
*/
|
||||
void setType(ProductType<?> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the product's type.
|
||||
* @return Returns the type.
|
||||
*/
|
||||
@Override
|
||||
@NotNull
|
||||
public ProductType<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if both products match.
|
||||
* @param product The other product
|
||||
* @return Returns whether both products match
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Product product) {
|
||||
return super.equals(product);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the function for checking the y layer.
|
||||
* @param yPredicate The function
|
||||
*/
|
||||
public void setYPredicate(@NotNull IntPredicate yPredicate) {
|
||||
this.yPredicate = yPredicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* A toString function. Nothing to explain
|
||||
* @return The object and its data converted to a string
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DynamicProduct{" +
|
||||
|
||||
@@ -4,6 +4,7 @@ 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 org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -11,11 +12,30 @@ import java.util.*;
|
||||
import java.util.function.IntPredicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* An implementation for {@link ProductType} that dynamically reads its data and products from a properties file.
|
||||
*/
|
||||
public class DynamicProductType implements ProductType<DynamicProduct> {
|
||||
/**
|
||||
* The type's id
|
||||
*/
|
||||
private final String id;
|
||||
/**
|
||||
* All of the products mapped by their property specifiers.
|
||||
* @see Product#getPropertySpecifier()
|
||||
*/
|
||||
private final Map<String, DynamicProduct> variations;
|
||||
/**
|
||||
* The property ids
|
||||
*/
|
||||
private final String[] properties;
|
||||
|
||||
/**
|
||||
* Constructs a new dynamic product type.
|
||||
* @param id The id
|
||||
* @param variations All of the products that are derived of this type
|
||||
* @param properties The property ids
|
||||
*/
|
||||
public DynamicProductType(String id, List<DynamicProduct> variations, String[] properties) {
|
||||
this.id = id;
|
||||
this.variations = new HashMap<>();
|
||||
@@ -26,6 +46,12 @@ public class DynamicProductType implements ProductType<DynamicProduct> {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a product type from an input stream with a properties file
|
||||
* @param id The type's id
|
||||
* @param inputStream The input stream containing a properties file
|
||||
* @return Returns the constructed product type
|
||||
*/
|
||||
@NotNull
|
||||
public static DynamicProductType from(@NotNull String id, @NotNull InputStream inputStream) {
|
||||
Properties propertiesFile = new Properties();
|
||||
@@ -83,6 +109,13 @@ public class DynamicProductType implements ProductType<DynamicProduct> {
|
||||
return new DynamicProductType(id, List.of(new DynamicProduct(Util.emptyArray())), Util.emptyArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new product prototype for the given property value.
|
||||
* @param propertiesFile The properties file to load from
|
||||
* @param property The property id to target
|
||||
* @param variant The property value to target.
|
||||
* @return Returns a new prototype
|
||||
*/
|
||||
private static ProductPrototype makePrototype(Properties propertiesFile, String property, String variant) {
|
||||
ProductPrototype prototype = new ProductPrototype(variant);
|
||||
String base = property + "." + variant + ".";
|
||||
@@ -111,41 +144,85 @@ public class DynamicProductType implements ProductType<DynamicProduct> {
|
||||
return prototype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the product with the given values.
|
||||
* @param values The properties' values
|
||||
* @return Returns the associated product or <code>null</code> if it's nonexistent
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public DynamicProduct getProduct(@NotNull String[] values) {
|
||||
return variations.get(String.join("_", values));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type's id
|
||||
* @return The id
|
||||
*/
|
||||
@Override
|
||||
public @NotNull String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the property ids
|
||||
* @return The property ids
|
||||
*/
|
||||
@Override
|
||||
public @NotNull String[] getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a random product from the variations.
|
||||
* @param random An instance of {@link Random} to use for the calculation
|
||||
* @return A random product
|
||||
*/
|
||||
@Override
|
||||
public @NotNull Product randomProduct(Random random) {
|
||||
public @NotNull DynamicProduct randomProduct(Random random) {
|
||||
List<DynamicProduct> products = new ArrayList<>(variations.values());
|
||||
return products.get(random.nextInt(products.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all of the products mapped by their property specifier.
|
||||
* @return A map of those
|
||||
* @see DynamicProduct#getPropertySpecifier()
|
||||
*/
|
||||
public Map<String, DynamicProduct> getVariations() {
|
||||
return variations;
|
||||
}
|
||||
|
||||
/**
|
||||
* A prototype used for building the product variations
|
||||
*/
|
||||
private static class ProductPrototype {
|
||||
/**
|
||||
* The property specifier with all properties that already have been used
|
||||
*/
|
||||
String value;
|
||||
|
||||
/**
|
||||
* The depth of the prototype. <code>null</code> if it should be inherited
|
||||
*/
|
||||
Integer depth = null;
|
||||
/**
|
||||
* The y tester of the prototype. <code>null</code> if it should be inherited
|
||||
*/
|
||||
IntPredicate yPredicate = null;
|
||||
|
||||
/**
|
||||
* Constructs a new prototype with the given property specifier
|
||||
* @param value The property specifier
|
||||
*/
|
||||
public ProductPrototype(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the prototypes' data to the given product
|
||||
* @param product The product which shall get adapted
|
||||
*/
|
||||
public void apply(DynamicProduct product) {
|
||||
if (depth != null)
|
||||
product.setDepth(depth);
|
||||
@@ -153,6 +230,11 @@ public class DynamicProductType implements ProductType<DynamicProduct> {
|
||||
product.setYPredicate(yPredicate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges two prototypes into each other. The result has the properties of both. The other prototype is recessive
|
||||
* @param prototype The other prototype
|
||||
* @return A newly constructed prototype with the calculated properties.
|
||||
*/
|
||||
public ProductPrototype combine(ProductPrototype prototype) {
|
||||
ProductPrototype result = new ProductPrototype(value + ";" + prototype.value);
|
||||
if (prototype.depth != null)
|
||||
@@ -167,6 +249,10 @@ public class DynamicProductType implements ProductType<DynamicProduct> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts to string. That's all.
|
||||
* @return The stringified product type.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DynamicProductType{" +
|
||||
|
||||
@@ -3,33 +3,68 @@ package de.siphalor.was.content.quest;
|
||||
import de.siphalor.was.content.product.Product;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a quest.
|
||||
*/
|
||||
public class Quest {
|
||||
/**
|
||||
* The type of this quest.
|
||||
*/
|
||||
@NotNull
|
||||
private final Type type;
|
||||
/**
|
||||
* The quest reward/punishment
|
||||
*/
|
||||
private final int reward;
|
||||
/**
|
||||
* The product to store/deliver
|
||||
*/
|
||||
@NotNull
|
||||
private final Product product;
|
||||
|
||||
/**
|
||||
* Constructs a new quest.
|
||||
* @param type The type
|
||||
* @param reward The reward/punishment
|
||||
* @param product The product to store/deliver
|
||||
*/
|
||||
public Quest(@NotNull Type type, int reward, @NotNull Product product) {
|
||||
this.product = product;
|
||||
this.reward = reward;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the product to store/deliver.
|
||||
* @return The product
|
||||
*/
|
||||
@NotNull
|
||||
public Product getProduct() {
|
||||
return product;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of this quest.
|
||||
* @return The type
|
||||
*/
|
||||
@NotNull
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the reward/punishment for this quest.
|
||||
* @return The reward/punishment
|
||||
*/
|
||||
public int getReward() {
|
||||
return reward;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the type of a quest. <br />
|
||||
* <code>IN</code> for incoming (store) <br />
|
||||
* <code>OUT</code> for outgoing (deliver)
|
||||
*/
|
||||
public enum Type {
|
||||
IN, OUT
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@ package de.siphalor.was.content.quest;
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* A class that provides the game with quests and optionally finishes.
|
||||
*/
|
||||
public interface QuestGenerator extends Enumeration<Quest> {
|
||||
/**
|
||||
* Restarts this generator
|
||||
|
||||
@@ -10,14 +10,28 @@ import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class handles the loading and access of quest generators.
|
||||
*/
|
||||
public class QuestManager implements ResourceManager<QuestGenerator> {
|
||||
/**
|
||||
* All of the quest generators mapped by their ids
|
||||
*/
|
||||
private final Map<String, QuestGenerator> questGenerators = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Clears all loaded quest generators.
|
||||
*/
|
||||
@Override
|
||||
public void clear() {
|
||||
questGenerators.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all quest generators from the given content manager
|
||||
* @param contentManager The content manager to load from
|
||||
* @param productManager The product manager to check product definitions against
|
||||
*/
|
||||
public void reload(@NotNull ContentManager contentManager, @NotNull ProductManager productManager) {
|
||||
contentManager.getResources("quests", "csv").forEach(resource -> {
|
||||
InputStream inputStream = resource.getInputStream();
|
||||
@@ -32,6 +46,11 @@ public class QuestManager implements ResourceManager<QuestGenerator> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a quest generator by its id.
|
||||
* @param id The id
|
||||
* @return The associated quest generator
|
||||
*/
|
||||
@Override
|
||||
public QuestGenerator get(String id) {
|
||||
return questGenerators.get(id);
|
||||
|
||||
@@ -5,18 +5,36 @@ import de.siphalor.was.content.product.Product;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* An implementation of {@link QuestGenerator} that randomly spits out all kinds of quests with all kinds of products loaded.
|
||||
*/
|
||||
public class RandomQuestGenerator implements QuestGenerator {
|
||||
/**
|
||||
* The internal random instance
|
||||
*/
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
@Override
|
||||
public void restart() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This runs infinitely, so always <code>true</code>.
|
||||
* @return <code>true</code>
|
||||
*/
|
||||
@Override
|
||||
public boolean hasMoreElements() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next quest.
|
||||
* @return Another quest
|
||||
*/
|
||||
@Override
|
||||
public Quest nextElement() {
|
||||
Product product = WhatAStorage.getInstance().getProductManager().randomProduct(RANDOM);
|
||||
|
||||
@@ -17,15 +17,34 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* A quest generator that follows a static list of quests.
|
||||
*/
|
||||
public class StaticQuestGenerator implements QuestGenerator {
|
||||
/**
|
||||
* The list of quests to follow
|
||||
*/
|
||||
@NotNull
|
||||
private final List<Quest> quests;
|
||||
/**
|
||||
* The current index in the quest list
|
||||
*/
|
||||
private int index = 0;
|
||||
|
||||
/**
|
||||
* Constructs a new quest generator with the given quest list.
|
||||
* @param quests The quest list to use
|
||||
*/
|
||||
public StaticQuestGenerator(@NotNull List<Quest> quests) {
|
||||
this.quests = quests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a new static quest generator from the given input stream. The input stream should contain CSV format.
|
||||
* @param inputStream An input stream with csv format
|
||||
* @param productManager The product manager to check product definitions against
|
||||
* @return The newly loaded quest generator or <code>null</code> if the laoding failed
|
||||
*/
|
||||
@Nullable
|
||||
public static StaticQuestGenerator fromCsv(@NotNull InputStream inputStream, @NotNull ProductManager productManager) {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
@@ -69,16 +88,27 @@ public class StaticQuestGenerator implements QuestGenerator {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restarts this generator.
|
||||
*/
|
||||
@Override
|
||||
public void restart() {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next quest and advances.
|
||||
* @return The next quest
|
||||
*/
|
||||
@Override
|
||||
public Quest nextElement() {
|
||||
return quests.get(index++);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether there are still new quests in the list.
|
||||
* @return Whether there are quests left
|
||||
*/
|
||||
@Override
|
||||
public boolean hasMoreElements() {
|
||||
return index < quests.size();
|
||||
|
||||
@@ -5,14 +5,29 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.io.InputStream;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* An implementation for {@link Resource} that runs a callback to get the input stream.
|
||||
*/
|
||||
public class CallbackResource extends Resource {
|
||||
/**
|
||||
* The callback to run for the input stream
|
||||
*/
|
||||
Supplier<InputStream> supplier;
|
||||
|
||||
/**
|
||||
* Constructs a new callback resource.
|
||||
* @param id The id
|
||||
* @param supplier The supplier that will provide the input stream
|
||||
*/
|
||||
public CallbackResource(String id, Supplier<InputStream> supplier) {
|
||||
super(id);
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the callback to get the input stream.
|
||||
* @return An input stream or <code>null</code> if the callback failed
|
||||
*/
|
||||
@Override
|
||||
public @Nullable InputStream getInputStream() {
|
||||
return supplier.get();
|
||||
|
||||
@@ -5,14 +5,29 @@ import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* A file based implementation for {@link Resource}.
|
||||
*/
|
||||
public class FileResource extends Resource {
|
||||
/**
|
||||
* The file that this resource points to
|
||||
*/
|
||||
private final File file;
|
||||
|
||||
/**
|
||||
* Constructs a new file resource
|
||||
* @param id The id to use
|
||||
* @param file The file to point to
|
||||
*/
|
||||
public FileResource(String id, File file) {
|
||||
super(id);
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new {@link FileInputStream} to the contained file.
|
||||
* @return The input stream or <code>null</code> if opening the stream failed
|
||||
*/
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
try {
|
||||
|
||||
@@ -4,16 +4,34 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* A representation for some kind of resource.
|
||||
*/
|
||||
public abstract class Resource {
|
||||
/**
|
||||
* The resource's id
|
||||
*/
|
||||
private final String id;
|
||||
|
||||
/**
|
||||
* Constructs a new resource with the given id.
|
||||
* @param id The id
|
||||
*/
|
||||
protected Resource(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an input stream for this resource.
|
||||
* @return An input stream to the resource
|
||||
*/
|
||||
@Nullable
|
||||
public abstract InputStream getInputStream();
|
||||
|
||||
/**
|
||||
* Gets the id of this resource. Usually namespaced
|
||||
* @return The id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -7,16 +7,43 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
/**
|
||||
* Represents the current budget and a transaction history.
|
||||
*/
|
||||
public class Balance {
|
||||
/**
|
||||
* The current budget
|
||||
*/
|
||||
private int budget = 0;
|
||||
/**
|
||||
* The total money gained
|
||||
*/
|
||||
private int totalIncome = 0;
|
||||
/**
|
||||
* The total money lost
|
||||
*/
|
||||
private int totalLoss = 0;
|
||||
/**
|
||||
* The transaction history
|
||||
*/
|
||||
private final Queue<Transaction> history = new ConcurrentLinkedQueue<>();
|
||||
|
||||
/**
|
||||
* Adds a new transaction to the history.
|
||||
* @param type The transaction type
|
||||
* @param change The amount of money received/lost
|
||||
* @param product The product that this was about or <code>null</code> if none
|
||||
* @return The added transaction
|
||||
*/
|
||||
public Transaction add(@NotNull Transaction.Type type, int change, @Nullable Product product) {
|
||||
return add(new Transaction(type, change, product != null ? product.getTranslationKey() : ""));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new transaction to the history.
|
||||
* @param transaction The transaction
|
||||
* @return the added transaction
|
||||
*/
|
||||
public Transaction add(@NotNull Transaction transaction) {
|
||||
history.add(transaction);
|
||||
|
||||
@@ -30,19 +57,35 @@ public class Balance {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the complete transaction history.
|
||||
* @return The history
|
||||
*/
|
||||
@NotNull
|
||||
public Queue<Transaction> getHistory() {
|
||||
return history;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current budget.
|
||||
* @return The current budget
|
||||
*/
|
||||
public int getBudget() {
|
||||
return budget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total amount of money gained.
|
||||
* @return the total income
|
||||
*/
|
||||
public int getTotalIncome() {
|
||||
return totalIncome;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total amount of money lost
|
||||
* @return the total loss
|
||||
*/
|
||||
public int getTotalLoss() {
|
||||
return totalLoss;
|
||||
}
|
||||
|
||||
@@ -6,30 +6,62 @@ import de.siphalor.was.content.lang.I18n;
|
||||
import java.util.Locale;
|
||||
import java.util.prefs.Preferences;
|
||||
|
||||
/**
|
||||
* Holds the game's options and is responsible for saving and loading them.
|
||||
*/
|
||||
public class Options {
|
||||
/**
|
||||
* Whether quest should get automatically added when fulfilled
|
||||
*/
|
||||
private boolean autoRefillQuests;
|
||||
/**
|
||||
* Allow resolving of two quests that target the same product. One asks to deposit it, the other to deliver it
|
||||
*/
|
||||
private boolean allowQuestResolving;
|
||||
|
||||
/**
|
||||
* Gets whether quest resolving is enabled.
|
||||
* @return Whether quest resolving is enabled
|
||||
*/
|
||||
public boolean getAllowQuestResolving() {
|
||||
return allowQuestResolving;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether quest resolving should be enabled.
|
||||
* @param allowQuestResolving Whether it should be enabled
|
||||
*/
|
||||
public void setAllowQuestResolving(boolean allowQuestResolving) {
|
||||
this.allowQuestResolving = allowQuestResolving;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether fulfilled quests should automatically be refilled.
|
||||
* @return Whether fulfilled quests should automatically be refilled
|
||||
*/
|
||||
public boolean getAutoRefillQuests() {
|
||||
return autoRefillQuests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether fulfilled quests should automatically be refilled.
|
||||
* @param autoRefillQuests Whether fulfilled quests should automatically be refilled
|
||||
*/
|
||||
public void setAutoRefillQuests(boolean autoRefillQuests) {
|
||||
this.autoRefillQuests = autoRefillQuests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the preferences object used for session independent storage.
|
||||
* @return The preferences object
|
||||
*/
|
||||
private Preferences getPreferences() {
|
||||
return Preferences.userNodeForPackage(WhatAStorage.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the options from the storage.
|
||||
*/
|
||||
public void load() {
|
||||
Preferences preferences = getPreferences();
|
||||
autoRefillQuests = preferences.getBoolean("auto-refill-quests", false);
|
||||
@@ -39,6 +71,9 @@ public class Options {
|
||||
I18n.getInstance().setLang(lang, WhatAStorage.getInstance().getContentManager());
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the options data to the storage
|
||||
*/
|
||||
public void save() {
|
||||
Preferences preferences = getPreferences();
|
||||
preferences.putBoolean("auto-refill-quests", autoRefillQuests);
|
||||
|
||||
@@ -2,9 +2,22 @@ package de.siphalor.was.game;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* The class holding the stored products.
|
||||
*/
|
||||
public class Storage {
|
||||
/**
|
||||
* The storage slots
|
||||
*/
|
||||
StorageSlot[][] slots;
|
||||
|
||||
/**
|
||||
* Constructs a new storage with the given lengths.
|
||||
* @param width The width
|
||||
* @param height The height
|
||||
* @param depth The depth of the {@link StorageSlot}s
|
||||
* @throws IllegalArgumentException if any of the lengths is smaller or equal to zero
|
||||
*/
|
||||
public Storage(int width, int height, int depth) {
|
||||
if (width <= 0 || height <= 0 || depth <= 0) {
|
||||
throw new IllegalArgumentException("Storage lengths must be bigger than zero");
|
||||
@@ -18,19 +31,36 @@ public class Storage {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the storage slot at the specified location. <b>Coordinate must be valid!</b>
|
||||
* @param x The x position (<b>Must be in bounds</b>)
|
||||
* @param y The y position (<b>Must be in bounds</b>
|
||||
* @return The storage slot at the given location
|
||||
*/
|
||||
@NotNull
|
||||
public StorageSlot get(int x, int y) {
|
||||
return slots[x][y];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the width of the storage
|
||||
* @return The width
|
||||
*/
|
||||
public int getWidth() {
|
||||
return slots.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the height of the storage
|
||||
* @return The height
|
||||
*/
|
||||
public int getHeight() {
|
||||
return slots[0].length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears this storage from all products
|
||||
*/
|
||||
public void clear() {
|
||||
for (StorageSlot[] row : slots) {
|
||||
for (StorageSlot slot : row) {
|
||||
|
||||
@@ -10,22 +10,43 @@ import java.util.Collection;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
/**
|
||||
* Represent a single storage slot.
|
||||
*/
|
||||
public class StorageSlot {
|
||||
/**
|
||||
* The depth of the slot
|
||||
*/
|
||||
final int depth;
|
||||
/**
|
||||
* The products in this slot
|
||||
*/
|
||||
final Product[] products;
|
||||
|
||||
/**
|
||||
* Constructs a new storage slot.
|
||||
* @param depth The depth of this slot
|
||||
*/
|
||||
public StorageSlot(int depth) {
|
||||
this.depth = depth;
|
||||
this.products = new Product[depth];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of the products.
|
||||
* @return The product array. Some entries might be <code>null</code> to indicate empty storage
|
||||
*/
|
||||
@NotNull
|
||||
public Product[] getProducts() {
|
||||
return products;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all stored products indexed by their visual position (depth-dependent).
|
||||
* @return A collection of indexed products
|
||||
*/
|
||||
@NotNull
|
||||
public Collection<Pair<Integer, Product>> getProductsIndexed() {
|
||||
public Collection<Pair<@NotNull Integer, @NotNull Product>> getProductsIndexed() {
|
||||
Queue<Pair<Integer, Product>> queue = new ConcurrentLinkedQueue<>();
|
||||
int index = 0;
|
||||
for (int i = 0; i < depth; i++) {
|
||||
@@ -39,10 +60,17 @@ public class StorageSlot {
|
||||
return queue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all products from this slot.
|
||||
*/
|
||||
public void clear() {
|
||||
Arrays.fill(products, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the visually first product.
|
||||
* @return The product
|
||||
*/
|
||||
@Nullable
|
||||
public Product front() {
|
||||
for (int i = products.length - 1; i >= 0; i--) {
|
||||
@@ -54,6 +82,10 @@ public class StorageSlot {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the visually first product.
|
||||
* @return The visual position where this product was removed from or <code>-1</code> if there was no product to remove
|
||||
*/
|
||||
public int pop() {
|
||||
if (products[0] == null)
|
||||
return -1;
|
||||
@@ -69,6 +101,11 @@ public class StorageSlot {
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given product fits into this slot depth-wise.
|
||||
* @param product The product to check
|
||||
* @return Returns whether it fits
|
||||
*/
|
||||
public boolean fits(@NotNull Product product) {
|
||||
int blocked = 0;
|
||||
for (Product p : products) {
|
||||
@@ -79,6 +116,11 @@ public class StorageSlot {
|
||||
return product.getDepth() <= depth - blocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new product to the visual front of this slot.
|
||||
* @param product The product to add
|
||||
* @return The visual position where the product went or <code>-1</code> if insertion failed
|
||||
*/
|
||||
public int add(@NotNull Product product) {
|
||||
int blocked = 0;
|
||||
int i;
|
||||
|
||||
@@ -4,34 +4,81 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Represents a transaction.
|
||||
*/
|
||||
public class Transaction {
|
||||
/**
|
||||
* The {@link Type} of this transaction
|
||||
*/
|
||||
private final Type type;
|
||||
/**
|
||||
* The money change of this transaction
|
||||
*/
|
||||
private final int change;
|
||||
/**
|
||||
* An optional translation key for a product. Might be empty
|
||||
*/
|
||||
private final String productKey;
|
||||
|
||||
/**
|
||||
* Constructs a new transaction.
|
||||
* @param type The type
|
||||
* @param change The money change of this transaction
|
||||
* @param productKey A translation key for a product
|
||||
*/
|
||||
public Transaction(@NotNull Type type, int change, @NotNull String productKey) {
|
||||
this.type = type;
|
||||
this.change = change;
|
||||
this.productKey = productKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type.
|
||||
* @return The type
|
||||
*/
|
||||
@NotNull
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the money change
|
||||
* @return The change
|
||||
*/
|
||||
public int getChange() {
|
||||
return change;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the product translation key.
|
||||
* @return The translation key or <code>""</code> if none is present
|
||||
*/
|
||||
@NotNull
|
||||
public String getProductKey() {
|
||||
return productKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the type of a transaction:
|
||||
* <ul>
|
||||
* <li><code>ABANDON</code>: Abandoned a quest</li>
|
||||
* <li><code>DESTROY</code>: destroyed a product</li>
|
||||
* <li><code>MOVE</code>: Moved a product</li>
|
||||
* <li><code>NOOP</code>: For internal use. To be used with a change of <code>0</code></li>
|
||||
* <li><code>DELIVER</code>: Delivered a product</li>
|
||||
* <li><code>STORE</code>: Stored a product</li>
|
||||
* <li><code>RESOLVE</code>: Resolved two quests against each other</li>
|
||||
* </ul>
|
||||
*/
|
||||
public enum Type {
|
||||
ABANDON, DESTROY, MOVE, NOOP, DELIVER, STORE, RESOLVE;
|
||||
|
||||
/**
|
||||
* Gets the translation key for this type
|
||||
* @return The translation key
|
||||
*/
|
||||
@NotNull
|
||||
public String getTranslationKey() {
|
||||
return "game.balance.history.type." + name().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
@@ -1,28 +1,69 @@
|
||||
package de.siphalor.was.util;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents the pair of two values.
|
||||
* @param <A> The type of the first value
|
||||
* @param <B> The type of the second value
|
||||
*/
|
||||
public class Pair<A, B> {
|
||||
/**
|
||||
* The first value
|
||||
*/
|
||||
private final A first;
|
||||
/**
|
||||
* The second value
|
||||
*/
|
||||
private final B second;
|
||||
|
||||
/**
|
||||
* Constructs a new pair.
|
||||
* @param first The first value
|
||||
* @param second The second value
|
||||
* @param <A> The type of the first value
|
||||
* @param <B> The type of the second value
|
||||
* @return The new pair
|
||||
*/
|
||||
@NotNull
|
||||
public static <A, B> Pair<A, B> of(A first, B second) {
|
||||
return new Pair<>(first, second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new pair.
|
||||
* @param first The first value
|
||||
* @param second The second value
|
||||
*/
|
||||
public Pair(A first, B second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first value.
|
||||
* @return The first value
|
||||
*/
|
||||
public A getFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the second value.
|
||||
* @return The second value
|
||||
*/
|
||||
public B getSecond() {
|
||||
return second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for equality.
|
||||
* @param o The other object
|
||||
* @return Returns whether both are equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -32,6 +73,10 @@ public class Pair<A, B> {
|
||||
Objects.equals(second, pair.second);
|
||||
}
|
||||
|
||||
/**
|
||||
* The combined hash code of both values
|
||||
* @return The hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(first, second);
|
||||
|
||||
@@ -7,19 +7,31 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* An input stream that can be reused. <br />
|
||||
* Close with {@link PersistentInputStream#realClose()} <br />
|
||||
* <b>Taken from here: https://stackoverflow.com/questions/924990/how-to-cache-inputstream-for-multiple-use#1303314</b>
|
||||
*/
|
||||
public class PersistentInputStream extends BufferedInputStream {
|
||||
/**
|
||||
* Constructs a new persistent input stream.
|
||||
* @param in The base input stream
|
||||
*/
|
||||
public PersistentInputStream(@NotNull InputStream in) {
|
||||
super(in);
|
||||
super.mark(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets this input stream.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
super.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this input stream.
|
||||
*/
|
||||
public void realClose() throws IOException {
|
||||
super.close();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
package de.siphalor.was.util;
|
||||
|
||||
/**
|
||||
* An interface for classes that manage some kind of resources.
|
||||
* @param <T> The type of the resources
|
||||
*/
|
||||
public interface ResourceManager<T> {
|
||||
/**
|
||||
* Clear this manager's resources.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Gets a resource by the given id.
|
||||
* @param id The resource's id
|
||||
* @return The associated resource
|
||||
*/
|
||||
T get(String id);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package de.siphalor.was.util;
|
||||
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.io.IOException;
|
||||
import java.util.function.IntPredicate;
|
||||
import java.util.function.Predicate;
|
||||
@@ -9,28 +8,63 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.logging.SimpleFormatter;
|
||||
|
||||
/**
|
||||
* A utility collection.
|
||||
*/
|
||||
public class Util {
|
||||
/**
|
||||
* The main logger
|
||||
*/
|
||||
public static final Logger LOGGER;
|
||||
|
||||
/**
|
||||
* A predicate that always returns <code>true</code>
|
||||
*/
|
||||
private static final Predicate<?> DUMMY_PREDICATE = o -> true;
|
||||
/**
|
||||
* An int predicate that always returns <code>true</code>
|
||||
*/
|
||||
private static final IntPredicate DUMMY_INT_PREDICATE = value -> true;
|
||||
|
||||
/**
|
||||
* An empty array
|
||||
*/
|
||||
private static final Object[] EMPTY_ARRAY = new Object[0];
|
||||
|
||||
/**
|
||||
* Gets an always true predicate.
|
||||
* @param <T> The type of the predicate
|
||||
* @return A predicate that always returns <code>true</code>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Predicate<T> dummyPredicate() {
|
||||
return (Predicate<T>) DUMMY_PREDICATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an always true int predicate.
|
||||
* @return An int predicate that always returns <code>true</code>
|
||||
*/
|
||||
public static IntPredicate dummyIntPredicate() {
|
||||
return DUMMY_INT_PREDICATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an empty array of the given type. No memory allocations for this stuff. Also convenient
|
||||
* @param <T> The array type
|
||||
* @return The empty array
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T[] emptyArray() {
|
||||
return (T[]) EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a relative path to a resource id.
|
||||
* @param packId The pack where the resource lives
|
||||
* @param path The relative path to the resource
|
||||
* @return The resource id
|
||||
*/
|
||||
public static String pathToId(String packId, String path) {
|
||||
int dot = path.lastIndexOf('.');
|
||||
if (dot >= 0) {
|
||||
|
||||
@@ -5,17 +5,59 @@ import de.siphalor.was.content.product.Product;
|
||||
import de.siphalor.was.content.quest.Quest;
|
||||
import de.siphalor.was.game.Transaction;
|
||||
|
||||
/**
|
||||
* An interface for handling the display.
|
||||
*/
|
||||
public interface Visual {
|
||||
/**
|
||||
* Called in the setup stage of the application.
|
||||
* @param whatAStorage The main instance of the game
|
||||
*/
|
||||
void setup(WhatAStorage whatAStorage);
|
||||
|
||||
/**
|
||||
* Starts the display and hands over control to this method.
|
||||
*/
|
||||
void run();
|
||||
|
||||
/**
|
||||
* Called when a game starts.
|
||||
* @param width The storage width
|
||||
* @param height The storage height
|
||||
* @param depth The storage depth
|
||||
*/
|
||||
void onGameStart(int width, int height, int depth);
|
||||
|
||||
/**
|
||||
* Called when the a program stop got requested.
|
||||
*/
|
||||
void onScheduleStop();
|
||||
|
||||
/**
|
||||
* Called when the localization changed. Should reload all of the localized UIs.
|
||||
*/
|
||||
void invalidateI18n();
|
||||
|
||||
/**
|
||||
* Called when a transactions gets added.
|
||||
* @param budget The new budget
|
||||
* @param transaction The new transaction
|
||||
* @param totalIncome The total income
|
||||
* @param totalLoss The total loss
|
||||
*/
|
||||
void onBalanceChanged(int budget, Transaction transaction, int totalIncome, int totalLoss);
|
||||
|
||||
/**
|
||||
* Called when a quest gets added.
|
||||
* @param newQuest The new quest
|
||||
* @param canCreateMore Whether the user can request more quests
|
||||
*/
|
||||
void onQuestAdded(Quest newQuest, boolean canCreateMore);
|
||||
|
||||
/**
|
||||
* Called when a quest gets fulfilled or abandoned.
|
||||
* @param index The index of the quest to remove
|
||||
*/
|
||||
void onQuestRemoved(int index);
|
||||
|
||||
void onProductSet(int x, int y, int z, Product product);
|
||||
|
||||
@@ -23,9 +23,9 @@ public class DummyContentPack implements ContentPack {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Resource getResource(@NotNull String location) {
|
||||
if (content.containsKey(location))
|
||||
return new DummyResource(location, content.get(location));
|
||||
public @Nullable Resource getResource(@NotNull String identifier) {
|
||||
if (content.containsKey(identifier))
|
||||
return new DummyResource(identifier, content.get(identifier));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package de.siphalor.was.dummy;
|
||||
import de.siphalor.was.content.product.Product;
|
||||
import de.siphalor.was.content.product.ProductType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
@@ -87,7 +86,7 @@ public class DummyProduct implements Product {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Product randomProduct(Random random) {
|
||||
public @NotNull DummyProduct randomProduct(Random random) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user