diff --git a/src/core/CommandEnabler.java b/src/core/CommandEnabler.java new file mode 100644 index 0000000..174a5d1 --- /dev/null +++ b/src/core/CommandEnabler.java @@ -0,0 +1,17 @@ +package core; + +import java.util.HashMap; + +public class CommandEnabler +{ + // Config/const variables + public static final String filename = "commands.config"; + + // Local variables + private HashMap enabledMap; + + public CommandEnabler() + { + enabledMap = new HashMap<>(); + } +} diff --git a/src/core/LocBase.java b/src/core/LocBase.java index 6fdcd49..8106779 100644 --- a/src/core/LocBase.java +++ b/src/core/LocBase.java @@ -8,7 +8,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; -import dataStructures.SectionedKeyValueStore; +import dataStructures.TaggedPairStore; import utils.FileUtils; import utils.GlobalLog; import utils.LogFilter; @@ -25,7 +25,7 @@ public abstract class LocBase public final String functionName; // Example: "Localizer.Stub"; // Local translation storage - private SectionedKeyValueStore stringStore; + protected TaggedPairStore stringStore; // Logging private void Log(String str) { GlobalLog.Log(LogFilter.Strings, str); } @@ -139,7 +139,7 @@ public abstract class LocBase file.createNewFile(); } - stringStore = new SectionedKeyValueStore(fileContents); + stringStore = new TaggedPairStore(fileContents); } catch(IOException e) { diff --git a/src/core/LocCommands.java b/src/core/LocCommands.java index d01ff7b..42fb5ac 100644 --- a/src/core/LocCommands.java +++ b/src/core/LocCommands.java @@ -1,8 +1,12 @@ package core; +import java.util.ArrayList; import utils.GlobalLog; import utils.LogFilter; +import dataStructures.Pair; +// Performs the same localization for the strings associated with command names as +// is performed with general strings in the application public class LocCommands extends LocBase { public static final String fileName = "locCommands.config"; @@ -34,4 +38,12 @@ public class LocCommands extends LocBase { return instance.GetKey(toStub); } + + // Gets all of the un-translated defaults in the commands list. + public static ArrayList GetUnlocalizedCommands() + { + ArrayList raw = new ArrayList<>(); + instance.stringStore.ForEach((pair) -> raw.add((String)((Pair)pair).First )); + return raw; + } } diff --git a/src/core/ObjectBuilderFactory.java b/src/core/ObjectBuilderFactory.java index 89c285c..a07be59 100644 --- a/src/core/ObjectBuilderFactory.java +++ b/src/core/ObjectBuilderFactory.java @@ -13,7 +13,7 @@ import utils.LogFilter; // NOTE(wisp): Isolated factory to assist with storage and caching if needed. // This also minimizes the number of places JDA interacts with our codebase. // As it stands, if the object name begins with Kitty, it's constructed here. -// TODO: Make all methods ID based instead of event based +// TODO: Make all methods ID based instead of event based public class ObjectBuilderFactory { // Key: guild string id, Value: guild information @@ -34,9 +34,17 @@ public class ObjectBuilderFactory // RPManger for tracking RP system private static RPManager rpManager; - // Lazy initialization style for + // Localization classes - these are singletons, but should be initialized before almost all other + // things so their inclusion in the factory is to ensure they're started at the correct time. + @SuppressWarnings("unused") private static Localizer locStrings; + @SuppressWarnings("unused") private static LocCommands locCommands; + + // Lazy initialization multithreaded mutex stuff to prevent explosions. + // TODO: Investigate using 'synchronized' instead potentially private static boolean hasInitialized; private static Semaphore initMutex = new Semaphore(1); + + // This is it, this is how the lazy init starts! private static void LazyInit() { if(hasInitialized) @@ -47,26 +55,31 @@ public class ObjectBuilderFactory initMutex.acquire(); try { - // Initialization here. This is where we could read from something external. + // structure initialization + // Construct necessary data structures. guildCache = new HashMap(); userCache = new HashMap(); channelCache = new HashMap(); database = null; stats = null; + + // Start by reading from things that are external. Because + // we require these things to be resolved before the rest of the application, + // we place them here. + locStrings = new Localizer(); + locCommands = new LocCommands(); } finally { initMutex.release(); + hasInitialized = true; } } catch(InterruptedException ie) { GlobalLog.Error(LogFilter.Core, "Issue during object builder lazy initialization." - + " The factory was not initialized, " - + "and kitty will not be able to continue functionally."); + + " The factory was not initialized, and kitty will not be able to continue functionally."); } - - hasInitialized = true; } // Explicitly locks: guildCache diff --git a/src/dataStructures/SectionedKeyValueStore.java b/src/dataStructures/TaggedPairStore.java similarity index 78% rename from src/dataStructures/SectionedKeyValueStore.java rename to src/dataStructures/TaggedPairStore.java index 058ed3c..25b6a87 100644 --- a/src/dataStructures/SectionedKeyValueStore.java +++ b/src/dataStructures/TaggedPairStore.java @@ -18,25 +18,25 @@ import java.util.function.Consumer; // Note that the sections are NOT designed to allow for duplicate keys across them. // This is a restriction of the structure, but can be changed later potentially. // The only value not allowed in a key or value is the KeyValueSplit. -public class SectionedKeyValueStore +public class TaggedPairStore { // Variables public final char SectionStart = '['; public final char SectionEnd = ']'; - public final char KeyValueLineSeparator = '\n'; - public final String KeyValueSplit = "="; + public final char PairLineSeparator = '\n'; + public final String PairSplit = "="; // [Key: SectionName, [Key: KeyString, Value: ValueString]] - private HashMap> sectionKeyValue; + private HashMap> taggedPairs; // [Key: KeyString, Value: ValueString]] - private HashMap keyValue; + private HashMap allPairs; // String constructor that parses the input string into the object - public SectionedKeyValueStore(String input) + public TaggedPairStore(String input) { - sectionKeyValue = new HashMap>(); - keyValue = new HashMap(); + taggedPairs = new HashMap>(); + allPairs = new HashMap(); Parse(input); } @@ -44,7 +44,7 @@ public class SectionedKeyValueStore @SuppressWarnings({"rawtypes", "unchecked"}) public void ForEach(BiConsumer> action) { - Iterator it = sectionKeyValue.entrySet().iterator(); + Iterator it = taggedPairs.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry)it.next(); @@ -62,7 +62,7 @@ public class SectionedKeyValueStore @SuppressWarnings({"rawtypes"}) public void ForEach(Consumer> action) { - Iterator it = keyValue.entrySet().iterator(); + Iterator it = allPairs.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry)it.next(); @@ -79,11 +79,11 @@ public class SectionedKeyValueStore String out = ""; // Iterates over the sections and - Iterator it = sectionKeyValue.entrySet().iterator(); + Iterator it = taggedPairs.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry)it.next(); - out += ("" + SectionStart + pair.getKey() + SectionEnd + KeyValueLineSeparator); + out += ("" + SectionStart + pair.getKey() + SectionEnd + PairLineSeparator); Iterator internal = ((HashMap)pair.getValue()).entrySet().iterator(); while(internal.hasNext()) @@ -93,12 +93,12 @@ public class SectionedKeyValueStore String value = (String)internalPair.getValue(); if(key == value) - out += (key + KeyValueSplit) + KeyValueLineSeparator; + out += (key + PairSplit) + PairLineSeparator; else - out += (key + KeyValueSplit + value) + KeyValueLineSeparator; + out += (key + PairSplit + value) + PairLineSeparator; } - out += KeyValueLineSeparator; + out += PairLineSeparator; } return out; @@ -131,21 +131,21 @@ public class SectionedKeyValueStore // Parse out the pairs within the section, split them all out. String unparsedPairs = section.substring(pos + 1); - String[] pairs = unparsedPairs.split("\\" + KeyValueLineSeparator); + String[] pairs = unparsedPairs.split("\\" + PairLineSeparator); // Parse out valid key-value pairs, and store them in the specified section. // At this point, we can be guarenteed that sectionName is in the Hashmap. for(int pair = 0; pair < pairs.length; ++pair) { String line = pairs[pair]; - int splitPos = line.indexOf(KeyValueSplit); + int splitPos = line.indexOf(PairSplit); if(splitPos < 0) continue; String key = line.substring(0, splitPos); - String value = line.substring(splitPos + KeyValueSplit.length()); - sectionKeyValue.get(sectionName).putIfAbsent(key, value); - keyValue.putIfAbsent(key, value); + String value = line.substring(splitPos + PairSplit.length()); + taggedPairs.get(sectionName).putIfAbsent(key, value); + allPairs.putIfAbsent(key, value); } } } @@ -165,28 +165,28 @@ public class SectionedKeyValueStore public void AddKeyValue(String sectionName, String key, String value) { AddSection(sectionName); - sectionKeyValue.get(sectionName).putIfAbsent(key, value); - keyValue.putIfAbsent(key, value); + taggedPairs.get(sectionName).putIfAbsent(key, value); + allPairs.putIfAbsent(key, value); } // Adds a given section to the hashmap if it's not already present public void AddSection(String sectionName) { - sectionKeyValue.putIfAbsent(sectionName, new HashMap()); + taggedPairs.putIfAbsent(sectionName, new HashMap()); } // Returns a HashMap of Keys to Values for a given section @SuppressWarnings("unchecked") public HashMap GetSection(String sectionName) { - return (HashMap) sectionKeyValue.get(sectionName).clone(); + return (HashMap) taggedPairs.get(sectionName).clone(); } // Look up a global key public String GetKey(String key) { - if(keyValue.containsKey(key)) - return keyValue.get(key); + if(allPairs.containsKey(key)) + return allPairs.get(key); return null; } diff --git a/src/main/Main.java b/src/main/Main.java index 653667c..a30359a 100644 --- a/src/main/Main.java +++ b/src/main/Main.java @@ -13,7 +13,6 @@ import net.dv8tion.jda.core.entities.*; import net.dv8tion.jda.core.events.message.guild.*; import net.dv8tion.jda.core.hooks.ListenerAdapter; import offline.*; -import core.Localizer; import utils.GlobalLog; import net.dv8tion.jda.core.*; @@ -29,18 +28,11 @@ public class Main extends ListenerAdapter private static DatabaseManager databaseManager; private static Stats stats; private static RPManager rpManager; - private static Localizer locStrings; - private static LocCommands locCommands; - + // Main test location public static void main(String[] args) throws InterruptedException, LoginException, Exception { - // Localizer startup - Potentially integrate with the factory. Needs to happen first tho. - locStrings = new Localizer(); - locCommands = new LocCommands(); - - - // Factory startup + // Factory startup. The ordering is intentional. databaseManager = ObjectBuilderFactory.ConstructDatabaseManager(); commandManager = ObjectBuilderFactory.ConstructCommandManager(); rpManager = ObjectBuilderFactory.ConstructRPManager();