It is currently 13 Sep 2025, 20:37
   
Text Size

Issue 157: which classes do we need?

Post MTG Forge Related Programming Questions Here

Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins

Issue 157: which classes do we need?

Postby Max mtg » 22 Aug 2011, 23:58

http://cardforge.org/bugz/view.php?id=157

I completely agree that using a single class for every possible card representation is a Door To Nothingness. So, let's figure out, which classes are needed for each purpose. At the moment, we have two methods of representing a card: an instance of Card and a String with name. The latter being used for deck and card pool management and the former for everyting else.

To my opinion three "levels of detail" for Card class are needed:
1. CardReference - contains only name, edition, picture number and foiled flag. This is useful to store cards owned by player, be it questmode cardpool or a deck. Picture number is good for distinguishing different copies of lands and promos from ordinary cards.
2. CardOutOfGame (or simply Card) - contains all the rules and abilities, but has no temporary effects on it. This class is useful for displaying cards as quest rewards or in deckbuilder GUI. Such cards instances do have enough properties to filter them by having some ability (infect for instance) or sort by cmc. Their PT and other properties are always nominal and no game-related effects may be placed on these cards. One instance of each card of this type per application is enough. [These cards may persist for the whole app runtime]
3. CardInGame - has a reference to CardOutOfGame (it's prototype), but this card can be placed to any zone in game, can have counters placed over it as well as other effects, can have changed P/T, color, types and so on. [These objects are disposed as soon as game ends]
Single class for single responsibility.
Max mtg
Programmer
 
Posts: 1997
Joined: 02 Jul 2011, 14:26
Has thanked: 173 times
Been thanked: 334 times

Re: Issue 157: which classes do we need?

Postby friarsol » 23 Aug 2011, 01:32

I'd prefer that 2 have just Oracle text not actual parsed Abilities. This would include Power, Toughness, Loyalty, CC, Card Types and any Card Text. I do have a script that would add the Card Text data for us (and without much extra work can handle some of the other stuff as well), but there has been some conversation regarding it back and forth so I haven't run it yet. This is important to speed up the Deck Editor load times, so the full Card Game Objects won't be generated.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Issue 157: which classes do we need?

Postby Braids » 23 Aug 2011, 02:27

Max mtg has a thinking cap on!

1. sounds great, but the name is too generic. this sounds more like an inventory item. InventoryCard? BasicCard? DeckListItem? CardNameAndPicture? we might want to represent some tokens this way as well. my tokens don't have art. {maybe i haven't configured my game correctly?} also, we need a way to get one of these and have it choose a random picture. i have visions of importing decklists, and not all formats identify the picture {or set}.
2. i agree with the good friar. this should have text attributes only. it might not even be a Java class -- it sounds more like database material {relational or otherwise}. or maybe an object-relational map. use Hibernate?
3. CardInGame has a great name, and the relationship to #2 makes sense. because we need text for the card panel in the upper right of the battlefield window. but we also need a relationship to #1 for the picture.
4. so we also need a disk based one to many relationship from canonical ASCII card name to picture identifiers {like a set+picture number}. this specifies which card names can have which pictures, so we can pick random pictures for #1 and perhaps verify the pictures for #2 and/or #3.
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. ;)
User avatar
Braids
Programmer
 
Posts: 556
Joined: 22 Jun 2011, 00:39
Location: Unknown. Hobby: Driving myself and others to constructive madness.
Has thanked: 1 time
Been thanked: 1 time

Re: Issue 157: which classes do we need?

Postby Max mtg » 23 Aug 2011, 04:01

Braids wrote:Max mtg has a thinking cap on!
What does this mean? English is not my native language - so the phrase above sounds unclear to me.

Braids wrote:1. sounds great, but the name is too generic. this sounds more like an inventory item. InventoryCard? BasicCard? DeckListItem? CardNameAndPicture? we might want to represent some tokens this way as well. my tokens don't have art. {maybe i haven't configured my game correctly?} also, we need a way to get one of these and have it choose a random picture. i have visions of importing decklists, and not all formats identify the picture {or set}.
That is an inventory item. The reason I called it reference is because before that we had only cardnames as inventory storage unit, those were just strings. They only referred to a card, any card meeting the name criteria. Now it's time to eliminate randomness - I want such a record refer to one and only card, that is why extra fields were needed.

InventoryCard is a good idea. Others are not: BasicCard (class is not supposed to be an inheritance base and there won't be an AdvancedCard), DeckListItem (it would sound strange to give quest rewards with those or store them in cardpool), CardNameAndPicture (in fact they are, but there should be a name)
So, CardReference or CardInventory sound fine to me.

Tokens are never kept in inventory or deck, so we do not needed to support them at this level of abstraction... Do tokens belong to a set?

No random pictures! set+pictureIndex strictly define the appearance of any card, together with its name.
As for importing decklists - it's ok to have forge choose random picture for lands. Promo versions of cards should never get autoimported. In case edition is to be determined automatically, assume the latest one, when card was printed.

Braids wrote:2. i agree with the good friar. this should have text attributes only. it might not even be a Java class -- it sounds more like database material {relational or otherwise}. or maybe an object-relational map. use Hibernate?
Despite of the method for storing that data, we'll anyway end up with a java class representing a storage unit. So, there's no escape from a class. If you want to have an OracleCard here, it's fine, but you'll still need a prototype with all abilities parsed for the next level of detalization - the one which is supposed to be read from %cardname%.txt

Braids wrote:3. CardInGame has a great name, and the relationship to #2 makes sense. because we need text for the card panel in the upper right of the battlefield window. but we also need a relationship to #1 for the picture.
Yes, both references are necesary. Though you can always derive a reference to #2 (rules) from #1 (appearance).

Braids wrote:4. so we also need a disk based one to many relationship from canonical ASCII card name to picture identifiers {like a set+picture number}. this specifies which card names can have which pictures, so we can pick random pictures for #1 and perhaps verify the pictures for #2 and/or #3.
I expect picture management to be achieved quite simply:
1. Have card images organized in a tree (root)\(set)\(cardname).jpg
2. In card description files (the %cardname%.txt ones) for each edition there should be a number indicating amount of copies diven edition has, alongside with urls to donwload these pictures from (gatherer/magiccards).

Once a card is queried by its name+set+index, there exists one or no requested picture. To avoid misses index should no more than amount_of_copies_of_given_card_in_set.
Once a card is queried by its name+set (index missing) - choose index 0 for everything except basic lands. Follow instructions in previous line.
If a card is queried by name only, set = card.mostRecentSet(), move on to previous line.

Why do you need disk based relations (cardname) => (set,picture)?
Single class for single responsibility.
Max mtg
Programmer
 
Posts: 1997
Joined: 02 Jul 2011, 14:26
Has thanked: 173 times
Been thanked: 334 times

Re: Issue 157: which classes do we need?

Postby friarsol » 23 Aug 2011, 04:19

Max mtg wrote:
Braids wrote:2. i agree with the good friar. this should have text attributes only. it might not even be a Java class -- it sounds more like database material {relational or otherwise}. or maybe an object-relational map. use Hibernate?
Despite of the method for storing that data, we'll anyway end up with a java class representing a storage unit. So, there's no escape from a class. If you want to have an OracleCard here, it's fine, but you'll still need a prototype with all abilities parsed for the next level of detalization - the one which is supposed to be read from %cardname%.txt
I think the key point here is the Deck Editor doesn't need the Fleshed out abilities, only the text of the Abilities (for filtering/searching etc) so Oracle Text should be in this step and Fleshed Abilities should be in the one after this.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Issue 157: which classes do we need?

Postby Max mtg » 23 Aug 2011, 04:37

friarsol wrote:I think the key point here is the Deck Editor doesn't need the Fleshed out abilities, only the text of the Abilities (for filtering/searching etc) so Oracle Text should be in this step and Fleshed Abilities should be in the one after this.
I agree, the current deck editor is not versatile enough to deal with parsed abilities. And if parsing takes that much time, let's skip it.
Last edited by Max mtg on 23 Aug 2011, 10:04, edited 1 time in total.
Single class for single responsibility.
Max mtg
Programmer
 
Posts: 1997
Joined: 02 Jul 2011, 14:26
Has thanked: 173 times
Been thanked: 334 times

Re: Issue 157: which classes do we need?

Postby silly freak » 23 Aug 2011, 07:36

Parsing could be done lazily, but I think the oracle card is the better place, simply because it saves the game from parsing the ability for every card instance in every new game.

Although I'm not active on it right now, I have a similar structure in my game, with two levels. Actually, I do ability parsing at build time and store the parsed cards with functional ability objects in serialized form to improve startup time.
___

where's the "trust me, that will work!" switch for the compiler?
Laterna Magica - blog, forum, project, 2010/09/06 release!
silly freak
DEVELOPER
 
Posts: 598
Joined: 26 Mar 2009, 07:18
Location: Vienna, Austria
Has thanked: 93 times
Been thanked: 25 times

Re: Issue 157: which classes do we need?

Postby Max mtg » 23 Aug 2011, 12:53

silly freak wrote:Parsing could be done lazily, but I think the oracle card is the better place, simply because it saves the game from parsing the ability for every card instance in every new game.

Although I'm not active on it right now, I have a similar structure in my game, with two levels. Actually, I do ability parsing at build time and store the parsed cards with functional ability objects in serialized form to improve startup time.
If I got your idea right, at first we process simple text-only oracle records for all cards (that should be fast as it does not include any parsing), and as soon as a battle begins that heavy entites of Card are being created by LazyCardFactory.
So how this collection of oracle card data should be stored?
Single class for single responsibility.
Max mtg
Programmer
 
Posts: 1997
Joined: 02 Jul 2011, 14:26
Has thanked: 173 times
Been thanked: 334 times

Re: Issue 157: which classes do we need?

Postby silly freak » 23 Aug 2011, 13:41

I'm not up to date with forge's ability code, but what I'm saying is basically this:

Laterna Magica does it like this
-cards are stored as separate files
-before building a release, the card parser creates the OracleCards from these files and uses Java serialization to store them. (I use a zip archive with individual zip entries for every card)
-at runtime, cards are lazily loaded: everytime a card is needed that was not yet loaded, it is read from the archive. no text analysis is needed for loading a card, and cards are loaded individually.

what I suggested for forge
I think there is no need to load all cards at once, as every card is independent. It might take some/much refactoring, but CardFactory would need to be able to load single cards.

-every time an oracle card is needed, read it from the file. the OracleCard then contains the static info, including both oracle card text and card script text.
-when the abilities of a card are first needed (i.e. in a game), the abilities of these cards are parsed from the already read ability text in OracleCard and stored.
-when an InGameCard is created, it copies all abilities from the oracle card, as abilities may be added/removed subsequently

this would mean that for the first game, only up to 120 card's abilities need to be parsed, not all, and starting the constructed deck editor needs the time to read all card files, but not to parse all abilities. still, every ability on every card is only parsed once.

EDIT: I hope I don't sound like a smart ass, as i haven't worked on forge or even my own program for a long time. I just see how forge's architecture grows into something I consider structured and extensible, and when I see an opportunity to help going into that direction, even if only by suggestions, I try to do so ;)
___

where's the "trust me, that will work!" switch for the compiler?
Laterna Magica - blog, forum, project, 2010/09/06 release!
silly freak
DEVELOPER
 
Posts: 598
Joined: 26 Mar 2009, 07:18
Location: Vienna, Austria
Has thanked: 93 times
Been thanked: 25 times

Re: Issue 157: which classes do we need?

Postby friarsol » 23 Aug 2011, 14:15

silly freak wrote:this would mean that for the first game, only up to 120 card's abilities need to be parsed, not all, and starting the constructed deck editor needs the time to read all card files, but not to parse all abilities. still, every ability on every card is only parsed once.

EDIT: I hope I don't sound like a smart ass, as i haven't worked on forge or even my own program for a long time. I just see how forge's architecture grows into something I consider structured and extensible, and when I see an opportunity to help going into that direction, even if only by suggestions, I try to do so ;)
Not at all. This is exactly how I was picturing it occurring as well. I believe I stated as much the last time we had this conversation, but noone was actively working to make the improvements quite yet.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Issue 157: which classes do we need?

Postby Rob Cashwalker » 23 Aug 2011, 15:26

There should only need to be two classes of Card, one pure text, aka "printed" stats and one class which is created on the fly for each instance of the printed card needed.

The PrintedCard class just maintains the cardname.txt data, along with the Oracle text. One global, immutable List of these objects. No fancy data structures. Efficient searching and sorting would be nice, runtime DB or just faking it by wrapping a few TreeMaps built using different keys (name, color, type, keywords, etc..). Heap usage for those sorts of maps should be significantly less than the original map which included the entire Card object with code baggage.

The ActiveCard class is created by a Factory, on-demand based on parsing the PrintedCard object. This object has uniqueness and begins life only when the in-game library is being assembled. During assembly, SetInfo is assigned, along with picture selection, if multiples are available in the SetInfo. While in-game this object may move from zone-to-zone, can be cloned, can be blinked, etc, without affecting any other ActiveCards that just happen to share a name with each other.

One tricky part is Parsing a card object which isn't scripted... ahh, but here's a trick. Let's give all the hardcoded cards a special AbilityScript word that relates to their specific code, but takes it out of hard-coded CardFactories, in favor of an AbilityFactory_HardCode... or something.
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Re: Issue 157: which classes do we need?

Postby silly freak » 24 Aug 2011, 07:09

Rob Cashwalker wrote:One tricky part is Parsing a card object which isn't scripted... ahh, but here's a trick. Let's give all the hardcoded cards a special AbilityScript word that relates to their specific code, but takes it out of hard-coded CardFactories, in favor of an AbilityFactory_HardCode... or something.
hmm... this sounds familiar^^
My Blog wrote:If the line is "text {T}: Add {G} to your mana pool.", the "text" handler tries to find an ability parser that can parse the line. Even if I can't represent an ability, I can make a class specifically for that ability and add a line handler that applies an arbitrary class to the card, like "apply laterna.magica.cards.DestroyAllCreatures".
___

where's the "trust me, that will work!" switch for the compiler?
Laterna Magica - blog, forum, project, 2010/09/06 release!
silly freak
DEVELOPER
 
Posts: 598
Joined: 26 Mar 2009, 07:18
Location: Vienna, Austria
Has thanked: 93 times
Been thanked: 25 times

Re: Issue 157: which classes do we need?

Postby Braids » 25 Aug 2011, 03:46

Max mtg wrote:
Braids wrote:Max mtg has a thinking cap on!
What does this mean? English is not my native language - so the phrase above sounds unclear to me.
oh, it's an idiomatic phrase. it means you have been thinking seriously about something and usually critically analyzing it.

Max mtg wrote:
Braids wrote:1. sounds great, but the name is too generic. this sounds more like an inventory item. InventoryCard? BasicCard? DeckListItem? CardNameAndPicture? we might want to represent some tokens this way as well. my tokens don't have art. {maybe i haven't configured my game correctly?} also, we need a way to get one of these and have it choose a random picture. i have visions of importing decklists, and not all formats identify the picture {or set}.
That is an inventory item. The reason I called it reference is because before that we had only cardnames as inventory storage unit, those were just strings. They only referred to a card, any card meeting the name criteria. Now it's time to eliminate randomness - I want such a record refer to one and only card, that is why extra fields were needed.

InventoryCard is a good idea. Others are not: BasicCard (class is not supposed to be an inheritance base and there won't be an AdvancedCard), DeckListItem (it would sound strange to give quest rewards with those or store them in cardpool), CardNameAndPicture (in fact they are, but there should be a name)
So, CardReference or CardInventory sound fine to me.
CardReference sounds too much like a pointer or "passed by reference", which is a specific term in computer science. InventoryCard, then? not CardInventory, that denotes an entire inventory, instead of one card.

Max mtg wrote:Tokens are never kept in inventory or deck, so we do not needed to support them at this level of abstraction... Do tokens belong to a set?
oh, you're right. yes, they can belong to a set, but it's much more important that the token's name, color(s), abilities, power, and toughness are correct. some tokens with the same name vary in these attributes. :(

Max mtg wrote:No random pictures! set+pictureIndex strictly define the appearance of any card, together with its name.
your vote is duly noted, but there is no need to be so vehement.

Max mtg wrote:As for importing decklists - it's ok to have forge choose random picture for lands. Promo versions of cards should never get autoimported. In case edition is to be determined automatically, assume the latest one, when card was printed.
i can live with that. when you say, "promo versions of cards", are you referring to {Magic Rewards'} textless spells?

Max mtg wrote:
Braids wrote:2. i agree with the good friar. this should have text attributes only. it might not even be a Java class -- it sounds more like database material {relational or otherwise}. or maybe an object-relational map. use Hibernate?
Despite of the method for storing that data, we'll anyway end up with a java class representing a storage unit. So, there's no escape from a class. If you want to have an OracleCard here, it's fine, but you'll still need a prototype with all abilities parsed for the next level of detalization - the one which is supposed to be read from %cardname%.txt
yes, i suppose it has to be some Java class at some point, unless i want to use a raw HashMap to represent card text and attributes. :)

Max mtg wrote:Why do you need disk based relations (cardname) => (set,picture)?
to validate possibly incorrectly imported deck lists, i think. but like you said, the relationship can be deduced from #3 to #1.
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. ;)
User avatar
Braids
Programmer
 
Posts: 556
Joined: 22 Jun 2011, 00:39
Location: Unknown. Hobby: Driving myself and others to constructive madness.
Has thanked: 1 time
Been thanked: 1 time

Re: Issue 157: which classes do we need?

Postby Braids » 25 Aug 2011, 03:50

silly freak wrote:Parsing could be done lazily, but I think the oracle card is the better place, simply because it saves the game from parsing the ability for every card instance in every new game.
we presently have a LazyCardFactory, but it has only proven itself in unit testing. it will not yet work with the main Forge app, because it doesn't support iterating over every card.

silly freak wrote:Although I'm not active on it right now, I have a similar structure in my game, with two levels. Actually, I do ability parsing at build time and store the parsed cards with functional ability objects in serialized form to improve startup time.
very nice. :D
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. ;)
User avatar
Braids
Programmer
 
Posts: 556
Joined: 22 Jun 2011, 00:39
Location: Unknown. Hobby: Driving myself and others to constructive madness.
Has thanked: 1 time
Been thanked: 1 time

Re: Issue 157: which classes do we need?

Postby Braids » 25 Aug 2011, 03:57

Rob Cashwalker wrote:. . . The PrintedCard class just maintains the cardname.txt data, along with the Oracle text.
so you like #2. i think we would want Forge specific metadata in there, too, like AI compatibility. the deck generators should be able to work with this information without creating CardInGame (#3) instances.

Rob Cashwalker wrote:The ActiveCard class is created by a Factory, on-demand based on parsing the PrintedCard object. This object has uniqueness and begins life only when the in-game library is being assembled. During assembly, SetInfo is assigned, along with picture selection, if multiples are available in the SetInfo. While in-game this object may move from zone-to-zone, can be cloned, can be blinked, etc, without affecting any other ActiveCards that just happen to share a name with each other.
what about a card inside a decklist, quest collection, shop inventory or sideboard? that's what #1 is about. i don't think we want to store all of #2 for each card in a deck.
"That is the dumbest thing I've ever seen." --Rob Cashwalker, regarding Innistrad double-sided cards. One of the first times he and I have ever agreed on something. ;)
User avatar
Braids
Programmer
 
Posts: 556
Joined: 22 Jun 2011, 00:39
Location: Unknown. Hobby: Driving myself and others to constructive madness.
Has thanked: 1 time
Been thanked: 1 time

Next

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 37 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 37 users online :: 0 registered, 0 hidden and 37 guests (based on users active over the past 10 minutes)
Most users ever online was 7967 on 09 Sep 2025, 23:08

Users browsing this forum: No registered users and 37 guests

Login Form