mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Autocomplete plugin filenames and Bash Tags in editor
Bash Tags are hardcoded in the game settings. They could be sourced from the masterlist, but while that would be more flexible, they don't change often and hardcoding them avoids having to make a change to masterlist syntax.
This commit is contained in:
+2
-1
@@ -33,6 +33,7 @@
|
||||
"Jed": "SlexAxton/Jed#a9d03e1bbca9211a8b29a93a298a7ee9ddb353f0",
|
||||
"jed-gettext-parser": "^1.0.0",
|
||||
"marked": "^0.3.2",
|
||||
"lodash": "^4.3.0"
|
||||
"lodash": "^4.3.0",
|
||||
"paper-autocomplete": "loot/paper-autocomplete#master"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,73 @@ namespace loot {
|
||||
_masterFile = "Oblivion.esm";
|
||||
_repositoryURL = "https://github.com/loot/oblivion.git";
|
||||
_repositoryBranch = "v0.8";
|
||||
|
||||
bashTags = {
|
||||
"Actors.ACBS",
|
||||
"Actors.AIData",
|
||||
"Actors.AIPackages",
|
||||
"Actors.AIPackagesForceAdd",
|
||||
"Actors.Animations",
|
||||
"Actors.CombatStyle",
|
||||
"Actors.DeathItem",
|
||||
"Actors.Skeleton",
|
||||
"Actors.Spells",
|
||||
"Actors.SpellsForceAdd",
|
||||
"Actors.Stats",
|
||||
"Body-F",
|
||||
"Body-M",
|
||||
"Body-Size-F",
|
||||
"Body-Size-M",
|
||||
"C.Climate",
|
||||
"C.Light",
|
||||
"C.Music",
|
||||
"C.Name",
|
||||
"C.Owner",
|
||||
"C.RecordFlags",
|
||||
"C.Water",
|
||||
"Creatures.Blood",
|
||||
"Deactivate",
|
||||
"Delev",
|
||||
"Eyes",
|
||||
"Factions",
|
||||
"Filter",
|
||||
"Graphics",
|
||||
"Hair",
|
||||
"IIM",
|
||||
"Invent",
|
||||
"InventOnly",
|
||||
"Merge",
|
||||
"MustBeActiveIfImported",
|
||||
"Names",
|
||||
"NoMerge",
|
||||
"NpcFaces",
|
||||
"NpcFacesForceFullImport",
|
||||
"NPC.Class",
|
||||
"Npc.EyesOnly",
|
||||
"Npc.HairOnly",
|
||||
"NPC.Race",
|
||||
"Relations",
|
||||
"Relev",
|
||||
"Roads",
|
||||
"R.AddSpells",
|
||||
"R.Attributes-F",
|
||||
"R.Attributes-M",
|
||||
"R.ChangeSpells",
|
||||
"R.Description",
|
||||
"R.Ears",
|
||||
"R.Head",
|
||||
"R.Mouth",
|
||||
"R.Relations",
|
||||
"R.Skills",
|
||||
"R.Teeth",
|
||||
"ScriptContents",
|
||||
"Scripts",
|
||||
"Sound",
|
||||
"SpellStats",
|
||||
"Stats",
|
||||
"Voice-F",
|
||||
"Voice-M",
|
||||
};
|
||||
}
|
||||
else if (Id() == GameSettings::tes5) {
|
||||
_name = "TES V: Skyrim";
|
||||
@@ -62,6 +129,78 @@ namespace loot {
|
||||
_masterFile = "Skyrim.esm";
|
||||
_repositoryURL = "https://github.com/loot/skyrim.git";
|
||||
_repositoryBranch = "v0.8";
|
||||
|
||||
bashTags = {
|
||||
"Actors.ACBS",
|
||||
"Actors.AIData",
|
||||
"Actors.AIPackages",
|
||||
"Actors.AIPackagesForceAdd",
|
||||
"Actors.Animations",
|
||||
"Actors.CombatStyle",
|
||||
"Actors.DeathItem",
|
||||
"Actors.Skeleton",
|
||||
"Actors.Spells",
|
||||
"Actors.SpellsForceAdd",
|
||||
"Actors.Stats",
|
||||
"Body-F",
|
||||
"Body-M",
|
||||
"Body-Size-F",
|
||||
"Body-Size-M",
|
||||
"C.Acoustic",
|
||||
"C.Climate",
|
||||
"C.ImageSpace",
|
||||
"C.Light",
|
||||
"C.Location",
|
||||
"C.Music",
|
||||
"C.Name",
|
||||
"C.Owner",
|
||||
"C.RecordFlags",
|
||||
"C.Regions",
|
||||
"C.SkyLighting",
|
||||
"C.Water",
|
||||
"Creatures.Blood",
|
||||
"Deactivate",
|
||||
"Delev",
|
||||
"Eyes",
|
||||
"Factions",
|
||||
"Filter",
|
||||
"Graphics",
|
||||
"Hair",
|
||||
"IIM",
|
||||
"Invent",
|
||||
"InventOnly",
|
||||
"Merge",
|
||||
"MustBeActiveIfImported",
|
||||
"Names",
|
||||
"NoMerge",
|
||||
"NpcFaces",
|
||||
"NpcFacesForceFullImport",
|
||||
"NPC.Class",
|
||||
"Npc.EyesOnly",
|
||||
"Npc.HairOnly",
|
||||
"NPC.Race",
|
||||
"Relations",
|
||||
"Relev",
|
||||
"Roads",
|
||||
"R.AddSpells",
|
||||
"R.Attributes-F",
|
||||
"R.Attributes-M",
|
||||
"R.ChangeSpells",
|
||||
"R.Description",
|
||||
"R.Ears",
|
||||
"R.Head",
|
||||
"R.Mouth",
|
||||
"R.Relations",
|
||||
"R.Skills",
|
||||
"R.Teeth",
|
||||
"ScriptContents",
|
||||
"Scripts",
|
||||
"Sound",
|
||||
"SpellStats",
|
||||
"Stats",
|
||||
"Voice-F",
|
||||
"Voice-M",
|
||||
};
|
||||
}
|
||||
else if (Id() == GameSettings::fo3) {
|
||||
_name = "Fallout 3";
|
||||
@@ -70,6 +209,11 @@ namespace loot {
|
||||
_masterFile = "Fallout3.esm";
|
||||
_repositoryURL = "https://github.com/loot/fallout3.git";
|
||||
_repositoryBranch = "v0.8";
|
||||
|
||||
bashTags = {
|
||||
"Deflst",
|
||||
"Destructible",
|
||||
};
|
||||
}
|
||||
else if (Id() == GameSettings::fonv) {
|
||||
_name = "Fallout: New Vegas";
|
||||
@@ -78,6 +222,12 @@ namespace loot {
|
||||
_masterFile = "FalloutNV.esm";
|
||||
_repositoryURL = "https://github.com/loot/falloutnv.git";
|
||||
_repositoryBranch = "v0.8";
|
||||
|
||||
bashTags = {
|
||||
"Deflst",
|
||||
"Destructible",
|
||||
"WeaponMods",
|
||||
};
|
||||
}
|
||||
else if (Id() == GameSettings::fo4) {
|
||||
_name = "Fallout 4";
|
||||
@@ -191,6 +341,10 @@ namespace loot {
|
||||
return LootPaths::getLootDataPath() / _lootFolderName / "userlist.yaml";
|
||||
}
|
||||
|
||||
std::vector<std::string> GameSettings::getSupportedBashTags() const {
|
||||
return bashTags;
|
||||
}
|
||||
|
||||
GameSettings& GameSettings::SetName(const std::string& name) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Setting \"" << _name << "\" name to: " << name;
|
||||
_name = name;
|
||||
|
||||
@@ -59,6 +59,8 @@ namespace loot {
|
||||
boost::filesystem::path MasterlistPath() const;
|
||||
boost::filesystem::path UserlistPath() const;
|
||||
|
||||
std::vector<std::string> getSupportedBashTags() const;
|
||||
|
||||
GameSettings& SetName(const std::string& name);
|
||||
GameSettings& SetMaster(const std::string& masterFile);
|
||||
GameSettings& SetRegistryKey(const std::string& registry);
|
||||
@@ -84,6 +86,8 @@ namespace loot {
|
||||
std::string _repositoryBranch;
|
||||
|
||||
boost::filesystem::path _gamePath; //Path to the game's folder.
|
||||
|
||||
std::vector<std::string> bashTags;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -701,6 +701,8 @@ namespace loot {
|
||||
// Now store global messages.
|
||||
gameNode["globalMessages"] = GetGeneralMessages();
|
||||
|
||||
gameNode["bashTags"] = _lootState.CurrentGame().getSupportedBashTags();
|
||||
|
||||
// Now store plugin data.
|
||||
for (const auto& plugin : installed) {
|
||||
/* Each plugin has members while hold its raw masterlist and userlist data for
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<link rel="import" href="../../../../bower_components/iron-icons/iron-icons.html">
|
||||
|
||||
<link rel="import" href="../../../../bower_components/paper-autocomplete/paper-autocomplete.html">
|
||||
<link rel="import" href="../../../../bower_components/paper-icon-button/paper-icon-button.html">
|
||||
<link rel="import" href="../../../../bower_components/paper-input/paper-input.html">
|
||||
<link rel="import" href="../../../../bower_components/paper-input/paper-textarea.html">
|
||||
@@ -12,7 +13,7 @@
|
||||
|
||||
<template id="fileRow">
|
||||
<tr>
|
||||
<td><paper-input error-message="A filename is required." class="name" required auto-validate no-label-float></paper-input></td>
|
||||
<td><paper-autocomplete error-message="A filename is required." class="name" required auto-validate no-label-float></paper-autocomplete></td>
|
||||
<td><paper-input class="display" no-label-float></paper-input></td>
|
||||
<td><paper-input class="condition" no-label-float></paper-input></td>
|
||||
<td>
|
||||
@@ -55,7 +56,7 @@
|
||||
<paper-item value="remove">Remove</paper-item>
|
||||
</loot-dropdown-menu>
|
||||
</td>
|
||||
<td><paper-input error-message="A name is required." class="name" required auto-validate no-label-float></paper-input></td>
|
||||
<td><paper-autocomplete error-message="A name is required." class="name" required auto-validate no-label-float></paper-autocomplete></td>
|
||||
<td><paper-input class="condition" no-label-float></paper-input></td>
|
||||
<td>
|
||||
<span>
|
||||
@@ -240,7 +241,7 @@
|
||||
if (trash.length > 0 && (!writableOnly || !trash[0].disabled)) {
|
||||
const rowData = {};
|
||||
|
||||
const inputs = rows[i].querySelectorAll('paper-input, paper-textarea, loot-dropdown-menu');
|
||||
const inputs = rows[i].querySelectorAll('paper-autocomplete, paper-input, paper-textarea, loot-dropdown-menu');
|
||||
for (let j = 0; j < inputs.length; ++j) {
|
||||
rowData[inputs[j].className] = inputs[j].value;
|
||||
}
|
||||
@@ -264,7 +265,7 @@
|
||||
trash.disabled = readOnly;
|
||||
}
|
||||
|
||||
const inputs = row.querySelectorAll('paper-input, paper-textarea, loot-dropdown-menu');
|
||||
const inputs = row.querySelectorAll('paper-autocomplete, paper-input, paper-textarea, loot-dropdown-menu');
|
||||
for (let i = 0; i < inputs.length; ++i) {
|
||||
if (classMask) {
|
||||
for (let j = 0; j < classMask.length; ++j) {
|
||||
@@ -337,7 +338,7 @@
|
||||
},
|
||||
|
||||
validate() {
|
||||
const inputs = this.querySelectorAll('paper-input, paper-textarea');
|
||||
const inputs = this.querySelectorAll('paper-autocomplete, paper-input, paper-textarea');
|
||||
for (let i = 0; i < inputs.length; ++i) {
|
||||
if (!inputs[i].validate()) {
|
||||
return false;
|
||||
|
||||
@@ -235,5 +235,13 @@
|
||||
static onSearchChangeSelection(evt) {
|
||||
document.getElementById('pluginCardList').scrollToIndex(evt.detail.selection);
|
||||
}
|
||||
|
||||
static initialiseAutocompleteFilenames(filenames) {
|
||||
getElementInTableRowTemplate('fileRow', 'name').setAttribute('source', JSON.stringify(filenames));
|
||||
}
|
||||
|
||||
static initialiseAutocompleteBashTags(tags) {
|
||||
getElementInTableRowTemplate('tagRow', 'name').setAttribute('source', JSON.stringify(tags));
|
||||
}
|
||||
};
|
||||
}));
|
||||
|
||||
@@ -59,8 +59,7 @@ function onChangeGame(evt) {
|
||||
const gameInfo = JSON.parse(result, loot.Plugin.fromJson);
|
||||
loot.game = new loot.Game(gameInfo, loot.l10n);
|
||||
|
||||
/* Re-initialise conflicts filter plugin list. */
|
||||
loot.Filters.fillConflictsFilterList(loot.game.plugins);
|
||||
loot.game.initialiseUI(loot.DOM, loot.Filters);
|
||||
|
||||
/* Now update virtual lists. */
|
||||
if (loot.filters.areAnyFiltersActive()) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
this.globalMessages = obj.globalMessages || [];
|
||||
this.masterlist = obj.masterlist || {};
|
||||
this.plugins = obj.plugins || [];
|
||||
this.bashTags = obj.bashTags || [];
|
||||
|
||||
this.oldLoadOrder = undefined;
|
||||
|
||||
@@ -330,6 +331,15 @@
|
||||
});
|
||||
}
|
||||
|
||||
initialiseUI(DOM, Filters) {
|
||||
/* Re-initialise autocomplete suggestions. */
|
||||
DOM.initialiseAutocompleteFilenames(this.getPluginNames());
|
||||
DOM.initialiseAutocompleteBashTags(this.bashTags);
|
||||
|
||||
/* Re-initialise conflicts filter plugin list. */
|
||||
Filters.fillConflictsFilterList(this.plugins);
|
||||
}
|
||||
|
||||
static onPluginsChange(evt) {
|
||||
if (!evt.detail.valuesAreTotals) {
|
||||
evt.detail.totalMessageNo += parseInt(document.getElementById('totalMessageNo').textContent, 10);
|
||||
|
||||
@@ -176,7 +176,7 @@
|
||||
const game = JSON.parse(result, Plugin.fromJson);
|
||||
appData.game = new Game(game, appData.l10n);
|
||||
|
||||
appData.Filters.fillConflictsFilterList(appData.game.plugins);
|
||||
appData.game.initialiseUI(dom, appData.Filters);
|
||||
appData.filters.load(appData.settings.filters);
|
||||
|
||||
/* Initialise the lists before checking if any filters need to be applied.
|
||||
|
||||
@@ -59,6 +59,8 @@ namespace loot {
|
||||
EXPECT_EQ("", game.DataPath());
|
||||
EXPECT_EQ("", game.MasterlistPath());
|
||||
EXPECT_EQ("", game.UserlistPath());
|
||||
|
||||
EXPECT_TRUE(game.getSupportedBashTags().empty());
|
||||
}
|
||||
|
||||
TEST_P(GameSettingsTest, idConstructorShouldInitialiseSettingsToDefaultsForThatGame) {
|
||||
@@ -87,6 +89,180 @@ namespace loot {
|
||||
EXPECT_EQ(LootPaths::getLootDataPath() / "folder" / "userlist.yaml", game.UserlistPath());
|
||||
}
|
||||
|
||||
TEST_P(GameSettingsTest, idConstructorShouldSetCorrectBashTagsForTES4) {
|
||||
game = GameSettings(GameSettings::tes4);
|
||||
|
||||
std::vector<std::string> expectedBashTags = {
|
||||
"Actors.ACBS",
|
||||
"Actors.AIData",
|
||||
"Actors.AIPackages",
|
||||
"Actors.AIPackagesForceAdd",
|
||||
"Actors.Animations",
|
||||
"Actors.CombatStyle",
|
||||
"Actors.DeathItem",
|
||||
"Actors.Skeleton",
|
||||
"Actors.Spells",
|
||||
"Actors.SpellsForceAdd",
|
||||
"Actors.Stats",
|
||||
"Body-F",
|
||||
"Body-M",
|
||||
"Body-Size-F",
|
||||
"Body-Size-M",
|
||||
"C.Climate",
|
||||
"C.Light",
|
||||
"C.Music",
|
||||
"C.Name",
|
||||
"C.Owner",
|
||||
"C.RecordFlags",
|
||||
"C.Water",
|
||||
"Creatures.Blood",
|
||||
"Deactivate",
|
||||
"Delev",
|
||||
"Eyes",
|
||||
"Factions",
|
||||
"Filter",
|
||||
"Graphics",
|
||||
"Hair",
|
||||
"IIM",
|
||||
"Invent",
|
||||
"InventOnly",
|
||||
"Merge",
|
||||
"MustBeActiveIfImported",
|
||||
"Names",
|
||||
"NoMerge",
|
||||
"NpcFaces",
|
||||
"NpcFacesForceFullImport",
|
||||
"NPC.Class",
|
||||
"Npc.EyesOnly",
|
||||
"Npc.HairOnly",
|
||||
"NPC.Race",
|
||||
"Relations",
|
||||
"Relev",
|
||||
"Roads",
|
||||
"R.AddSpells",
|
||||
"R.Attributes-F",
|
||||
"R.Attributes-M",
|
||||
"R.ChangeSpells",
|
||||
"R.Description",
|
||||
"R.Ears",
|
||||
"R.Head",
|
||||
"R.Mouth",
|
||||
"R.Relations",
|
||||
"R.Skills",
|
||||
"R.Teeth",
|
||||
"ScriptContents",
|
||||
"Scripts",
|
||||
"Sound",
|
||||
"SpellStats",
|
||||
"Stats",
|
||||
"Voice-F",
|
||||
"Voice-M",
|
||||
};
|
||||
EXPECT_EQ(expectedBashTags, game.getSupportedBashTags());
|
||||
}
|
||||
|
||||
TEST_P(GameSettingsTest, idConstructorShouldSetCorrectBashTagsForTES5) {
|
||||
game = GameSettings(GameSettings::tes5);
|
||||
|
||||
std::vector<std::string> expectedBashTags = {
|
||||
"Actors.ACBS",
|
||||
"Actors.AIData",
|
||||
"Actors.AIPackages",
|
||||
"Actors.AIPackagesForceAdd",
|
||||
"Actors.Animations",
|
||||
"Actors.CombatStyle",
|
||||
"Actors.DeathItem",
|
||||
"Actors.Skeleton",
|
||||
"Actors.Spells",
|
||||
"Actors.SpellsForceAdd",
|
||||
"Actors.Stats",
|
||||
"Body-F",
|
||||
"Body-M",
|
||||
"Body-Size-F",
|
||||
"Body-Size-M",
|
||||
"C.Acoustic",
|
||||
"C.Climate",
|
||||
"C.ImageSpace",
|
||||
"C.Light",
|
||||
"C.Location",
|
||||
"C.Music",
|
||||
"C.Name",
|
||||
"C.Owner",
|
||||
"C.RecordFlags",
|
||||
"C.Regions",
|
||||
"C.SkyLighting",
|
||||
"C.Water",
|
||||
"Creatures.Blood",
|
||||
"Deactivate",
|
||||
"Delev",
|
||||
"Eyes",
|
||||
"Factions",
|
||||
"Filter",
|
||||
"Graphics",
|
||||
"Hair",
|
||||
"IIM",
|
||||
"Invent",
|
||||
"InventOnly",
|
||||
"Merge",
|
||||
"MustBeActiveIfImported",
|
||||
"Names",
|
||||
"NoMerge",
|
||||
"NpcFaces",
|
||||
"NpcFacesForceFullImport",
|
||||
"NPC.Class",
|
||||
"Npc.EyesOnly",
|
||||
"Npc.HairOnly",
|
||||
"NPC.Race",
|
||||
"Relations",
|
||||
"Relev",
|
||||
"Roads",
|
||||
"R.AddSpells",
|
||||
"R.Attributes-F",
|
||||
"R.Attributes-M",
|
||||
"R.ChangeSpells",
|
||||
"R.Description",
|
||||
"R.Ears",
|
||||
"R.Head",
|
||||
"R.Mouth",
|
||||
"R.Relations",
|
||||
"R.Skills",
|
||||
"R.Teeth",
|
||||
"ScriptContents",
|
||||
"Scripts",
|
||||
"Sound",
|
||||
"SpellStats",
|
||||
"Stats",
|
||||
"Voice-F",
|
||||
"Voice-M",
|
||||
};
|
||||
EXPECT_EQ(expectedBashTags, game.getSupportedBashTags());
|
||||
}
|
||||
|
||||
TEST_P(GameSettingsTest, idConstructorShouldSetNoBashTagsForFO3) {
|
||||
game = GameSettings(GameSettings::fo3);
|
||||
|
||||
std::vector<std::string> expectedBashTags = {
|
||||
"Deflst",
|
||||
"Destructible",
|
||||
};
|
||||
EXPECT_EQ(expectedBashTags, game.getSupportedBashTags());
|
||||
}
|
||||
|
||||
TEST_P(GameSettingsTest, idConstructorShouldSetNoBashTagsForFONV) {
|
||||
game = GameSettings(GameSettings::fonv);
|
||||
|
||||
std::vector<std::string> expectedBashTags = {
|
||||
"Deflst",
|
||||
"Destructible",
|
||||
"WeaponMods",
|
||||
};
|
||||
EXPECT_EQ(expectedBashTags, game.getSupportedBashTags());
|
||||
}
|
||||
|
||||
TEST_P(GameSettingsTest, idConstructorShouldSetNoBashTagsForFO4) {
|
||||
EXPECT_TRUE(GameSettings(GameSettings::fo4).getSupportedBashTags().empty());
|
||||
}
|
||||
|
||||
TEST_P(GameSettingsTest, isInstalledShouldBeFalseIfGamePathIsNotSet) {
|
||||
GameSettings game;
|
||||
EXPECT_FALSE(game.IsInstalled());
|
||||
|
||||
Reference in New Issue
Block a user