Skip to main content

Editor Firebase

Important Information

The EditorFirebase.cs class generates an Editor-prepared Firebase connection, for usage outside of Play mode. This Editor helper acts as a supply-source for many visualization tools, such as the Transactional Item Graph View

warning

The EditorFirebase instance must be created as a named instance, not using default GetInstance(). This is to ensure proper runtime static variables are reset behind-the-scenes at Firebase. CITATION NEEDED FOR FIREBASE GUIDELINE

app = FirebaseApp.Create(
FirebaseApp.DefaultInstance.Options,
"FIREBASE_EDITOR");

Only utilize one Editor Firebase singleton at a time. Do not change scenes while Editor Firebase is connected. I've done my best to add robust safeties to ensure a lack of memory leak in-editor, but it's advisable to be very deliberate when turning on/off Editor Firebase.


Code Reference:

Assets/Scripts/Editor/EditorFirebase.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Firebase;
using Firebase.Firestore;
using m00m.Scripts.SO_Base.CharacterBuilder;
using Sirenix.Utilities;
using UnityEngine;

#if UNITY_EDITOR
[ExecuteAlways]
#endif
public class EditorFirebase : MonoBehaviour
{

public static EditorFirebase Local;
public AssetPool Pool;
public Action OnPurchasablesUpdated = delegate { };
public PlayerConfiguration_SO playerConfiguration;

[NonSerialized]
public Dictionary<PlayerItem_SO, FireAuth.PurchasableItem> purchasableClothes = new();
[NonSerialized]
public Dictionary<InventoryItem_Base_SO, FireAuth.PurchasableItem> purchasableInventoryItems = new();
[NonSerialized]
public Dictionary<ItemPack_SO, FireAuth.PurchasableItem> purchasablePacks = new();
[NonSerialized]
public Dictionary<PlayerOutfit, FireAuth.PurchasableItem> purchasableOutfits = new();
[NonSerialized]
public Dictionary<PlayerEquipment_SO, FireAuth.PurchasableItem> purchasableEquipment = new();
[NonSerialized]
public Dictionary<ColorwayBase_SO, FireAuth.PurchasableItem> purchasableColorways = new();
[NonSerialized]
public Dictionary<BuildItemData, FireAuth.PurchasableItem> purchasableBuildItem = new();


[ContextMenu("Start Editor Listeners")]
public void EditorListener()
{
if (Local == null)
ListenForPurchasables();
}

[ContextMenu("End Editor Listeners")]
public void EndEditorListener()
{
StopListeners();
}

public void SendToFirebase(TransactionalItemData_Base_SO item)
{
/**
* Internal function to type check the derivative from TransactionalItemData_Base_SO
* and send to Firebase with the proper type, typically using other intermediary
* helper functions, such as SendToFirebase(PlayerItem_SO item) when the Type of
* transactional item is PlayerItem_SO.
*/
}

public void SendToFirebase(PlayerItem_SO individualItem)
{
//Wrapper to ascribe the right type when using helper function
}

public void SendToFirebase(BuildItemData data)
{
//Wrapper to ascribe the right type when using helper function
}

public void SendToFirebase(TransactionalItemData_Base_SO individualItem, PurchasableType type)
{
//Wrapper to ascribe the right type when using helper function
}

public void SendToFirebase(PlayerItemPack pack)
{
//Packs are handled a bit differently, as we create a singular purchasable item that contains child items, for a set price.
//This allows us to offer a discount on a bundle of items, or sell a collab pack for a set price.
//Wrapper to ascribe the right type when using helper function
}

public void SendToFirebase(InventoryItem_Base_SO inventoryItem)
{
//Wrapper to ascribe the right type when using helper function
}

public void SendToFirebase(PlayerOutfit outfit)
{
//Wrapper to ascribe the right type when using helper function
}

/**
* Enum with mapped StringValue to get the official string-type when stored in Firebase.
* We are moving towards lowercase-only support to eliminate any potential casing issues.
* The string value is accessed by:
* PurchasableTypes.Pack.StringValue() => "pack"
*/

[System.Serializable]
public enum PurchasableType
{
[StringValue("PlayerItem")]
PlayerItem,
[StringValue("Inventory")]
Inventory,
[StringValue("pack")]
Pack,
[StringValue("outfit")]
Outfit,
[StringValue("equipment")]
Equipment,
[StringValue("colorway")]
Colorway,
[StringValue("builditem")]
BuildItem
}


/**
* Function to access Firebase SDK and sync latest data, specifically for outfits
*/
public async Task SendOutfitToFirebasePurchasables(PlayerOutfit outfit)
{
// Outfits work similarly to packs, except they are not discounted at a set price.
// An outfit is priced based on outstanding items the player has yet to own.
}

/**
* Function to access Firebase SDK and sync latest data, for all other Transactional Item Data Bases.
*/
public async Task SendToFirebasePurchasables(TransactionalItemData_Base_SO item, PurchasableType type)
{
if (Local == null) return;
if (type == PurchasableType.Pack && item is PlayerItemPack pack)
{
List<FireAuth.PurchasableIncludes> includes = new List<FireAuth.PurchasableIncludes>();
foreach (var _item in pack.playerItems)
{
includes.Add(new FireAuth.PurchasableIncludes()
{
itemID = _item.id,
type = PurchasableType.PlayerItem.StringValue()
});
}
await db.Collection(FireAuth.NetworkingConstants.PURCHASABLES).Document(pack.packID).SetAsync(new FireAuth.PurchasableItem()
{
creditCost = pack.packCostCredits,
itemID = pack.packID,
type = type.StringValue(),
includes = includes.ToList()
});
}
else
{
await db.Collection(FireAuth.NetworkingConstants.PURCHASABLES).Document(item.id).SetAsync(new FireAuth.PurchasableItem()
{
creditCost = item.creditCost,
itemID = item.id,
type = type.StringValue()
});
}
}

void ListenForPurchasables()
{
/**
* Internal function to gather purchasable items, and sort
* into the given public dictionaries to be accessed by other features.
*/
}
}