Firebase Backend

Setup & Run Guide

Scope ‑ This document explains how to integrate the BulletHell Elemental Template v1.4 with Firebase Authentication and Cloud Firestore. It covers both a Quick Start for experienced users and a Step‑by‑Step walkthrough with screenshots for newcomers.


Read the offline backend page first

1. Quick Start (Experienced Users)

  1. Unity Version – 2022.3 LTS (or newer).

  2. Packages – Ensure the following Unity packages are installed via Package Manager:

    • Input System

    • AI Navigation

    • In‑App Purchasing

    • 2D Sprite

    • TextMeshPro (TMP)

  3. Firebase SDK – Import:

    • FirebaseAuth 12.2.0 (or newer)

    • FirebaseFirestore 12.2.0 (or newer)

    • add FIREBASE in Scripting Define Symbols in Build Settings > Player

  4. Template – Import BulletHell Elemental Template.

  5. Scenes – Add to Build Settings in this order: Login, Home, other maps.

  6. Tags / Layers – If missing, add Monster tag and assign it to all enemy prefabs.

  7. google‑services.json – Download from the Firebase Console and place inside Assets/StreamingAssets/ (create the folder if missing). Name must remain unchanged.

  8. Firebase Console

    • Enable Email/Password and Anonymous sign‑in in Authentication → Sign‑in method.

    • Create Firestore collection Players.

    • Create root‑level collection BattlePass with

      • Document ID: SeasonInfo

      • Field Season (Number → 1)

      • Field StartSeason (Timestamp → season start date)

    • Apply the security rules shown below.

  9. Run – Press Play in the Login scene. Account creation & data sync occur automatically.

Firestore Database Rules :

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    /* ───────── helper predicates ───────── */
    function isSignedIn()  { return request.auth != null; }
    function isOwner(uid)  { return isSignedIn() && request.auth.uid == uid; }

    /* ────────────────────────────────────────────────────────────────
    match /Players/{uid} {

      /* READ (single doc + queries/collections) */
      allow get, list: if isSignedIn();

      /* WRITE (create/update/delete) – owner only */
      allow create, update, delete: if isOwner(uid);

      /* Inventory sub-collection */
      match /PurchasedItems/Items/List/{itemId} {
        allow get, list, create, update, delete: if isOwner(uid);
      }

      /* Catch-all for nested docs (Characters, Progress, …) */
      match /{document=**} {
        allow get, list, create, update, delete: if isOwner(uid);
      }
    }

    /* ────────────────────────────────────────────────────────────────
     *  GLOBAL NICKNAME REGISTRY  (/PlayerNames/{nameLower})
     * ─────────────────────────────────────────────────────────────── */
    match /PlayerNames/{nameLower} {
      allow get:  if true;
      allow list: if false;

      allow create: if isSignedIn()
        && request.resource.data.keys().hasOnly(['ownerUid','createdAt'])
        && request.resource.data.ownerUid == request.auth.uid;

      allow update, delete: if isSignedIn()
        && resource.data.ownerUid == request.auth.uid
        && request.resource.data == resource.data;
    }

    /* ────────────────────────────────────────────────────────────────
     *  CURRENCIES  (/Players/{uid}/Currencies/{coinId})
     * ─────────────────────────────────────────────────────────────── */
    match /Players/{uid}/Currencies/{coinId} {
      allow get:  if isOwner(uid);
      allow list: if false;
      allow delete: if false;

      allow create: if isOwner(uid)
        && request.resource.data.keys().hasOnly(['initialAmount','amount'])
        && request.resource.data.initialAmount is int
        && request.resource.data.amount        is int
        && request.resource.data.initialAmount >= 0
        && request.resource.data.amount        >= 0;

      allow update: if isOwner(uid)
        && request.resource.data.keys().hasOnly(['amount'])
        && request.resource.data.amount is int
        && request.resource.data.amount >= 0;
    }

    /* ────────────────────────────────────────────────────────────────
     *  BATTLE-PASS META  (/BattlePass/SeasonInfo)
     * ─────────────────────────────────────────────────────────────── */
    match /BattlePass/{docId} {
      allow get: if isSignedIn() && docId == "SeasonInfo";
      allow list, create, update, delete: if false;
    }
  }
}

For developers who have not yet set up a project with Firebase or who have any questions, below is a detailed step-by-step guide with images:

2. Step‑by‑Step Guide (With Images)

2.1 Create a URP Project

  1. Open Unity Hub → New Project.

  2. Select Universal 3D (URP) template.

  3. Name your project and click Create.

Optional – HDRP/Built‑in pipelines work, but demo textures may need conversion.

2.2 Install Required Unity Packages

Window → Package Manager → Unity Registry. Add Input System, AI Navigation, In‑App Purchasing, 2D Sprite, TextMeshPro.

2.3 Import Firebase SDK

  1. Download FirebaseAuth.unitypackage and FirebaseFirestore.unitypackage from the Firebase Unity SDK Archive.

  2. Double‑click each package to import.

  3. When prompted, allow ExternalDependancyManager to resolve libraries.

  4. add FIREBASE in Scripting Define Symbols in Build Settings > Player

2.4 Import the Template

Drag the BulletHell Elemental Template .unitypackage into the Editor or install via Package Manager → My Assets.

2.5 Configure Project Settings

  • Player Settings → Identification → Package Name must match the Android/iOS package names you register in Firebase.

  • Switch Platform to Android or iOS before building (Editor → File → Build Settings).

2.6 Firebase Console Configuration

  1. Create Project → add Android and/or iOS app with the correct package name.

  2. Download google‑services.json (Android) or GoogleService‑Info.plist (iOS).

  3. Place json file in Assets/StreamingAssets/. If Unity cannot locate the file, verify the folder name and that the filename has no suffix (e.g., (1)).

  1. Firestore Database → Start in production mode.

  2. Create Collection Players → add a dummy document (ID can be auto‑generated).

  3. Create Collection BattlePass → new document SeasonInfo.

    • Add Number field Season = 1.

    • Add Timestamp field StartSeason = <TODAY>.

  4. Apply the security rules (see Quick Start above).

2.8 Prepare Cloud Firestore

  • Authentication → Sign‑in method: enable Email/Password and Anonymous.

2.7 Enable Authentication

2.8 Prepare Cloud Firestore

  1. Firestore Database → Start in production mode.

  2. Create Collection Players → add a dummy document (ID can be auto‑generated).

  3. Create Collection BattlePass → new document SeasonInfo.

    • Add Number field Season = 1.

    • Add Timestamp field StartSeason = <TODAY>.

  4. Apply the security rules (see Quick Start above).

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    /* ───────── helper predicates ───────── */
    function isSignedIn()  { return request.auth != null; }
    function isOwner(uid)  { return isSignedIn() && request.auth.uid == uid; }

     * ─────────────────────────────────────────────────────────────── */
    match /Players/{uid} {

      /* READ (single doc + queries/collections) */
      allow get, list: if isSignedIn();

      /* WRITE (create/update/delete) – owner only */
      allow create, update, delete: if isOwner(uid);

      /* Inventory sub-collection */
      match /PurchasedItems/Items/List/{itemId} {
        allow get, list, create, update, delete: if isOwner(uid);
      }

      /* Catch-all for nested docs (Characters, Progress, …) */
      match /{document=**} {
        allow get, list, create, update, delete: if isOwner(uid);
      }
    }

    /* ────────────────────────────────────────────────────────────────
     *  GLOBAL NICKNAME REGISTRY  (/PlayerNames/{nameLower})
     * ─────────────────────────────────────────────────────────────── */
    match /PlayerNames/{nameLower} {
      allow get:  if true;
      allow list: if false;

      allow create: if isSignedIn()
        && request.resource.data.keys().hasOnly(['ownerUid','createdAt'])
        && request.resource.data.ownerUid == request.auth.uid;

      allow update, delete: if isSignedIn()
        && resource.data.ownerUid == request.auth.uid
        && request.resource.data == resource.data;
    }

    /* ────────────────────────────────────────────────────────────────
     *  CURRENCIES  (/Players/{uid}/Currencies/{coinId})
     * ─────────────────────────────────────────────────────────────── */
    match /Players/{uid}/Currencies/{coinId} {
      allow get:  if isOwner(uid);
      allow list: if false;
      allow delete: if false;

      allow create: if isOwner(uid)
        && request.resource.data.keys().hasOnly(['initialAmount','amount'])
        && request.resource.data.initialAmount is int
        && request.resource.data.amount        is int
        && request.resource.data.initialAmount >= 0
        && request.resource.data.amount        >= 0;

      allow update: if isOwner(uid)
        && request.resource.data.keys().hasOnly(['amount'])
        && request.resource.data.amount is int
        && request.resource.data.amount >= 0;
    }

    /* ────────────────────────────────────────────────────────────────
     *  BATTLE-PASS META  (/BattlePass/SeasonInfo)
     * ─────────────────────────────────────────────────────────────── */
    match /BattlePass/{docId} {
      allow get: if isSignedIn() && docId == "SeasonInfo";
      allow list, create, update, delete: if false;
    }
  }
}

2.9 Verify Tags, Layers & Scenes

If you imported the template into an existing project:

  • Add Monster tag in Edit → Project Settings → Tags & Layers.

  • Assign it to enemy prefabs in BulletHellTemplate/Resources/Monsters/.

  • Ensure scene order in Build Settings: Login, Home, others.

2.10 Test in Editor

  1. Open Login scene.

  2. Press Play – the template auto‑creates a local account, syncs with Firebase, and loads initial data.

  3. Check Console for Firebase initialization logs.

3. Common Issues & Fixes

Issue

Cause

Fix

google‑services.json not found

File in wrong location

Place inside Assets/StreamingAssets/. Refresh project.

"Unknown error" on account creation

Weak password

Use at least 8 chars, 1 number, 1 special char.

Android/iOS build fails on "Validate References"

Unused platform DLLs

Edit → Project Settings → Player → Other Settings, disable Validate References for unsupported platform.


4. Next Steps

  • Customize Battle Pass seasons by updating Season and StartSeason fields.

  • Harden security with App Check or move save logic to Cloud Functions (requires paid Firebase plan).

  • Join our community for support and feature requests.

Discord – https://discord.com/invite/EGGj77g3eQ Email – rafbizachi5@gmail.com

Last updated