mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
Add update_cards_scripts
This commit is contained in:
@@ -87,6 +87,31 @@ void AddCardAction::perform(bool to_undo) {
|
|||||||
set.buildUIDMap();
|
set.buildUIDMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateCardAction::UpdateCardAction(Set& set, const vector<CardP>& cards_to_add, const vector<CardP>& cards_to_remove)
|
||||||
|
: CardListAction(set)
|
||||||
|
, action_add(ADD, set, cards_to_add)
|
||||||
|
, action_remove(REMOVE, set, cards_to_remove)
|
||||||
|
{}
|
||||||
|
|
||||||
|
String UpdateCardAction::getName(bool to_undo) const {
|
||||||
|
return _ACTION_("update card");
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateCardAction::perform(bool to_undo) {
|
||||||
|
if (to_undo) {
|
||||||
|
action_remove.perform(to_undo);
|
||||||
|
set.actions.tellListeners(action_remove, to_undo);
|
||||||
|
action_add.perform(to_undo);
|
||||||
|
set.actions.tellListeners(action_add, to_undo);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
action_add.perform(to_undo);
|
||||||
|
set.actions.tellListeners(action_add, to_undo);
|
||||||
|
action_remove.perform(to_undo);
|
||||||
|
set.actions.tellListeners(action_remove, to_undo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Reorder cards
|
// ----------------------------------------------------------------------------- : Reorder cards
|
||||||
|
|
||||||
ReorderCardsAction::ReorderCardsAction(Set& set, size_t card_id1, size_t card_id2)
|
ReorderCardsAction::ReorderCardsAction(Set& set, size_t card_id1, size_t card_id2)
|
||||||
|
|||||||
@@ -50,6 +50,18 @@ public:
|
|||||||
vector<ActionP> card_link_actions;
|
vector<ActionP> card_link_actions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Update one or more cards from a set by replacing them with other cards
|
||||||
|
class UpdateCardAction : public CardListAction {
|
||||||
|
public:
|
||||||
|
UpdateCardAction(Set& set, const vector<CardP>& cards_to_add, const vector<CardP>& cards_to_remove);
|
||||||
|
|
||||||
|
String getName(bool to_undo) const override;
|
||||||
|
void perform(bool to_undo) override;
|
||||||
|
|
||||||
|
AddCardAction action_add;
|
||||||
|
AddCardAction action_remove;
|
||||||
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Reorder cards
|
// ----------------------------------------------------------------------------- : Reorder cards
|
||||||
|
|
||||||
/// Change the position of a card in the card list by swapping two cards
|
/// Change the position of a card in the card list by swapping two cards
|
||||||
|
|||||||
@@ -400,8 +400,10 @@ String BulkAction::getName(bool to_undo) const {
|
|||||||
return to_undo ? name_undo : name_do;
|
return to_undo ? name_undo : name_do;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BulkAction::perform(bool to_undo) {
|
void BulkAction::perform(bool to_undo) {
|
||||||
FOR_EACH(action, actions) {
|
size_t size = actions.size();
|
||||||
|
for (size_t i = 0 ; i < size ; ++i) {
|
||||||
|
ActionP& action = actions[to_undo ? size - i - 1 : i];
|
||||||
action->perform(to_undo);
|
action->perform(to_undo);
|
||||||
set->actions.tellListeners(*action, to_undo);
|
set->actions.tellListeners(*action, to_undo);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,18 +25,22 @@ IMPLEMENT_REFLECTION_NO_SCRIPT(AddCardsScript) {
|
|||||||
|
|
||||||
void AddCardsScript::perform(Set& set, vector<CardP>& out) {
|
void AddCardsScript::perform(Set& set, vector<CardP>& out) {
|
||||||
// Perform script
|
// Perform script
|
||||||
Context& ctx = set.getContext();
|
Context& ctx = set.getContext();
|
||||||
|
if (enabled.hasBeenRead()) {
|
||||||
|
enabled.update(ctx);
|
||||||
|
if (!enabled()) return;
|
||||||
|
}
|
||||||
ScriptValueP result = script.invoke(ctx);
|
ScriptValueP result = script.invoke(ctx);
|
||||||
// Add cards to out
|
// Add cards to out
|
||||||
ScriptValueP it = result->makeIterator();
|
ScriptValueP it = result->makeIterator();
|
||||||
while (ScriptValueP item = it->next()) {
|
while (ScriptValueP item = it->next()) {
|
||||||
CardP card = from_script<CardP>(item);
|
CardP new_card = from_script<CardP>(item);
|
||||||
// is this a new card?
|
// is this a new card?
|
||||||
if (contains(set.cards,card) || contains(out,card)) {
|
if (contains(set.cards,new_card) || contains(out,new_card)) {
|
||||||
// make copy
|
// make copy
|
||||||
card = make_intrusive<Card>(*card);
|
new_card = make_intrusive<Card>(&set, new_card);
|
||||||
}
|
}
|
||||||
out.push_back(card);
|
out.push_back(new_card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+38
-2
@@ -42,7 +42,38 @@ Card::Card(Game& game)
|
|||||||
, has_styling(false)
|
, has_styling(false)
|
||||||
{
|
{
|
||||||
data.init(game.card_fields);
|
data.init(game.card_fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Card::Card(Set* set, const CardP& card)
|
||||||
|
: game(card->game)
|
||||||
|
, time_created (wxDateTime::Now())
|
||||||
|
, time_modified(wxDateTime::Now())
|
||||||
|
, notes(card->notes)
|
||||||
|
, uid(generate_uid())
|
||||||
|
, linked_card_1(card->linked_card_1)
|
||||||
|
, linked_card_2(card->linked_card_2)
|
||||||
|
, linked_card_3(card->linked_card_3)
|
||||||
|
, linked_card_4(card->linked_card_4)
|
||||||
|
, linked_relation_1(card->linked_relation_1)
|
||||||
|
, linked_relation_2(card->linked_relation_2)
|
||||||
|
, linked_relation_3(card->linked_relation_3)
|
||||||
|
, linked_relation_4(card->linked_relation_4)
|
||||||
|
, has_styling(card->has_styling)
|
||||||
|
, stylesheet_version(card->stylesheet_version)
|
||||||
|
, stylesheet(card->stylesheet)
|
||||||
|
{
|
||||||
|
if (!stylesheet && set) {
|
||||||
|
stylesheet = set->stylesheetForP(card);
|
||||||
|
}
|
||||||
|
if (has_styling) {
|
||||||
|
styling_data.cloneFrom(card->styling_data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (stylesheet && set) styling_data.cloneFrom(set->stylingDataFor(*stylesheet));
|
||||||
|
}
|
||||||
|
data.cloneFrom(card->data);
|
||||||
|
extra_data.cloneFrom(card->extra_data);
|
||||||
|
}
|
||||||
|
|
||||||
String Card::identification() const {
|
String Card::identification() const {
|
||||||
// an identifying field
|
// an identifying field
|
||||||
@@ -344,7 +375,12 @@ void reflect_version_check(GetDefaultMember& handler, const Char* key, intrusive
|
|||||||
|
|
||||||
IMPLEMENT_REFLECTION(Card) {
|
IMPLEMENT_REFLECTION(Card) {
|
||||||
REFLECT(stylesheet);
|
REFLECT(stylesheet);
|
||||||
reflect_version_check(handler, _("stylesheet_version"), stylesheet);
|
if (Handler::isReading) {
|
||||||
|
REFLECT_NO_SCRIPT(stylesheet_version);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
reflect_version_check(handler, _("stylesheet_version"), stylesheet);
|
||||||
|
}
|
||||||
REFLECT(has_styling);
|
REFLECT(has_styling);
|
||||||
if (has_styling) {
|
if (has_styling) {
|
||||||
if (stylesheet) {
|
if (stylesheet) {
|
||||||
|
|||||||
+5
-1
@@ -35,6 +35,8 @@ public:
|
|||||||
Card();
|
Card();
|
||||||
/// Creates a card using the given game
|
/// Creates a card using the given game
|
||||||
Card(Game& game);
|
Card(Game& game);
|
||||||
|
/// Copy constructor, makes a deep copy
|
||||||
|
Card(Set* set, const CardP& card);
|
||||||
|
|
||||||
/// The game this card is made for
|
/// The game this card is made for
|
||||||
Game* game;
|
Game* game;
|
||||||
@@ -60,7 +62,9 @@ public:
|
|||||||
wxDateTime time_created, time_modified;
|
wxDateTime time_created, time_modified;
|
||||||
/// Alternative style to use for this card
|
/// Alternative style to use for this card
|
||||||
/** Optional; if not set use the card style from the set */
|
/** Optional; if not set use the card style from the set */
|
||||||
StyleSheetP stylesheet;
|
StyleSheetP stylesheet;
|
||||||
|
/// What version of the stylesheet was this card using when it was last saved?
|
||||||
|
Version stylesheet_version;
|
||||||
/// Alternative options to use for this card, for this card's stylesheet
|
/// Alternative options to use for this card, for this card's stylesheet
|
||||||
/** Optional; if not set use the styling data from the set.
|
/** Optional; if not set use the styling data from the set.
|
||||||
* If stylesheet is set then contains data for the this->stylesheet, otherwise for set->stylesheet
|
* If stylesheet is set then contains data for the this->stylesheet, otherwise for set->stylesheet
|
||||||
|
|||||||
+6
-3
@@ -16,6 +16,7 @@
|
|||||||
#include <data/pack.hpp>
|
#include <data/pack.hpp>
|
||||||
#include <data/word_list.hpp>
|
#include <data/word_list.hpp>
|
||||||
#include <data/add_cards_script.hpp>
|
#include <data/add_cards_script.hpp>
|
||||||
|
#include <data/update_cards_script.hpp>
|
||||||
#include <util/io/package_manager.hpp>
|
#include <util/io/package_manager.hpp>
|
||||||
#include <script/script.hpp>
|
#include <script/script.hpp>
|
||||||
|
|
||||||
@@ -55,7 +56,6 @@ IMPLEMENT_REFLECTION(Game) {
|
|||||||
REFLECT_NO_SCRIPT(json_paths);
|
REFLECT_NO_SCRIPT(json_paths);
|
||||||
REFLECT_NO_SCRIPT(statistics_dimensions);
|
REFLECT_NO_SCRIPT(statistics_dimensions);
|
||||||
REFLECT_NO_SCRIPT(statistics_categories);
|
REFLECT_NO_SCRIPT(statistics_categories);
|
||||||
REFLECT_COMPAT(<308, "pack_item", pack_types);
|
|
||||||
REFLECT_NO_SCRIPT(pack_types);
|
REFLECT_NO_SCRIPT(pack_types);
|
||||||
REFLECT_NO_SCRIPT(keyword_match_script);
|
REFLECT_NO_SCRIPT(keyword_match_script);
|
||||||
REFLECT(has_keywords);
|
REFLECT(has_keywords);
|
||||||
@@ -63,7 +63,8 @@ IMPLEMENT_REFLECTION(Game) {
|
|||||||
REFLECT(keyword_parameter_types);
|
REFLECT(keyword_parameter_types);
|
||||||
REFLECT_NO_SCRIPT(keywords);
|
REFLECT_NO_SCRIPT(keywords);
|
||||||
REFLECT_NO_SCRIPT(word_lists);
|
REFLECT_NO_SCRIPT(word_lists);
|
||||||
REFLECT_NO_SCRIPT(add_cards_scripts);
|
REFLECT_NO_SCRIPT(add_cards_scripts);
|
||||||
|
REFLECT_NO_SCRIPT(update_cards_scripts);
|
||||||
REFLECT_NO_SCRIPT(auto_replaces);
|
REFLECT_NO_SCRIPT(auto_replaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +206,9 @@ void Game::validate(Version v) {
|
|||||||
}
|
}
|
||||||
card_links_alt_names.emplace(linked_tr, linked_default);
|
card_links_alt_names.emplace(linked_tr, linked_default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// sort the update_cards_scripts from oldest to newest
|
||||||
|
std::sort(update_cards_scripts.begin(), update_cards_scripts.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::initCardListColorScript() {
|
void Game::initCardListColorScript() {
|
||||||
|
|||||||
+23
-21
@@ -26,6 +26,7 @@ DECLARE_POINTER_TYPE(KeywordMode);
|
|||||||
DECLARE_POINTER_TYPE(Keyword);
|
DECLARE_POINTER_TYPE(Keyword);
|
||||||
DECLARE_POINTER_TYPE(WordList);
|
DECLARE_POINTER_TYPE(WordList);
|
||||||
DECLARE_POINTER_TYPE(AddCardsScript);
|
DECLARE_POINTER_TYPE(AddCardsScript);
|
||||||
|
DECLARE_POINTER_TYPE(UpdateCardsScript);
|
||||||
DECLARE_POINTER_TYPE(AutoReplace);
|
DECLARE_POINTER_TYPE(AutoReplace);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Game
|
// ----------------------------------------------------------------------------- : Game
|
||||||
@@ -38,27 +39,28 @@ class Game : public Packaged {
|
|||||||
public:
|
public:
|
||||||
Game();
|
Game();
|
||||||
|
|
||||||
OptionalScript init_script; ///< Script of variables available to other scripts in this game
|
OptionalScript init_script; ///< Script of variables available to other scripts in this game
|
||||||
vector<FieldP> set_fields; ///< Fields for set information
|
vector<FieldP> set_fields; ///< Fields for set information
|
||||||
IndexMap<FieldP,StyleP> default_set_style; ///< Default style for the set fields, because it is often the same
|
IndexMap<FieldP,StyleP> default_set_style; ///< Default style for the set fields, because it is often the same
|
||||||
vector<FieldP> card_fields; ///< Fields on each card
|
vector<FieldP> card_fields; ///< Fields on each card
|
||||||
vector<CardLinkP> card_links; ///< Possible links between cards
|
vector<CardLinkP> card_links; ///< Possible links between cards
|
||||||
OptionalScript card_list_color_script; ///< Script that determines the color of items in the card list
|
OptionalScript card_list_color_script; ///< Script that determines the color of items in the card list
|
||||||
OptionalScript import_script; ///< Script applied as the last step of the new_card function
|
OptionalScript import_script; ///< Script applied as the last step of the new_card function
|
||||||
vector<String> json_paths; ///< Paths inside JSON files to find the card array
|
vector<String> json_paths; ///< Paths inside JSON files to find the card array
|
||||||
vector<StatsDimensionP> statistics_dimensions; ///< (Additional) statistics dimensions
|
vector<StatsDimensionP> statistics_dimensions; ///< (Additional) statistics dimensions
|
||||||
vector<StatsCategoryP> statistics_categories; ///< (Additional) statistics categories
|
vector<StatsCategoryP> statistics_categories; ///< (Additional) statistics categories
|
||||||
vector<PackTypeP> pack_types; ///< Types of random card packs to generate
|
vector<PackTypeP> pack_types; ///< Types of random card packs to generate
|
||||||
vector<WordListP> word_lists; ///< Word lists for editing with a drop down list
|
vector<WordListP> word_lists; ///< Word lists for editing with a drop down list
|
||||||
vector<AddCardsScriptP> add_cards_scripts; ///< Scripts for adding multiple cards to the set
|
vector<AddCardsScriptP> add_cards_scripts; ///< Scripts for adding multiple cards to the set
|
||||||
vector<AutoReplaceP> auto_replaces; ///< Things to autoreplace in textboxes
|
vector<UpdateCardsScriptP> update_cards_scripts; ///< Scripts for updating cards made with an earlier version of this game
|
||||||
map<String,String> card_fields_alt_names; ///< Other names that fields might go by, for example in CSV files
|
vector<AutoReplaceP> auto_replaces; ///< Things to autoreplace in textboxes
|
||||||
map<String,String> card_links_alt_names; ///< Localized names that card links go by
|
map<String,String> card_fields_alt_names; ///< Other names that fields might go by, for example in CSV files
|
||||||
bool has_keywords; ///< Does this game use keywords?
|
map<String,String> card_links_alt_names; ///< Localized names that card links go by
|
||||||
OptionalScript keyword_match_script; ///< For the keyword editor
|
bool has_keywords; ///< Does this game use keywords?
|
||||||
vector<KeywordParamP> keyword_parameter_types;///< Types of keyword parameters
|
OptionalScript keyword_match_script; ///< For the keyword editor
|
||||||
vector<KeywordModeP> keyword_modes; ///< Modes of keywords
|
vector<KeywordParamP> keyword_parameter_types;///< Types of keyword parameters
|
||||||
vector<KeywordP> keywords; ///< Keywords for use in text
|
vector<KeywordModeP> keyword_modes; ///< Modes of keywords
|
||||||
|
vector<KeywordP> keywords; ///< Keywords for use in text
|
||||||
|
|
||||||
Dependencies dependent_scripts_cards; ///< scripts that depend on the card list
|
Dependencies dependent_scripts_cards; ///< scripts that depend on the card list
|
||||||
Dependencies dependent_scripts_keywords; ///< scripts that depend on the keywords
|
Dependencies dependent_scripts_keywords; ///< scripts that depend on the keywords
|
||||||
|
|||||||
@@ -85,7 +85,6 @@ bool Keyword::contains(QuickFilterPart const& query) const {
|
|||||||
|
|
||||||
IMPLEMENT_REFLECTION(Keyword) {
|
IMPLEMENT_REFLECTION(Keyword) {
|
||||||
REFLECT(keyword);
|
REFLECT(keyword);
|
||||||
if (handler.formatVersion() < 301) read_compat(handler, this);
|
|
||||||
REFLECT(match);
|
REFLECT(match);
|
||||||
REFLECT(reminder);
|
REFLECT(reminder);
|
||||||
REFLECT(rules);
|
REFLECT(rules);
|
||||||
|
|||||||
+56
-9
@@ -14,6 +14,7 @@
|
|||||||
#include <data/keyword.hpp>
|
#include <data/keyword.hpp>
|
||||||
#include <data/pack.hpp>
|
#include <data/pack.hpp>
|
||||||
#include <data/field.hpp>
|
#include <data/field.hpp>
|
||||||
|
#include <data/update_cards_script.hpp>
|
||||||
#include <data/field/text.hpp> // for 0.2.7 fix
|
#include <data/field/text.hpp> // for 0.2.7 fix
|
||||||
#include <data/field/information.hpp>
|
#include <data/field/information.hpp>
|
||||||
#include <data/field/image.hpp>
|
#include <data/field/image.hpp>
|
||||||
@@ -172,7 +173,7 @@ void fix_value_207(const ValueP& value) {
|
|||||||
|
|
||||||
void Set::validate(Version file_app_version) {
|
void Set::validate(Version file_app_version) {
|
||||||
Packaged::validate(file_app_version);
|
Packaged::validate(file_app_version);
|
||||||
// are the
|
// are the game and stylesheet defined?
|
||||||
if (!game) {
|
if (!game) {
|
||||||
throw Error(_ERROR_1_("no game specified",_TYPE_("set")));
|
throw Error(_ERROR_1_("no game specified",_TYPE_("set")));
|
||||||
}
|
}
|
||||||
@@ -183,7 +184,9 @@ void Set::validate(Version file_app_version) {
|
|||||||
if (stylesheet->game != game) {
|
if (stylesheet->game != game) {
|
||||||
throw Error(_ERROR_("stylesheet and set refer to different game"));
|
throw Error(_ERROR_("stylesheet and set refer to different game"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We can probably retire this
|
||||||
|
/*
|
||||||
// This is our chance to fix version incompatabilities
|
// This is our chance to fix version incompatabilities
|
||||||
if (file_app_version < 207) {
|
if (file_app_version < 207) {
|
||||||
// Since 0.2.7 we use </tag> style close tags, in older versions it was </>
|
// Since 0.2.7 we use </tag> style close tags, in older versions it was </>
|
||||||
@@ -192,16 +195,52 @@ void Set::validate(Version file_app_version) {
|
|||||||
FOR_EACH(v, c->data) fix_value_207(v);
|
FOR_EACH(v, c->data) fix_value_207(v);
|
||||||
}
|
}
|
||||||
FOR_EACH(v, data) fix_value_207(v);
|
FOR_EACH(v, data) fix_value_207(v);
|
||||||
/* FOR_EACH(s, styleData) {
|
FOR_EACH(s, styleData) {
|
||||||
FOR_EACH(v, s.second->data) fix_value_207(v);
|
FOR_EACH(v, s.second->data) fix_value_207(v);
|
||||||
}
|
}
|
||||||
*/ }
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// we want at least one card
|
// we want at least one card
|
||||||
if (cards.empty()) cards.push_back(make_intrusive<Card>(*game));
|
if (cards.empty()) cards.push_back(make_intrusive<Card>(*game));
|
||||||
// update scripts
|
// update scripts
|
||||||
script_manager->updateAll();
|
script_manager->updateAll();
|
||||||
// build uid map
|
// build uid map
|
||||||
buildUIDMap();
|
buildUIDMap();
|
||||||
|
// update cards with game update_cards_scripts
|
||||||
|
for (int j = 0; j < game->update_cards_scripts.size(); ++j) {
|
||||||
|
UpdateCardsScriptP& script = game->update_cards_scripts[j];
|
||||||
|
if (game_version >= script->before_version) continue;
|
||||||
|
size_t size = cards.size();
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
CardP& card = cards[i];
|
||||||
|
vector<CardP> new_cards = script->perform(*this, card);
|
||||||
|
if (!new_cards.empty()) {
|
||||||
|
--i;
|
||||||
|
--size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// update cards with stylesheet update_cards_scripts
|
||||||
|
for (int i = 0; i < cards.size(); ++i) {
|
||||||
|
CardP& card = cards[i];
|
||||||
|
StyleSheetP stylesheet = stylesheetForP(card);
|
||||||
|
for (int j = 0; j < stylesheet->update_cards_scripts.size(); ++j) {
|
||||||
|
UpdateCardsScriptP& script = stylesheet->update_cards_scripts[j];
|
||||||
|
if (card->stylesheet_version >= script->before_version) continue;
|
||||||
|
vector<CardP> new_cards = script->perform(*this, card);
|
||||||
|
if (!new_cards.empty()) {
|
||||||
|
FOR_EACH(new_card, new_cards) {
|
||||||
|
// Initialize the stylesheet_version if it wasn't defined, to prevent this script from applying again
|
||||||
|
if (stylesheet == stylesheetForP(new_card) && new_card->stylesheet_version < script->before_version) {
|
||||||
|
new_card->stylesheet_version = script->before_version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reflect_version_check(Reader& handler, const Char* key, intrusive_ptr<Packaged> const& package) {
|
void reflect_version_check(Reader& handler, const Char* key, intrusive_ptr<Packaged> const& package) {
|
||||||
@@ -225,15 +264,23 @@ IMPLEMENT_REFLECTION(Set) {
|
|||||||
REFLECT_IF_READING {
|
REFLECT_IF_READING {
|
||||||
data.init(game->set_fields);
|
data.init(game->set_fields);
|
||||||
}
|
}
|
||||||
reflect_version_check(handler, _("game_version"), game);
|
if (Handler::isReading) {
|
||||||
|
REFLECT_NO_SCRIPT(game_version);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
reflect_version_check(handler, _("game_version"), game);
|
||||||
|
}
|
||||||
WITH_DYNAMIC_ARG(game_for_reading, game.get());
|
WITH_DYNAMIC_ARG(game_for_reading, game.get());
|
||||||
REFLECT(stylesheet);
|
REFLECT(stylesheet);
|
||||||
REFLECT_COMPAT(<300, "style", stylesheet);
|
if (Handler::isReading) {
|
||||||
reflect_version_check(handler, _("stylesheet_version"), stylesheet);
|
REFLECT_NO_SCRIPT(stylesheet_version);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
reflect_version_check(handler, _("stylesheet_version"), stylesheet);
|
||||||
|
}
|
||||||
WITH_DYNAMIC_ARG(stylesheet_for_reading, stylesheet.get());
|
WITH_DYNAMIC_ARG(stylesheet_for_reading, stylesheet.get());
|
||||||
REFLECT_N("set_info", data);
|
REFLECT_N("set_info", data);
|
||||||
if (stylesheet) {
|
if (stylesheet) {
|
||||||
REFLECT_COMPAT(<300, "extra_set_info", styling_data);
|
|
||||||
REFLECT_N("styling", styling_data);
|
REFLECT_N("styling", styling_data);
|
||||||
}
|
}
|
||||||
// Experimental: save each card to a different file
|
// Experimental: save each card to a different file
|
||||||
|
|||||||
+5
-1
@@ -61,7 +61,11 @@ public:
|
|||||||
ActionStack actions; ///< Actions performed on this set and the cards in it
|
ActionStack actions; ///< Actions performed on this set and the cards in it
|
||||||
KeywordDatabase keyword_db; ///< Database for matching keywords, must be cleared when keywords change
|
KeywordDatabase keyword_db; ///< Database for matching keywords, must be cleared when keywords change
|
||||||
VCSP vcs; ///< The version control system to use
|
VCSP vcs; ///< The version control system to use
|
||||||
|
/// What version of the game was this set using when it was last saved?
|
||||||
|
Version game_version;
|
||||||
|
/// What version of the default stylesheet was this set using when it was last saved?
|
||||||
|
Version stylesheet_version;
|
||||||
|
|
||||||
/// A context for performing scripts
|
/// A context for performing scripts
|
||||||
/** Should only be used from the main thread! */
|
/** Should only be used from the main thread! */
|
||||||
Context& getContext();
|
Context& getContext();
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <data/stylesheet.hpp>
|
#include <data/stylesheet.hpp>
|
||||||
#include <data/game.hpp>
|
#include <data/game.hpp>
|
||||||
#include <data/field.hpp>
|
#include <data/field.hpp>
|
||||||
|
#include <data/update_cards_script.hpp>
|
||||||
#include <util/io/package_manager.hpp>
|
#include <util/io/package_manager.hpp>
|
||||||
#include <gui/new_window.hpp> // for selecting stylesheets on load error
|
#include <gui/new_window.hpp> // for selecting stylesheets on load error
|
||||||
|
|
||||||
@@ -75,7 +76,11 @@ void StyleSheet::validate(Version ver) {
|
|||||||
throw Error(_ERROR_1_("no game specified",_TYPE_("stylesheet")));
|
throw Error(_ERROR_1_("no game specified",_TYPE_("stylesheet")));
|
||||||
}
|
}
|
||||||
// a stylesheet depends on the game it is made for
|
// a stylesheet depends on the game it is made for
|
||||||
requireDependency(game.get());
|
requireDependency(game.get());
|
||||||
|
// sort the update_cards_scripts from oldest to newest
|
||||||
|
std::sort(update_cards_scripts.begin(), update_cards_scripts.end(), [](const auto& a, const auto& b) {
|
||||||
|
return *a < *b;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -125,6 +130,7 @@ IMPLEMENT_REFLECTION(StyleSheet) {
|
|||||||
extra_card_style.init(extra_card_fields);
|
extra_card_style.init(extra_card_fields);
|
||||||
}
|
}
|
||||||
REFLECT(extra_card_style);
|
REFLECT(extra_card_style);
|
||||||
|
REFLECT_NO_SCRIPT(update_cards_scripts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ DECLARE_POINTER_TYPE(StyleSheet);
|
|||||||
DECLARE_POINTER_TYPE(Field);
|
DECLARE_POINTER_TYPE(Field);
|
||||||
DECLARE_POINTER_TYPE(Style);
|
DECLARE_POINTER_TYPE(Style);
|
||||||
DECLARE_POINTER_TYPE(CardRegion);
|
DECLARE_POINTER_TYPE(CardRegion);
|
||||||
|
DECLARE_POINTER_TYPE(UpdateCardsScript);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : StyleSheet
|
// ----------------------------------------------------------------------------- : StyleSheet
|
||||||
|
|
||||||
@@ -33,12 +34,13 @@ class StyleSheet : public Packaged {
|
|||||||
public:
|
public:
|
||||||
StyleSheet();
|
StyleSheet();
|
||||||
|
|
||||||
GameP game; ///< The game this stylesheet is made for
|
GameP game; ///< The game this stylesheet is made for
|
||||||
OptionalScript init_script; ///< Script of variables available to other scripts in this stylesheet
|
OptionalScript init_script; ///< Script of variables available to other scripts in this stylesheet
|
||||||
double card_width; ///< The width of a card in pixels
|
vector<UpdateCardsScriptP> update_cards_scripts; ///< Scripts for updating cards made with an earlier version of this stylesheet
|
||||||
double card_height; ///< The height of a card in pixels
|
double card_width; ///< The width of a card in pixels
|
||||||
double card_dpi; ///< The resolution of a card in dots per inch
|
double card_height; ///< The height of a card in pixels
|
||||||
Color card_background; ///< The background color of cards
|
double card_dpi; ///< The resolution of a card in dots per inch
|
||||||
|
Color card_background; ///< The background color of cards
|
||||||
vector<CardRegionP> card_regions;
|
vector<CardRegionP> card_regions;
|
||||||
/// The styling for card fields
|
/// The styling for card fields
|
||||||
/** The indices should correspond to the card_fields in the Game */
|
/** The indices should correspond to the card_fields in the Game */
|
||||||
|
|||||||
@@ -178,7 +178,6 @@ IMPLEMENT_REFLECTION(SymbolInFont) {
|
|||||||
REFLECT(draw_text);
|
REFLECT(draw_text);
|
||||||
REFLECT(text_font);
|
REFLECT(text_font);
|
||||||
REFLECT(text_alignment);
|
REFLECT(text_alignment);
|
||||||
REFLECT_COMPAT(<300,"text_align",text_alignment);
|
|
||||||
REFLECT(text_margin_left);
|
REFLECT(text_margin_left);
|
||||||
REFLECT(text_margin_right);
|
REFLECT(text_margin_right);
|
||||||
REFLECT(text_margin_top);
|
REFLECT(text_margin_top);
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
//| Description: Magic Set Editor - Program to make card games |
|
||||||
|
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
|
||||||
|
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Includes
|
||||||
|
|
||||||
|
#include <util/prec.hpp>
|
||||||
|
#include <data/update_cards_script.hpp>
|
||||||
|
#include <data/action/set.hpp>
|
||||||
|
#include <data/set.hpp>
|
||||||
|
#include <data/card.hpp>
|
||||||
|
#include <data/stylesheet.hpp>
|
||||||
|
#include <data/action/value.hpp>
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : UpdateCardsScript
|
||||||
|
|
||||||
|
IMPLEMENT_REFLECTION_NO_SCRIPT(UpdateCardsScript) {
|
||||||
|
REFLECT(before_version);
|
||||||
|
REFLECT(description);
|
||||||
|
REFLECT(enabled);
|
||||||
|
REFLECT(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void UpdateCardsScript::perform(Set& set, CardP& card, vector<CardP>& out) {
|
||||||
|
// Perform script
|
||||||
|
Context& ctx = set.getContext(card);
|
||||||
|
if (enabled.hasBeenRead()) {
|
||||||
|
enabled.update(ctx);
|
||||||
|
if (!enabled()) return;
|
||||||
|
}
|
||||||
|
ScriptValueP result = script.invoke(ctx);
|
||||||
|
// Add cards to out
|
||||||
|
ScriptValueP it = result->makeIterator();
|
||||||
|
while (ScriptValueP item = it->next()) {
|
||||||
|
CardP new_card = from_script<CardP>(item);
|
||||||
|
// is this a new card?
|
||||||
|
if (contains(set.cards,new_card) || contains(out,new_card)) {
|
||||||
|
// make copy
|
||||||
|
new_card = make_intrusive<Card>(&set, new_card);
|
||||||
|
}
|
||||||
|
out.push_back(new_card);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<CardP> UpdateCardsScript::perform(Set& set, CardP card) {
|
||||||
|
// Perform script
|
||||||
|
vector<CardP> cards;
|
||||||
|
perform(set, card, cards);
|
||||||
|
// Add to set
|
||||||
|
if (!cards.empty()) {
|
||||||
|
set.actions.addAction(make_unique<UpdateCardAction>(set, cards, vector<CardP>{card}), false);
|
||||||
|
}
|
||||||
|
return cards;
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
//| Description: Magic Set Editor - Program to make card games |
|
||||||
|
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
|
||||||
|
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Includes
|
||||||
|
|
||||||
|
#include <util/prec.hpp>
|
||||||
|
#include <script/scriptable.hpp>
|
||||||
|
|
||||||
|
class Set;
|
||||||
|
DECLARE_POINTER_TYPE(Card);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : UpdateCardsScript
|
||||||
|
|
||||||
|
/// A script to add one or more cards to a set
|
||||||
|
class UpdateCardsScript : public IntrusivePtrBase<UpdateCardsScript> {
|
||||||
|
public:
|
||||||
|
Version before_version;
|
||||||
|
String description;
|
||||||
|
Scriptable<bool> enabled;
|
||||||
|
OptionalScript script;
|
||||||
|
|
||||||
|
bool operator < (const UpdateCardsScript& other) const {
|
||||||
|
return before_version < other.before_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform the script; return the cards (if any)
|
||||||
|
void perform(Set& set, CardP& card, vector<CardP>& out);
|
||||||
|
/// Perform the script; add cards to the set
|
||||||
|
vector<CardP> perform(Set& set, CardP card); // don't use CardP& here, because set.cards may get reallocated which would invalidate the ref
|
||||||
|
|
||||||
|
DECLARE_REFLECTION();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -376,12 +376,12 @@ bool CardListBase::parseText(String& text, vector<CardP>& out) {
|
|||||||
if (ScriptCustomCollection* custom = dynamic_cast<ScriptCustomCollection*>(sv.get())) {
|
if (ScriptCustomCollection* custom = dynamic_cast<ScriptCustomCollection*>(sv.get())) {
|
||||||
for (size_t i = 0; i < custom->value.size(); i++) {
|
for (size_t i = 0; i < custom->value.size(); i++) {
|
||||||
if (ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(custom->value[i].get())) {
|
if (ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(custom->value[i].get())) {
|
||||||
out.push_back(make_intrusive<Card>(*c->getValue()));
|
out.push_back(c->getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(sv.get())) {
|
} else if (ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(sv.get())) {
|
||||||
out.push_back(make_intrusive<Card>(*c->getValue()));
|
out.push_back(c->getValue());
|
||||||
}
|
}
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
|
|
||||||
|
|||||||
@@ -26,11 +26,13 @@
|
|||||||
|
|
||||||
SCRIPT_FUNCTION(new_card) {
|
SCRIPT_FUNCTION(new_card) {
|
||||||
SCRIPT_PARAM(GameP, game);
|
SCRIPT_PARAM(GameP, game);
|
||||||
|
ScriptValueP set_ = ctx.getVariableOpt(BOOST_PP_CAT(L, "set")); // this is just SCRIPT_OPTIONAL_PARAM_(Set*, set) but the macro fails
|
||||||
|
Set* set = set_ && set_ != script_nil ? from_script<Set*>(set_, BOOST_PP_CAT(L, "set")) : nullptr;
|
||||||
SCRIPT_OPTIONAL_PARAM_(bool, ignore_field_not_found);
|
SCRIPT_OPTIONAL_PARAM_(bool, ignore_field_not_found);
|
||||||
// create a new card object
|
SCRIPT_OPTIONAL_PARAM_(CardP, copy_from);
|
||||||
CardP new_card = make_intrusive<Card>(*game);
|
|
||||||
// iterate on the given key/value pairs
|
|
||||||
SCRIPT_PARAM(ScriptValueP, input);
|
SCRIPT_PARAM(ScriptValueP, input);
|
||||||
|
// create a new card object, or a copy
|
||||||
|
CardP new_card = copy_from ? make_intrusive<Card>(set, copy_from) : make_intrusive<Card>(*game);
|
||||||
// check for a stylesheet first, since other things depend on it
|
// check for a stylesheet first, since other things depend on it
|
||||||
ScriptValueP it = input->makeIterator();
|
ScriptValueP it = input->makeIterator();
|
||||||
ScriptValueP key;
|
ScriptValueP key;
|
||||||
@@ -39,7 +41,7 @@ SCRIPT_FUNCTION(new_card) {
|
|||||||
if (key == script_nil || value == script_nil) continue;
|
if (key == script_nil || value == script_nil) continue;
|
||||||
String key_name = key->toString();
|
String key_name = key->toString();
|
||||||
if (set_stylesheet_container(*game, new_card, value, key_name, ignore_field_not_found)) break;
|
if (set_stylesheet_container(*game, new_card, value, key_name, ignore_field_not_found)) break;
|
||||||
}
|
}
|
||||||
// set the rest of the key/value pairs
|
// set the rest of the key/value pairs
|
||||||
it = input->makeIterator();
|
it = input->makeIterator();
|
||||||
while (ScriptValueP value = it->next(&key)) {
|
while (ScriptValueP value = it->next(&key)) {
|
||||||
@@ -98,7 +100,7 @@ SCRIPT_FUNCTION(new_card) {
|
|||||||
else {
|
else {
|
||||||
set_container(container, value, key_name);
|
set_container(container, value, key_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if the game has a construction script, set the card context variable to be this card, run script
|
// if the game has a construction script, set the card context variable to be this card, run script
|
||||||
if (game->import_script) {
|
if (game->import_script) {
|
||||||
ScriptValueP ctx_card = ctx.getVariableOpt(SCRIPT_VAR_card);
|
ScriptValueP ctx_card = ctx.getVariableOpt(SCRIPT_VAR_card);
|
||||||
@@ -134,7 +136,7 @@ SCRIPT_FUNCTION(new_card) {
|
|||||||
}
|
}
|
||||||
// restore old context card
|
// restore old context card
|
||||||
if (ctx_card) ctx.setVariable(SCRIPT_VAR_card, ctx_card);
|
if (ctx_card) ctx.setVariable(SCRIPT_VAR_card, ctx_card);
|
||||||
}
|
}
|
||||||
SCRIPT_RETURN(new_card);
|
SCRIPT_RETURN(new_card);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,10 @@ inline static bool set_stylesheet_container(const Game& game, CardP& card, Scrip
|
|||||||
if (key_name == _("style") || key_name == _("stylesheet") || key_name == _("template")) {
|
if (key_name == _("style") || key_name == _("stylesheet") || key_name == _("template")) {
|
||||||
if (!trim(value->toString()).empty()) {
|
if (!trim(value->toString()).empty()) {
|
||||||
card->stylesheet = StyleSheet::byGameAndName(game, value->toString());
|
card->stylesheet = StyleSheet::byGameAndName(game, value->toString());
|
||||||
if (card->stylesheet) card->styling_data.init(card->stylesheet->styling_fields);
|
if (card->stylesheet) {
|
||||||
|
card->styling_data.init(card->stylesheet->styling_fields);
|
||||||
|
card->extraDataFor(*card->stylesheet).init(card->stylesheet->extra_card_fields);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -104,7 +107,14 @@ inline static bool set_stylesheet_container(const Game& game, CardP& card, Scrip
|
|||||||
inline static bool set_builtin_container(const Game& game, CardP& card, ScriptValueP& value, String key_name, bool ignore_field_not_found) {
|
inline static bool set_builtin_container(const Game& game, CardP& card, ScriptValueP& value, String key_name, bool ignore_field_not_found) {
|
||||||
// check if the given value is for a built-in field, if found set it and return true
|
// check if the given value is for a built-in field, if found set it and return true
|
||||||
key_name = unified_form(key_name);
|
key_name = unified_form(key_name);
|
||||||
if (key_name == _("card_notes") || key_name == _("notes") || key_name == _("note")) {
|
if (key_name == _("style") || key_name == _("stylesheet") || key_name == _("template")) {
|
||||||
|
return true; // we already took care of this
|
||||||
|
}
|
||||||
|
else if (key_name == _("style_version") || key_name == _("stylesheet_version") || key_name == _("template_version")) {
|
||||||
|
card->stylesheet_version = Version::fromString(value->toString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (key_name == _("card_notes") || key_name == _("notes") || key_name == _("note")) {
|
||||||
card->notes = value->toString();
|
card->notes = value->toString();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -237,7 +247,7 @@ inline static bool cards_from_table(SetP& set, vector<String>& headers, std::vec
|
|||||||
// is this a new card?
|
// is this a new card?
|
||||||
if (contains(set->cards, card) || contains(cards_out, card)) {
|
if (contains(set->cards, card) || contains(cards_out, card)) {
|
||||||
// make copy
|
// make copy
|
||||||
card = make_intrusive<Card>(*card);
|
card = make_intrusive<Card>(set.get(), card);
|
||||||
}
|
}
|
||||||
cards_out.push_back(card);
|
cards_out.push_back(card);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,7 @@ CardP json_to_mse_card(boost::json::object& jv, Set* set) {
|
|||||||
StyleSheetP stylesheet = StyleSheet::byGameAndName(*set->game, String::FromUTF8(stylesheet_view.data(), stylesheet_view.size()));
|
StyleSheetP stylesheet = StyleSheet::byGameAndName(*set->game, String::FromUTF8(stylesheet_view.data(), stylesheet_view.size()));
|
||||||
if (!stylesheet) continue;
|
if (!stylesheet) continue;
|
||||||
IndexMap<FieldP, ValueP>& stylesheet_data = card->extraDataFor(*stylesheet);
|
IndexMap<FieldP, ValueP>& stylesheet_data = card->extraDataFor(*stylesheet);
|
||||||
|
stylesheet_data.init(stylesheet->extra_card_fields);
|
||||||
boost::json::object stylesheet_datav = it->value().as_object();
|
boost::json::object stylesheet_datav = it->value().as_object();
|
||||||
for (auto stylesheet_it = stylesheet_datav.begin(); stylesheet_it != stylesheet_datav.end(); ++stylesheet_it) {
|
for (auto stylesheet_it = stylesheet_datav.begin(); stylesheet_it != stylesheet_datav.end(); ++stylesheet_it) {
|
||||||
boost::json::string_view key_view = stylesheet_it->key();
|
boost::json::string_view key_view = stylesheet_it->key();
|
||||||
@@ -404,7 +405,7 @@ ScriptValueP json_to_mse(const String& string, Set* set) {
|
|||||||
options.allow_invalid_utf8 = true;
|
options.allow_invalid_utf8 = true;
|
||||||
wxScopedCharBuffer buffer = string.ToUTF8();
|
wxScopedCharBuffer buffer = string.ToUTF8();
|
||||||
boost::json::value jv = boost::json::parse(boost::json::string_view(buffer.data(), buffer.length()), ec, {}, options);
|
boost::json::value jv = boost::json::parse(boost::json::string_view(buffer.data(), buffer.length()), ec, {}, options);
|
||||||
if(ec && buffer.length() > 0) queue_message(MESSAGE_ERROR, _ERROR_("json cant parse") + _("\n\n") + ec.message());
|
//if(ec && buffer.length() > 0) queue_message(MESSAGE_ERROR, _ERROR_("json cant parse") + _("\n\n") + ec.message());
|
||||||
if(ec) return script_nil;
|
if(ec) return script_nil;
|
||||||
return json_to_mse(jv, set);
|
return json_to_mse(jv, set);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,21 @@ IndexMap<Key,Value>& DelayedIndexMaps<Key,Value>::get(const String& name, const
|
|||||||
return item->read_data;
|
return item->read_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initialize this map with cloned values from another map
|
||||||
|
template <typename Key, typename Value>
|
||||||
|
void DelayedIndexMaps<Key,Value>::cloneFrom(const DelayedIndexMaps<Key,Value>& values) {
|
||||||
|
clear();
|
||||||
|
for (const auto& [name, src_ptr] : values.data) {
|
||||||
|
if (!src_ptr) continue;
|
||||||
|
auto dst_ptr = make_intrusive<DelayedIndexMapsData<Key,Value>>();
|
||||||
|
dst_ptr->unread_data = src_ptr->unread_data;
|
||||||
|
if (src_ptr->unread_data.empty()) {
|
||||||
|
dst_ptr->read_data.cloneFrom(src_ptr->read_data);
|
||||||
|
}
|
||||||
|
data[name] = dst_ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Key, typename Value>
|
template <typename Key, typename Value>
|
||||||
void DelayedIndexMaps<Key,Value>::clear() {
|
void DelayedIndexMaps<Key,Value>::clear() {
|
||||||
data.clear();
|
data.clear();
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ public:
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/// Initialize this map with cloned values from another list
|
/// Initialize this map with cloned values from another map
|
||||||
void cloneFrom(const IndexMap<Key,Value>& values) {
|
void cloneFrom(const IndexMap<Key,Value>& values) {
|
||||||
if (this->size() == values.size()) return;
|
if (this->size() == values.size()) return;
|
||||||
this->reserve(values.size());
|
this->reserve(values.size());
|
||||||
for(size_t index = size() ; index < values.size() ; ++index) {
|
for(size_t index = size() ; index < values.size() ; ++index) {
|
||||||
@@ -147,6 +147,8 @@ class DelayedIndexMaps {
|
|||||||
public:
|
public:
|
||||||
/// Get the data for a specific name. Initialize the map with init_with (if it is not alread initialized)
|
/// Get the data for a specific name. Initialize the map with init_with (if it is not alread initialized)
|
||||||
IndexMap<Key,Value>& get(const String& name, const vector<Key>& init_with);
|
IndexMap<Key,Value>& get(const String& name, const vector<Key>& init_with);
|
||||||
|
/// Initialize this map with cloned values from another map
|
||||||
|
void cloneFrom(const DelayedIndexMaps<Key,Value>& values);
|
||||||
/// Clear the delayed index map
|
/// Clear the delayed index map
|
||||||
void clear();
|
void clear();
|
||||||
map<String, intrusive_ptr<DelayedIndexMapsData<Key,Value>>> data;
|
map<String, intrusive_ptr<DelayedIndexMapsData<Key,Value>>> data;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ Reader::Reader(wxInputStream& input, Packaged* package, const String& filename,
|
|||||||
handleAppVersion();
|
handleAppVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reader::handleIgnore(int end_version, const Char* a) {
|
void Reader::handleIgnore(Version end_version, const Char* a) {
|
||||||
if (file_app_version < end_version) {
|
if (file_app_version < end_version) {
|
||||||
if (enterBlock(a)) exitBlock();
|
if (enterBlock(a)) exitBlock();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public:
|
|||||||
/// Is the thing currently being read 'complex', i.e. does it have children
|
/// Is the thing currently being read 'complex', i.e. does it have children
|
||||||
inline bool isCompound() const { return indent != expected_indent - 1 || value.empty(); }
|
inline bool isCompound() const { return indent != expected_indent - 1 || value.empty(); }
|
||||||
/// Ignore old keys
|
/// Ignore old keys
|
||||||
void handleIgnore(int, const Char*);
|
void handleIgnore(Version, const Char*);
|
||||||
/// Get the version of the format we are reading
|
/// Get the version of the format we are reading
|
||||||
inline Version formatVersion() const { return file_app_version; }
|
inline Version formatVersion() const { return file_app_version; }
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@ private:
|
|||||||
value = key == _("include_localized_file") ? addLocale(value) : key == _("include_dark_file") ? addDark(value) : value;
|
value = key == _("include_localized_file") ? addLocale(value) : key == _("include_dark_file") ? addDark(value) : value;
|
||||||
auto [stream, include_package] = openFileFromPackage(package, value);
|
auto [stream, include_package] = openFileFromPackage(package, value);
|
||||||
Reader sub_reader(*stream, include_package, value, ignore_invalid);
|
Reader sub_reader(*stream, include_package, value, ignore_invalid);
|
||||||
if (sub_reader.file_app_version == 0) {
|
if (sub_reader.file_app_version.isZero()) {
|
||||||
// in an included file, use the app version of the parent if there is none
|
// in an included file, use the app version of the parent if there is none
|
||||||
sub_reader.file_app_version = file_app_version;
|
sub_reader.file_app_version = file_app_version;
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-24
@@ -13,30 +13,31 @@
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Version
|
// ----------------------------------------------------------------------------- : Version
|
||||||
|
|
||||||
UInt Version::toNumber() const { return version; }
|
UInt Version::toNumber() const { return major * 10000 + minor * 100 + revision; }
|
||||||
|
|
||||||
String Version::toString() const {
|
String Version::toString() const {
|
||||||
if (version > 20000000) {
|
if (major >= 2000) {
|
||||||
// major > 2000, the version is a date, use ISO notation
|
// the version is a date, use ISO notation
|
||||||
return String::Format(_("%04d-%02d-%02d"),
|
return String::Format(_("%04d-%02d-%02d"),
|
||||||
(version / 10000) ,
|
major,
|
||||||
(version / 100) % 100,
|
minor,
|
||||||
(version / 1) % 100);
|
revision);
|
||||||
} else {
|
} else {
|
||||||
return String::Format(_("%d.%d.%d"),
|
return String::Format(_("%d.%d.%d"),
|
||||||
(version / 10000) ,
|
major,
|
||||||
(version / 100) % 100,
|
minor,
|
||||||
(version / 1) % 100);
|
revision);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Version Version::fromString(const String& version) {
|
Version Version::fromString(const String& version) {
|
||||||
UInt major = 0, minor = 0, build = 0;
|
UInt major = 0, minor = 0, revision = 0;
|
||||||
if (wxSscanf(version, _("%u.%u.%u"), &major, &minor, &build)<=1) // a.b.c style
|
if (wxSscanf(version, _("%u.%u.%u"), &major, &minor, &revision)<=1) // a.b.c style
|
||||||
wxSscanf(version, _("%u-%u-%u"), &major, &minor, &build); // date style
|
wxSscanf(version, _("%u-%u-%u"), &major, &minor, &revision); // date style
|
||||||
return Version(major * 10000 + minor * 100 + build);
|
return Version(major, minor, revision);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Version::isZero() const { return revision == 0u && minor == 0u && major == 0u; }
|
||||||
|
|
||||||
template <> void Reader::handle(Version& v) {
|
template <> void Reader::handle(Version& v) {
|
||||||
v = Version::fromString(getValue());
|
v = Version::fromString(getValue());
|
||||||
@@ -51,7 +52,7 @@ template <> void GetDefaultMember::handle(const Version& v) {
|
|||||||
// ----------------------------------------------------------------------------- : Versions
|
// ----------------------------------------------------------------------------- : Versions
|
||||||
|
|
||||||
// NOTE: Don't use leading zeroes, they mean octal
|
// NOTE: Don't use leading zeroes, they mean octal
|
||||||
const Version app_version = 10000 * MSE_VERSION_MAJOR + 100 * MSE_VERSION_MINOR + MSE_VERSION_PATCH;
|
const Version app_version = Version(MSE_VERSION_MAJOR, MSE_VERSION_MINOR, MSE_VERSION_PATCH);
|
||||||
|
|
||||||
#if defined UNOFFICIAL_BUILD
|
#if defined UNOFFICIAL_BUILD
|
||||||
const Char* version_suffix = _(" (Unofficial)");
|
const Char* version_suffix = _(" (Unofficial)");
|
||||||
@@ -88,13 +89,13 @@ const Char* version_suffix = _(" (ascii build)");
|
|||||||
* 2.0.0 : bugfix release mostly, added error console
|
* 2.0.0 : bugfix release mostly, added error console
|
||||||
* 2.0.2 : store game and stylesheet version numbers
|
* 2.0.2 : store game and stylesheet version numbers
|
||||||
*/
|
*/
|
||||||
const Version file_version_locale = 20002; // 2.0.2
|
const Version file_version_locale = Version(2u, 0u, 2u);
|
||||||
const Version file_version_set = 20002; // 2.0.2
|
const Version file_version_set = Version(2u, 0u, 2u);
|
||||||
const Version file_version_game = 308; // 0.3.8
|
const Version file_version_game = Version(0u, 3u, 8u);
|
||||||
const Version file_version_stylesheet = 308; // 0.3.8
|
const Version file_version_stylesheet = Version(0u, 3u, 8u);
|
||||||
const Version file_version_symbol_font = 306; // 0.3.6
|
const Version file_version_symbol_font = Version(0u, 3u, 6u);
|
||||||
const Version file_version_export_template = 307; // 0.3.7
|
const Version file_version_export_template = Version(0u, 3u, 7u);
|
||||||
const Version file_version_installer = 307; // 0.3.7
|
const Version file_version_installer = Version(0u, 3u, 7u);
|
||||||
const Version file_version_symbol = 305; // 0.3.5
|
const Version file_version_symbol = Version(0u, 3u, 5u);
|
||||||
const Version file_version_clipboard = 20002; // 2.0.2
|
const Version file_version_clipboard = Version(2u, 6u, 0u);
|
||||||
const Version file_version_script = 307; // 0.3.7
|
const Version file_version_script = Version(0u, 3u, 7u);
|
||||||
|
|||||||
+36
-13
@@ -21,16 +21,34 @@
|
|||||||
/// A version number
|
/// A version number
|
||||||
struct Version {
|
struct Version {
|
||||||
public:
|
public:
|
||||||
Version() : version(0) {}
|
Version() : major(0u), minor(0u), revision(0u) {}
|
||||||
Version(UInt version) : version(version) {}
|
Version(UInt major, UInt minor, UInt revision) : major(major), minor(minor), revision(revision) {}
|
||||||
|
|
||||||
inline bool operator == (Version v) const { return version == v.version; }
|
bool operator==(const Version& v) const {
|
||||||
inline bool operator != (Version v) const { return version != v.version; }
|
return std::tie(major, minor, revision)
|
||||||
inline bool operator < (Version v) const { return version < v.version; }
|
== std::tie(v.major, v.minor, v.revision);
|
||||||
inline bool operator <= (Version v) const { return version <= v.version; }
|
}
|
||||||
inline bool operator > (Version v) const { return version > v.version; }
|
bool operator!=(const Version& v) const {
|
||||||
inline bool operator >= (Version v) const { return version >= v.version; }
|
return std::tie(major, minor, revision)
|
||||||
|
!= std::tie(v.major, v.minor, v.revision);
|
||||||
|
}
|
||||||
|
bool operator<(const Version& v) const {
|
||||||
|
return std::tie(major, minor, revision)
|
||||||
|
< std::tie(v.major, v.minor, v.revision);
|
||||||
|
}
|
||||||
|
bool operator>(const Version& v) const {
|
||||||
|
return std::tie(major, minor, revision)
|
||||||
|
> std::tie(v.major, v.minor, v.revision);
|
||||||
|
}
|
||||||
|
bool operator<=(const Version& v) const {
|
||||||
|
return std::tie(major, minor, revision)
|
||||||
|
<= std::tie(v.major, v.minor, v.revision);
|
||||||
|
}
|
||||||
|
bool operator>=(const Version& v) const {
|
||||||
|
return std::tie(major, minor, revision)
|
||||||
|
>= std::tie(v.major, v.minor, v.revision);
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert a version number to a string
|
/// Convert a version number to a string
|
||||||
String toString() const;
|
String toString() const;
|
||||||
/// Get the version number as an integer number
|
/// Get the version number as an integer number
|
||||||
@@ -38,9 +56,14 @@ public:
|
|||||||
|
|
||||||
/// Convert a string to a version number
|
/// Convert a string to a version number
|
||||||
static Version fromString(const String& version);
|
static Version fromString(const String& version);
|
||||||
|
|
||||||
private:
|
/// Did this version get properly initialized?
|
||||||
UInt version; ///< Version number encoded as aabbcc, where a=major, b=minor, c=revision
|
bool isZero() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
UInt major = 0;
|
||||||
|
UInt minor = 0;
|
||||||
|
UInt revision = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Versions
|
// ----------------------------------------------------------------------------- : Versions
|
||||||
|
|||||||
Reference in New Issue
Block a user