Compare commits
	
		
			6 commits
		
	
	
		
			26f23a1354
			...
			7d0ddc492c
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 7d0ddc492c | |||
| de7670204a | |||
| 846130771e | |||
| 4f853df32c | |||
| 8fb91f7754 | |||
| 37ac7dbb0c | 
					 4 changed files with 155 additions and 21 deletions
				
			
		
							
								
								
									
										5
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -181,5 +181,6 @@ cython_debug/ | ||||||
| .cursorindexingignore | .cursorindexingignore | ||||||
| 
 | 
 | ||||||
| # Custom stuff | # Custom stuff | ||||||
| gacha_game.db | gacha_game*.db | ||||||
| config.ini | gacha_game*.db.* | ||||||
|  | config*.ini | ||||||
|  |  | ||||||
|  | @ -1,7 +1,26 @@ | ||||||
| '''Essentials for the bot to function''' | '''Essentials for the bot to function''' | ||||||
| import configparser | import configparser | ||||||
|  | from os import environ, path | ||||||
|  | 
 | ||||||
|  | class ConfigError(Exception): | ||||||
|  |     '''Could not find config file''' | ||||||
|  | 
 | ||||||
|  | def get_config_file() -> str: | ||||||
|  |     '''Gets the path to the config file in the current environment''' | ||||||
|  |     env: str | None = environ.get('KEMOVERSE_ENV') | ||||||
|  |     if not env: | ||||||
|  |         raise ConfigError('Error: KEMOVERSE_ENV is unset') | ||||||
|  |     if not (env in ['prod', 'dev']): | ||||||
|  |         raise ConfigError(f'Error: Invalid environment: {env}') | ||||||
|  | 
 | ||||||
|  |     config_path: str = f'config_{env}.ini' | ||||||
|  | 
 | ||||||
|  |     if not path.isfile(config_path): | ||||||
|  |         raise ConfigError(f'Could not find {config_path}') | ||||||
|  |     return config_path | ||||||
|  | 
 | ||||||
| config = configparser.ConfigParser() | config = configparser.ConfigParser() | ||||||
| config.read('config.ini') | config.read(get_config_file()) | ||||||
| 
 | 
 | ||||||
| # Username for the bot | # Username for the bot | ||||||
| USER     = config['credentials']['User'] | USER     = config['credentials']['User'] | ||||||
|  |  | ||||||
							
								
								
									
										116
									
								
								readme.md
									
										
									
									
									
								
							
							
						
						
									
										116
									
								
								readme.md
									
										
									
									
									
								
							|  | @ -2,33 +2,41 @@ | ||||||
| 
 | 
 | ||||||
| A gacha-style bot for the Fediverse built with Python. Users can roll for characters, trade, duel, and perhaps engage with popularity-based mechanics. Currently designed for use with Misskey. Name comes from Kemonomimi and Fediverse. | A gacha-style bot for the Fediverse built with Python. Users can roll for characters, trade, duel, and perhaps engage with popularity-based mechanics. Currently designed for use with Misskey. Name comes from Kemonomimi and Fediverse. | ||||||
| 
 | 
 | ||||||
|  | ## Installation | ||||||
|  | 
 | ||||||
|  | ## Roadmap | ||||||
|  | 
 | ||||||
|  |  | ||||||
| 
 | 
 | ||||||
| ## 🔧 Features | ## 🔧 Features | ||||||
| 
 | 
 | ||||||
| ### ✅ Implemented | ### ✅ Implemented | ||||||
| - 🎲 Character roll system | - 🎲 Character roll system | ||||||
| - 🎴 Cards stats system | - 🧠 Core database structure for cards | ||||||
| - 🧠 Core database structure for characters and stats | - 📦 Basic support for storing pulls per player | ||||||
| - 📦 Basic support for storing pulls per user | - ⏱️ Time-based limitations on rolls | ||||||
| 
 | 
 | ||||||
| ### 🧩 In Progress | ### 🧩 In Progress | ||||||
| - 📝 Whitelist system to limit access | - 📝 Whitelist system to limit access | ||||||
| - ⏱️ Time-based limitations on rolls | - ⚠️  Explicit account creation/deletion | ||||||
| - ⚔️ Dueling system |  | ||||||
| 
 | 
 | ||||||
| ## 🧠 Planned Features (Long Term) | ## 🧠 Roadmap | ||||||
|  | 
 | ||||||
|  | [See our v2.0 board for more details](https://git.waifuism.life/waifu/kemoverse/projects/3) | ||||||
| 
 | 
 | ||||||
| ### 🛒 Gameplay & Collection | ### 🛒 Gameplay & Collection | ||||||
| - 🔁 **Trading system** between users | - 🔁 **Trading system** between players | ||||||
| - ⭐ **Favorite characters** (pin them or set profiles) | - ⭐ **Favorite characters** (pin them or set profiles) | ||||||
| - 📢 **Public post announcements** for rare card pulls | - 📢 **Public post announcements** for rare card pulls | ||||||
|  | - 📊 **Stats** for cards | ||||||
|  | - 🎮 **Games** to play | ||||||
|  |   - ⚔️ Dueling | ||||||
| - 🧮 **Leaderboards** | - 🧮 **Leaderboards** | ||||||
|   - Most traded Characters |   - Most traded cards | ||||||
|   - Most owned Characters |   - Most owned cards | ||||||
|   - Most voted Characters |   - Most voted cards | ||||||
|   - Most popular Characters (via usage-based popularity metrics) |   - Most popular cards (via usage-based popularity metrics) | ||||||
|   - Users with the rarest Characters |   - Users with the rarest cards | ||||||
| 
 | 
 | ||||||
| ### 🎨 Card Aesthetics | ### 🎨 Card Aesthetics | ||||||
| - 🖼️ Simple card template for character rendering | - 🖼️ Simple card template for character rendering | ||||||
|  | @ -39,7 +47,7 @@ A gacha-style bot for the Fediverse built with Python. Users can roll for charac | ||||||
| 
 | 
 | ||||||
| ## 🗃️ Tech Stack | ## 🗃️ Tech Stack | ||||||
| 
 | 
 | ||||||
| - Python (3.11+) | - Python (3.12+) | ||||||
| - SQLite | - SQLite | ||||||
| - Fediverse API integration (via Misskey endpoints) | - Fediverse API integration (via Misskey endpoints) | ||||||
| - Flask | - Flask | ||||||
|  | @ -49,10 +57,88 @@ A gacha-style bot for the Fediverse built with Python. Users can roll for charac | ||||||
| 
 | 
 | ||||||
| The bot is meant to feel *light, fun, and competitive*. Mixing social, gacha and duel tactics. | The bot is meant to feel *light, fun, and competitive*. Mixing social, gacha and duel tactics. | ||||||
| 
 | 
 | ||||||
| ## 🧪 Getting Started (coming soon) | ## 🧪 Installation | ||||||
| 
 | 
 | ||||||
| Instructions on installing dependencies, initializing the database, and running the bot locally will go here. | ### Download and install dependencies | ||||||
| 
 | 
 | ||||||
|  | Clone the repo | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | git clone https://git.waifuism.life/waifu/kemoverse.git | ||||||
|  | cd kemoverse | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Setup a virtual environment (Optional, recommended) | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | python3 -m venv venv | ||||||
|  | source venv/bin/activate | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Install project dependencies via pip | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | python3 -m pip install -r requirements.txt | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### Setup config file | ||||||
|  | 
 | ||||||
|  | A sample config file is included with the project as a template: `example_config.ini` | ||||||
|  | 
 | ||||||
|  | Create a copy of this file and replace its' values with your own. Consult the | ||||||
|  | template for more information about individual config values and their meaning. | ||||||
|  | 
 | ||||||
|  | Config files are environment-specific. Use `config_dev.ini` for development and | ||||||
|  | `config_prod.ini` for production. Switch between environments using the | ||||||
|  | `KEMOVERSE_ENV` environment variable. | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | cp example_config.ini config_dev.ini | ||||||
|  | # Edit config_dev.ini | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### Setup database | ||||||
|  | 
 | ||||||
|  | To set up the database, run: | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | KEMOVERSE_ENV=dev python3 setup_db.py | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### Run the bot | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | KEMOVERSE_ENV=dev ./startup.sh | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | If all goes well, you should now be able to interact with the bot. | ||||||
|  | 
 | ||||||
|  | ### Running in production | ||||||
|  | 
 | ||||||
|  | To run the the in a production environment, use `KEMOVERSE_ENV=prod`. You will | ||||||
|  | also need to create a `config_prod.ini` file and run the database setup step | ||||||
|  | again if pointing prod to a different database. (you are pointing dev and prod | ||||||
|  | to different databases, right? 🤨) | ||||||
|  | 
 | ||||||
|  | ### Updating | ||||||
|  | 
 | ||||||
|  | To update the bot, first pull new changes from upstream: | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | git pull | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Then run any database migrations. We recommend testing in dev beforehand to | ||||||
|  | make sure nothing breaks in the update process. | ||||||
|  | 
 | ||||||
|  | **Always backup your prod database before running any migrations!** | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | # Backup database file | ||||||
|  | cp gacha_game_dev.db gacha_game_dev.db.bak | ||||||
|  | # Run migrations | ||||||
|  | KEMOVERSE_ENV=dev python3 setup_db.py | ||||||
|  | ``` | ||||||
| 
 | 
 | ||||||
| ```mermaid | ```mermaid | ||||||
| flowchart TD | flowchart TD | ||||||
|  |  | ||||||
							
								
								
									
										34
									
								
								setup_db.py
									
										
									
									
									
								
							
							
						
						
									
										34
									
								
								setup_db.py
									
										
									
									
									
								
							|  | @ -11,6 +11,12 @@ class DBNotFoundError(Exception): | ||||||
| class InvalidMigrationError(Exception): | class InvalidMigrationError(Exception): | ||||||
|     '''Migration file has an invalid name''' |     '''Migration file has an invalid name''' | ||||||
| 
 | 
 | ||||||
|  | class KemoverseEnvUnset(Exception): | ||||||
|  |     '''KEMOVERSE_ENV is not set or has an invalid value''' | ||||||
|  | 
 | ||||||
|  | class ConfigError(Exception): | ||||||
|  |     '''Could not find the config file for the current environment''' | ||||||
|  | 
 | ||||||
| def get_migrations() -> List[Tuple[int, str]] | InvalidMigrationError: | def get_migrations() -> List[Tuple[int, str]] | InvalidMigrationError: | ||||||
|     '''Returns a list of migration files in numeric order.''' |     '''Returns a list of migration files in numeric order.''' | ||||||
|     # Store transaction id and filename separately |     # Store transaction id and filename separately | ||||||
|  | @ -50,11 +56,22 @@ def perform_migration(cursor: sqlite3.Cursor, migration: tuple[int, str]) -> Non | ||||||
| 
 | 
 | ||||||
| def get_db_path() -> str | DBNotFoundError: | def get_db_path() -> str | DBNotFoundError: | ||||||
|     '''Gets the DB path from config.ini''' |     '''Gets the DB path from config.ini''' | ||||||
|  |     env = os.environ.get('KEMOVERSE_ENV') | ||||||
|  |     if not (env and env in ['prod', 'dev']): | ||||||
|  |         raise KemoverseEnvUnset | ||||||
|  | 
 | ||||||
|  |     print(f'Running in "{env}" mode') | ||||||
|  | 
 | ||||||
|  |     config_path = f'config_{env}.ini' | ||||||
|  | 
 | ||||||
|  |     if not os.path.isfile(config_path): | ||||||
|  |         raise ConfigError(f'Could not find {config_path}') | ||||||
|  | 
 | ||||||
|     config = ConfigParser() |     config = ConfigParser() | ||||||
|     config.read('config.ini') |     config.read(config_path) | ||||||
|     db_path = config['application']['DatabaseLocation'] |     db_path = config['application']['DatabaseLocation'] | ||||||
|     if not db_path: |     if not db_path: | ||||||
|         raise DBNotFoundError |         raise DBNotFoundError() | ||||||
|     return db_path |     return db_path | ||||||
| 
 | 
 | ||||||
| def get_current_migration(cursor: sqlite3.Cursor) -> int: | def get_current_migration(cursor: sqlite3.Cursor) -> int: | ||||||
|  | @ -71,7 +88,18 @@ def get_current_migration(cursor: sqlite3.Cursor) -> int: | ||||||
| def main(): | def main(): | ||||||
|     '''Does the thing''' |     '''Does the thing''' | ||||||
|     # Connect to the DB |     # Connect to the DB | ||||||
|     db_path = get_db_path() |     db_path = '' | ||||||
|  |     try: | ||||||
|  |         db_path = get_db_path() | ||||||
|  |     except ConfigError as ex: | ||||||
|  |         print(ex) | ||||||
|  |         return | ||||||
|  |     except KemoverseEnvUnset: | ||||||
|  |         print('Error: KEMOVERSE_ENV is either not set or has an invalid value.') | ||||||
|  |         print('Please set KEMOVERSE_ENV to either "dev" or "prod" before running.') | ||||||
|  |         print(traceback.format_exc()) | ||||||
|  |         return | ||||||
|  | 
 | ||||||
|     conn = sqlite3.connect(db_path, autocommit=False) |     conn = sqlite3.connect(db_path, autocommit=False) | ||||||
|     conn.row_factory = sqlite3.Row |     conn.row_factory = sqlite3.Row | ||||||
|     cursor = conn.cursor() |     cursor = conn.cursor() | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue