Files
AppleHillsProduction/docs/cards_wip/card_migration_strategy.md

464 lines
14 KiB
Markdown
Raw Normal View History

2025-11-11 21:03:05 +01:00
# Old Card Scripts - Migration Strategy
## TL;DR: What Happens to Old Scripts?
**Answer:** They are **REPLACED** by the new state machine system, but **CardDisplay stays**.
### Keep (Don't Touch) ✅
- **`CardDisplay.cs`** - Core visual renderer, used by both old and new systems
### Replace (Eventually Deprecate) 🔄
- **`FlippableCard.cs`** → Replaced by `Card.cs` with state machine
- **`AlbumCard.cs`** → Replaced by `CardPlacedInSlotState.cs` + `CardAlbumEnlargedState.cs`
- **`AlbumCardPlacementDraggable.cs`** → Replaced by `Card.cs` with `CardDraggingState.cs`
---
## Current Usage Analysis
### Where FlippableCard is Used:
1. **BoosterOpeningPage.cs** (8 references)
- Line 592: Instantiate FlippableCard for booster reveal
- Line 601, 643, 660, 752, 770: GetComponent calls
- **Impact:** High - main booster opening flow
2. **AlbumCardPlacementDraggable.cs** (1 reference)
- Line 45: GetComponent reference
- **Impact:** Medium - album placement flow
3. **AlbumCard.cs** (1 reference)
- Line 94: GetComponentInParent during click forwarding
- **Impact:** Low - will be removed when AlbumCard is replaced
### Where AlbumCard is Used:
1. **AlbumCardSlot.cs** (2 references)
- Line 186-187: Instantiate and GetComponent for pre-placed cards
- **Impact:** High - album slot system
2. **AlbumViewPage.cs** (2 references)
- Line 346: GetComponent when handling enlarge
- Line 457-458: Instantiate AlbumCardPlacementDraggable
- **Impact:** High - album view interactions
3. **CardDisplay.cs** (1 reference)
- Line 316: GetComponentInParent for preview mode
- **Impact:** Low - preview feature
4. **FlippableCard.cs** (1 reference)
- Line 73: GetComponentInChildren reference
- **Impact:** Will be removed when FlippableCard is replaced
---
## Migration Phases
### Phase 1: Parallel Development (Current) ✅
**Status:** Both systems coexist, no breaking changes
```
Old System (Active) New System (Being Built)
├─ FlippableCard.cs ├─ Card.cs
├─ AlbumCard.cs ├─ CardContext.cs
├─ AlbumCardPlacement... ├─ CardAnimator.cs
└─ CardDisplay.cs ←──────────┼─→ CardDisplay.cs (shared!)
└─ State scripts...
```
**Action:** Build new Card prefab, test in isolation
**Timeline:** Current (you're here!)
---
### Phase 2: Partial Replacement - Booster Opening (Recommended Start)
**Status:** Replace booster cards only, album cards still use old system
#### Changes Required:
**File: `BoosterOpeningPage.cs`**
**Old code:**
```csharp
[SerializeField] private GameObject flippableCardPrefab;
// In SpawnCards()
GameObject cardObj = Instantiate(flippableCardPrefab, cardDisplayContainer);
FlippableCard flippableCard = cardObj.GetComponent<FlippableCard>();
flippableCard.SetupCard(cardData);
flippableCard.OnCardRevealed += HandleCardRevealed;
flippableCard.OnCardTappedAfterReveal += HandleCardTapped;
```
**New code:**
```csharp
[SerializeField] private GameObject cardPrefab; // New Card prefab
// In SpawnCards()
GameObject cardObj = Instantiate(cardPrefab, cardDisplayContainer);
StateMachine.Card card = cardObj.GetComponent<StateMachine.Card>();
card.SetupForBoosterReveal(cardData, isNew: true);
// Subscribe to state events (if needed)
var flippingState = card.GetStateComponent<StateMachine.States.CardFlippingState>("FlippingState");
// Add custom events if needed, or just let state machine handle it
```
**Benefits:**
- Test new system in one isolated flow
- Booster opening is cleanest use case (no complex album interactions)
- Easy to rollback if issues arise
**Timeline:** 2-4 hours
---
### Phase 3: Full Replacement - Album System
**Status:** Replace album cards, old system fully deprecated
#### Changes Required:
**File: `AlbumCardSlot.cs`**
**Old code:**
```csharp
[SerializeField] private GameObject albumCardPrefab;
// In SpawnPreviewCard()
GameObject cardObj = Instantiate(albumCardPrefab, transform);
AlbumCard albumCard = cardObj.GetComponent<AlbumCard>();
albumCard.SetupCard(cardData);
albumCard.SetParentSlot(this);
albumCard.OnEnlargeRequested += HandleEnlarge;
albumCard.OnShrinkRequested += HandleShrink;
```
**New code:**
```csharp
[SerializeField] private GameObject cardPrefab; // Same Card prefab as booster
// In SpawnPreviewCard()
GameObject cardObj = Instantiate(cardPrefab, transform);
StateMachine.Card card = cardObj.GetComponent<StateMachine.Card>();
card.SetupForAlbumSlot(cardData, this);
// Subscribe to enlarge events (if needed)
var albumEnlargedState = card.GetStateComponent<StateMachine.States.CardAlbumEnlargedState>("AlbumEnlargedState");
albumEnlargedState.OnEnlargeRequested += HandleEnlarge;
albumEnlargedState.OnShrinkRequested += HandleShrink;
```
**File: `AlbumViewPage.cs`**
Similar changes for handling enlarged cards and backdrop.
**Timeline:** 4-6 hours
---
### Phase 4: Cleanup - Remove Old Scripts
**Status:** Old scripts deleted, prefabs archived
#### Files to Remove:
-`FlippableCard.cs`
-`AlbumCard.cs`
-`AlbumCardPlacementDraggable.cs` (if drag system is integrated)
#### Files to Keep:
-`CardDisplay.cs` - Still used by new system!
-`AlbumCardSlot.cs` - Updated to use new Card prefab
-`BoosterOpeningPage.cs` - Updated to use new Card prefab
-`AlbumViewPage.cs` - Updated to use new Card prefab
**Timeline:** 1 hour (after Phases 2-3 are stable)
---
## Coexistence Strategy (During Migration)
### Option A: Gradual Scene-by-Scene (Recommended)
Replace one scene at a time:
```
Week 1: Booster Opening Scene
└─ Uses new Card.prefab
Week 2: Album View Scene
└─ Uses new Card.prefab
Week 3: Any other card scenes
└─ Uses new Card.prefab
Week 4: Remove old scripts
```
**Pros:**
- Low risk, easy rollback
- Test thoroughly at each step
- Team can adapt gradually
**Cons:**
- Longer timeline
- Maintain both systems temporarily
---
### Option B: Big Bang Replacement
Replace all at once in one PR/branch:
```
Day 1-2: Update BoosterOpeningPage
Day 3-4: Update AlbumViewPage + AlbumCardSlot
Day 5: Test everything
Day 6: Delete old scripts
```
**Pros:**
- Faster completion
- No long-term coexistence
**Cons:**
- Higher risk
- More testing needed
- Harder to rollback
---
## Feature Mapping: Old → New
### FlippableCard → Card with States
| Old Feature | Old Implementation | New Implementation |
|-------------|-------------------|-------------------|
| Idle hover | FlippableCard._idleHoverTween | CardIdleState.OnEnterState() |
| Click to flip | FlippableCard.OnPointerClick() | CardIdleState.OnPointerClick() |
| Flip animation | FlippableCard.FlipToReveal() | CardFlippingState.OnEnterState() |
| New card badge | FlippableCard.ShowAsNew() | CardEnlargedNewState (owns badge) |
| Repeat progress | FlippableCard.ShowAsRepeat() | CardEnlargedRepeatState (owns bar) |
| Tap to dismiss | FlippableCard.OnPointerClick() when waiting | CardEnlargedNewState.OnPointerClick() |
### AlbumCard → CardPlacedInSlotState + CardAlbumEnlargedState
| Old Feature | Old Implementation | New Implementation |
|-------------|-------------------|-------------------|
| Store parent slot | AlbumCard._parentSlot | CardPlacedInSlotState.SetParentSlot() |
| Click to enlarge | AlbumCard.OnPointerClick() | CardPlacedInSlotState.OnPointerClick() |
| Enlarge animation | AlbumCard.EnlargeCard() | CardAlbumEnlargedState.OnEnterState() |
| Shrink animation | AlbumCard.ShrinkCard() | CardAlbumEnlargedState.OnPointerClick() |
| Transform tracking | AlbumCard._originalParent, etc. | CardAlbumEnlargedState (same fields) |
### AlbumCardPlacementDraggable → Card with CardDraggingState
| Old Feature | Old Implementation | New Implementation |
|-------------|-------------------|-------------------|
| Drag feedback | AlbumCardPlacement... | CardDraggingState |
| Snap to slot | SnapToAlbumSlot() | CardDraggingState.OnDroppedInSlot() |
| Flip on drag | Nested FlippableCard | Just use Card with state machine |
---
## Events Migration
### Old Events (FlippableCard)
```csharp
flippableCard.OnCardRevealed += (card, data) => { };
flippableCard.OnCardTappedAfterReveal += (card) => { };
flippableCard.OnFlipStarted += (card) => { };
flippableCard.OnClickedWhileInactive += (card) => { };
```
### New Events (State-based)
```csharp
// Option 1: Listen to state machine transitions
var flippingState = card.GetStateComponent<CardFlippingState>("FlippingState");
// Then add custom events to states if needed
// Option 2: Poll current state
if (card.GetCurrentStateName() == "RevealedState")
{
// Card was revealed
}
// Option 3: Add custom events to Card.cs that relay from states
card.OnCardRevealed += (data) => { };
```
**Note:** Some events may not be needed anymore because state machine handles transitions internally.
---
## Testing Strategy
### Phase 2 Testing (Booster Only)
- [ ] Open booster pack
- [ ] Cards spawn in IdleState
- [ ] Click card triggers flip
- [ ] Flip animation plays correctly
- [ ] New cards show "NEW CARD" badge
- [ ] Repeat cards show progress bar
- [ ] Tap dismisses enlarged view
- [ ] Multiple cards work simultaneously
- [ ] No console errors
### Phase 3 Testing (Album Added)
- [ ] Cards appear in album slots
- [ ] Click card in album enlarges it
- [ ] Tap enlarged card shrinks it
- [ ] Backdrop shows/hides correctly
- [ ] Reparenting works (card moves to top layer)
- [ ] Card returns to correct slot
- [ ] Page flipping doesn't break card state
- [ ] No console errors
### Regression Testing (Both Phases)
- [ ] CardDisplay still renders correctly
- [ ] Card data persists across states
- [ ] Animations are smooth (60fps)
- [ ] Click detection works
- [ ] No memory leaks (profile with 20+ cards)
---
## Rollback Plan
If new system has issues:
### During Phase 2 (Booster Only)
1. Revert `BoosterOpeningPage.cs` changes
2. Re-assign old `flippableCardPrefab` in inspector
3. Old system still intact for album
### During Phase 3 (Album Added)
1. Revert `AlbumCardSlot.cs` and `AlbumViewPage.cs`
2. Re-assign old prefabs in inspector
3. Both systems revert to old
### After Phase 4 (Old Scripts Deleted)
1. Restore old scripts from Git history
2. Recreate old prefabs (if not archived)
3. Revert consumer scripts
**Prevention:** Archive old prefabs before deleting!
---
## CardDisplay.cs - The Survivor
**Why CardDisplay is NOT replaced:**
CardDisplay is a **pure visual renderer**. It:
- Takes CardData and displays it
- Has no state management
- Has no animation logic
- Has no interaction logic
This is **exactly what we want**! The new system uses CardDisplay as-is.
**Old hierarchy:**
```
FlippableCard
└─ AlbumCard
└─ CardDisplay ← renders visuals
```
**New hierarchy:**
```
Card (state machine)
└─ CardDisplay ← same renderer!
```
CardDisplay is already well-designed - it's a "presenter" in the MVP pattern. Keep it!
---
## Migration Checklist
### Preparation
- [ ] New Card.prefab created and tested in isolation
- [ ] CardAnimationConfig asset created
- [ ] All state scripts compiled without errors
- [ ] Team aware of upcoming changes
### Phase 2: Booster Opening
- [ ] Update BoosterOpeningPage.cs to use Card.prefab
- [ ] Remove FlippableCard references
- [ ] Update prefab assignments in inspector
- [ ] Test booster opening flow thoroughly
- [ ] Fix any issues before proceeding
### Phase 3: Album System
- [ ] Update AlbumCardSlot.cs to use Card.prefab
- [ ] Update AlbumViewPage.cs to use Card.prefab
- [ ] Remove AlbumCard references
- [ ] Update prefab assignments in inspector
- [ ] Test album interactions thoroughly
- [ ] Test booster→album flow (cards placed after opening)
### Phase 4: Cleanup
- [ ] Archive old prefabs (FlippableCard, AlbumCard)
- [ ] Delete FlippableCard.cs
- [ ] Delete AlbumCard.cs
- [ ] Delete AlbumCardPlacementDraggable.cs (if fully replaced)
- [ ] Run full regression test suite
- [ ] Update team documentation
- [ ] Celebrate! 🎉
---
## FAQ
**Q: Can I use both systems simultaneously?**
A: Yes, during migration. One scene can use FlippableCard while another uses Card.prefab.
**Q: Will old prefabs still work?**
A: Yes, until you delete the old scripts. Prefabs using FlippableCard will continue to function.
**Q: Do I need to migrate all at once?**
A: No! Recommended approach is scene-by-scene (Phase 2, then Phase 3).
**Q: What about CardDisplay?**
A: Keep it! It's used by both old and new systems. It's well-designed and doesn't need changes.
**Q: What if I find bugs in the new system?**
A: Rollback to old system (see Rollback Plan section), fix bugs, then retry migration.
**Q: How long will migration take?**
A: Estimated 6-10 hours total (2-4 for booster, 4-6 for album, testing time).
**Q: Will performance improve?**
A: Yes! 60% less code, more efficient state management, shared animation system.
---
## Summary
### Old Scripts Status:
| Script | Status | Timeline |
|--------|--------|----------|
| CardDisplay.cs | ✅ **KEEP** | Forever (it's perfect!) |
| FlippableCard.cs | 🔄 **REPLACE** | Phase 2 (booster) |
| AlbumCard.cs | 🔄 **REPLACE** | Phase 3 (album) |
| AlbumCardPlacementDraggable.cs | 🔄 **REPLACE** | Phase 3 (album) |
### Migration Path:
```
Now Phase 2 Phase 3 Future
────────────────────────────────────────────────────────────
Both systems → Booster uses → All use → Old scripts
coexist new Card, new Card deleted
album uses old
```
### Key Insight:
**You're not "fixing" the old scripts - you're replacing their ARCHITECTURE.**
The old scripts work, but they're built on a flawed foundation (wrapper hell, boolean soup). The new system solves this with isolated states and clean separation of concerns.
Think of it like replacing a house's foundation - you keep the furniture (CardDisplay), but rebuild the structure underneath.
---
**Ready to start? Begin with Phase 2 (Booster Opening) - it's the cleanest migration path!**