Pls don't feed my creation to AI ;>


A file where I dumped ideas for this project.

CLI Commands:
- Add `init` and `install`
  `init` is used initialize the ".mcserver" directory and its configurations.
  And `install` is used to install and setup the Minecraft server with the configuration inside ".mcserver".

Mod Management:
- Add mod search command with Modrinth: Done!
- Mod search with key=value. eg, mcserver search lithium limit=20: using flag

Miscellaneous
- Rename "ram" to "memory"? Only in script
- Shrink the project scope first: Yep!

new things
- Create config generator and loader: Done
- Make the search_mod limit based in modrinth configuration file: Done

Here's where I can yap about something
- CHANGELOGS.md is primarily for myself?

---

Semantic Versioning (MAJOR.Minor.patch):
- MAJOR: When you make incompatible API changes
- Minor: When you add functionality that is backward compatible
- patch: When you make bug fixes

The "v" Version Prefix:
- Use in:
  - Git Tag
  - Github Release
  - `mcserver --version`
  - User Agent
  - (Basically everything that a user will see)
- Don't use in:
  - Internal script version (`__version__`)
  - Changelog header
  - (Basically everything that is internal about the project)

Changelog Structure (Examples): ---

# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- Mod indexing

### Removed

- The whole project

## [<semver>] - <date(YYYY-MM-DD)>

### Added

- New command `D`

### Changed

- Command `A` now print `Hello, world!`

### Deprecating

- Removing command `C`

### Removed

- Command `B`

### Fixed

- Bug where the script stuck in an infinite loop

### Security

- Fix auth bug

## [0.0.0] - 2026-06-08

### Changed

- This example

[unreleased]: https://github.com/<username/<repo>/compare/<latest_tag>...HEAD
[<semvar>]: https://github.com/<username>/<repo>/compare/<prev_tag>...<tag>
[0.1.0]: https://github.com/<username>/<repo>/releases/tag/v0.1.0

---

make it nicer (imposible)
#- what am I doing making this project? my school has nothing to do with it. Me being self-deprecating and having Impostor Syndrome while coding is apparently normal? how? #TODO: comment-out this line
#paper? later. I mean it is close to being worked on ;)
#progress bar: whats that
warn client only mod because as the name suggest, it is designed for server! client already have too much attention ;/
#fabric installer, be dynamic (but sadly coding is not that magical that I can command the computer easily :insert_smile_with_tears_emoji:)
add init options for search because I felt like it: future/present me here. I, in fact, don't actually felt like it.
Lol the data-driven backup >:(
#pid lock I guess, what? .mcserver/.lock
be a good API citizen and implement ratelimit check >:)
auto download sometimes, when there's no optional or incompatible mods, or the size is "reasonable": what are you talking about?
haha, the scope will grow even more when you implement that rdepends >:)
oh hell nah, I already implemented that rdepends? how so quick? I have AI as helper, if you know rubberducking, that is exactly what I'm doing! not vibecoding I swear.
#Before that, fix my data migration logic first to make every single entry uses id as the key and don't leave any slug left! done, lol
After that, also implement a conflict check pls, like if you request this mod and that mod, and they met as "incompatible", whatever. you are kinda responsible for that, not really but nice to have, and make yourself comoareable to Prism >:). by "you" I mean myself. there, pls update your mcserver
#And then? hahaha, the hole of the rabbithole for dependency resolution didn't end there, you have to index them. why? because I said so. nah jk, because we should know that we already have Fabric API installed so we don't redownload it again. wdym?
remove? list? update? clean? check? yep, btw clean means remove orphaned mods, and check? I guess that can be used to scan for any manual .jar added in mods/
now make any mod that are incompatible ripples down to the source, only stopped by an optional mod -_-, wait, why I'm bother to fetch optional mods? just make it required only! idk I'm in the middle of refactoring rn
You screwed up the add command lol, no I'm not >:c
mod indexing, don't forget! don't remind me the... 3rd time?
Gemini suggest adding "status" command and get ram usage info, sure but not now. oh good idea I guess

Things that MCServer can touch (In theory):

XDG Cache
- mcserver
  - slug_index.json


Home Directory
- .cache # Failback if XDG Cache is not set
  - mcserver
    - slug_index.json


Server Root
- .mcserver/
  - configs/
    - launcher.json
    - modrinth.json
    - server.json
  - modrinth/
    - projects_records/
      - <project_id>.json
  - tempfiles/
    - <file_hash>
    - <url_hash> #if file hash does not exist, use hash from digesting the URL
  - metadata.json
  - state.json
- banned-ips.json
- banned-players.json
- eula.txt
- ops.json
- server.properties
- usercaches.json
- whitelist.json
- <jarfile_name>.jar

- A good error message for UX is one that not only tell you what went wrong, but also how to fix that error (or at least tell what caused the error) | Not like I'm interested right now...
- Consider to cache optional projects' bulk fetch data in resolved_projects even though we don't neccesearily process it?
- Delete cache if we don't install it (like dry run)
- Oh, back with zipapp huh... and I also have pyright now? cool
- You know what's cool? the ability to put 1.125M in the RAM config ofc. and also check if system RAM is even enough to run the server with the config.
- Make backup data-driven, meaning you can choose what ro get bsckup. and also option to rotate backup seems good for storage, deleting older backup for the new one.
- Hey, make every command function print with log.error and return as integer instead of raising error pls :>
- .mcserver/metadata.json and .mcserver/lock.json
- Warn projects that don't show up when `show`
- Actually, .mcserver/state.json (replacing lock.json) sounds better, and we can store pid_number, action, and created_time?
- The `show` command could show which Minecraft version are in common, pls future me >:). either in each mod's entry or at the end as sumarry of some sort.
- ChatGPT just told me about zipapp just now? Yes, it did.

I got an idea about the dependency resolution this small project (line 111)
So, instead of a big resolve_projects that do almost everything, why don't we just split them?
We can have a "data provider", function that when called will return the data that the resolver needs.
The "rule", or just the conflict checker -_-
And the BFS, the engine of the resolver.
probably like:
user: "request mod a"
resolve_dependencies: hey get_project_dependencies, what are the dependencies of mod a?
get_project_dependencies: mod b is required and mod c is required
resolve_dependencies: are mod b is somehow incompactible?
check_dependency_conflicts: no
resolve_dependencies: are mod c is somehow incompactible??
check_dependency_conflicts: no
resolve_dependencies: ok... what are dependencies of mod b?
(some dialogue later)
resolve_dependencies: ok, there's no more dependency. here you go "return the list of dependencies"
user: why are there 29 mods including dependencies 0_0 (basucally the resolver works)

on second thought, the caller is the one that handle conflict.

thx chatgpt but I can't prove it yet

- Merge install command functionallity to the start command [Done; 2026/07/03]
- Add import command to import .mrpack or future .mcserver
- Add export command
- Make the downloader:
  - Continue from where it left of
  - Internet speed from five seconds history
  - ETA
  - Make the status update each seconds instead of every packet recieved
- Please, somehow make the codebase morebmanageable ;-;
- Review codes, especially TypedDict, because why not
- Avoid making myself suffer in this project, potentially abandoning this cool project
- I hate CurseForge personally.



- And yet I still have no friend (to talk about my weird hobby of computer, including this)

- Oh hi Finjer! idk if you are reading this, cool. so uh... idk I added stuff I guess, or remove stuff.



- Add command such as 'whitelist add/remove/list', 'ban/unban/ban-list', and probably 'op/deop <player> <level>'

MCServer™ Naming Convention: (the Trademark is just a joke)
- is_*
  The value is true or false
  - Examples:
    - is_featured
    - is_primary
- filename
  Full file name with extension
- file_path
  The path of a file (relative to current working directory)
- download_url
  URL that can be downloaded
- *_count
  Return a number of something
  - Examples:
    - download_count
    - follower_count
- file_size
  The size of the file in byte
- file_hashes
  A hash or multiple hashes of the file
- *_url:
  Its an URL.
  - The `get_`

- Fix the "get_players_from_names" in minecraft_api.py. you mean, adding Content-Type: application/json? nvm I fixed it the same day anyway.

pls Othecat35, stop using AI.
- Othecat35 (2026/07/16)

(sadly) I could break that promise any seconds
- Othecat35 (2026/07/16)

I definitely broke my promise. (oops)
- Othecat35 (2026/07/20)


- Command like `mcserver config <set/get> <option>` and option probably just those options in init,
  so "mc_version" can mean <server.json>.game_version.
- init command could take some sort of "target dir"
- make src/mcserver/modrinth/projects.py into a dir, ans inside it we have metadata.py and relationship.py
- flowchart TD
  A[Did you fix a bug?]
  A -- Yes --> B[It's fix]

  A -- No --> C[Did you change functionality or affect UI?]
  C -- Yes --> D[It's feat]

  C -- No --> E[Did you add or change tests?]
  E -- Yes --> F[It's test]

  E -- No --> G[Did you change code style or formatting?]
  G -- Yes --> H[It's style]

  G -- No --> I[Did you make changes to documentation?]
  I -- Yes --> J[It's docs]

  I -- No --> K[Did you change things related to build or deploy operations?]
  K -- Yes --> L[It's build]

  K -- No --> M[Did you change something related to devops, infrastructure or backups?]
  M -- Yes --> N[It's ops]

  M -- No --> O[Did you complete a maintenance task or other non-code task?]
  O -- Yes --> P[It's chore]

  O -- No --> Q[Did you rewrite or restructure code specifically for performance?]
  Q -- Yes --> R[It's perf]

  Q -- No --> S[It's refactor]

- commit convention reference: https://gist.github.com/qoomon/5dfcdf8eec66a051ecd85625518cfd13
- or more "official" looking: https://www.conventionalcommits.org/en/v1.0.0/

Othecat35's Development Setup (For anyone if wondering):
- VSCodium
  - Extensions:
    Pyright
    Python

that's all lol


so, Modrinth has new way to represent which mod go to which environment right?
so it make the older 'server_side' and 'client_side' obselete.
but, most of my code rely on them.
what if, I make a 'translator' between the new 'environment' and the old '*_side'?
"How can you do that?" said Othecat35.
well, just convert one value into two values. like if the environment is 'client_and_server',
then the server_side is required and server_side is required
required = you need this mod on this side
recommended = this mod is recommended to be installed on this side
optional = you can have this mod in this side, or not
unsupported = basically this side is a side effect (it works but uh...)
incompatible = this mod may crash on this side
unknown = the dev doesn't even know their mod, wth
the mapping table (as for 2026-09-05, basically the time I wrote this):
| environment                   | server side   | client side   |
|-------------------------------|---------------|---------------|
| client_and_server             | required      | required      |
| client_only                   | unsupported   | required      |
| client_only_server_optional   | optional      | required      |
| singleplayer_only             | incompactible | required      |
| server_only                   | required      | unsupported   |
| server_only_client_optional   | required      | optional      |
| dedicated_server_only         | required      | incompactible |
| client_or_server              | optional      | optional      |
| client_or_server_prefers_both | recommended   | recommended   |
| unknown                       | unknown       | unknown       |

todo: move src/mcserver/server to src/mcserver/minecraft/server
because it make more sense I think

the export command... ".mcserver" and ".mrpack" format.
.mrpack is Modrinth Modpack format, I already know that.
.mcserver? what's this? a custom format? why?
idk, maybe it can store the actual configs of the server
the mod relationships, the metadata, etc
the pros is can contain more metadata of the server.
okay. but why? idk, maybe it looks cool? yea sure.

warning for those who want to interact with .properties,
consider bring your own module and don't use my parser.
why? its not perfect, and, basically don't. I only make it
to work with Minecraft, properties files like server.properties
and eula.txt.

4.0.0:
no add/remove for whitelist yet
no grant/revoke for op yet
no update command yet
and actually, no import command

for the remove command, I would use the resolver I already had. But it would be more complicated once we're dealing with mod that shared dependencies with other. I don't know ;-; I haven't even finished the add commad yet, but it is in incremental so don't rush me >:c
make a visualize command to visualize installed projects that output to graphviz format seems really cool
we should merge the metadata.json and relationships.json back into one file :o

look at myterious.py, idk why yiu thought it would be a good idea to make it more fun, and dynamic even.
mcserver export --client-setup seems nice
mcserver add thdilos-fox-origin -y is better
mcserver add jade --include-optional make sense, but for specifically requested mod that is client_only_server_optional, include them. otherwise, put them into "suggested" mods.

yo the get_project_informations() is broken because moderator_message can be null
as for every API interface/client, we can instead return parsed (for those who we already know the structure), and then another, extra (just a dict[str, Any]). call the new typeddict, *Data.

About lazy loading imports... what if I make it so that imports that are required regardless, just
import it on the module instead? because if you do import it, you must have a reason to do so. Like,
you don't import a module and not use it at all, right? so just move the imports outside the function.
init.py:
import argparse

def init(args: argparse.Namespace):
    import logging
    ...


init.py:
import argparse
import logging

def init(args: argparse.Namespace):
    ...

so, if you import init, you of course want to run init() right? so lazy-laoding it is not just useless,
it also make the code a bit more unreadable.
When do we lazy-loading stuff? imports that aren't always needed. Like command invocation in cli.py
with match case, because you don't need any to print the help message (except the help command itself),
or if you did, like init, you don't neccesearily need to import the stop command right? and also other
case is in init.py and start.pt. it import the appropriate loader and not other.

hmmm yes, global .mcserver config, just like cache.
it can be the default config of all your new Minecraft server derived from
and yea


Ah yes... rcon, and also swrver management protocol.
Don't forget to add a warning fof whitelist remove if the server is running to run whitelist remover

about whitelist add or op grant, remember to make the internal function does remove and add together, then call it upsert according to deepseek
