Code Monkey home page Code Monkey logo

backend's Introduction

Lochfolk Prinzessin Simulator (LPSim): 水皇模拟器,一个七圣召唤模拟器


Coverage Status PyPI version Ruff

该仓库为水皇模拟器的后端,用来模拟七圣召唤对局,使用Python 3.10编写,使用Pydantic和FastAPI。项目另有一个前端仓库,包含可以与该后端交互的前端页面。

该项目使用AGPL-3.0协议。如果您有任何基于此项目的二次开发和分发,请遵守该协议。

声明

本项目仅供学习交流使用,前端界面仅用于展示对局状态和方便代码调试。请在下载后24小时内删除与本项目相关的所有内容。所有相关代码基于AGPLv3协议开源。项目与米哈游公司无关,所有游戏素材版权归米哈游公司所有。本项目及其代码仓库中不包含米哈游具有版权的图像素材,或是任何与米哈游产品相关的非公开信息。

项目进度

✨ 4.5版本角色和卡牌,以及平衡性调整已实现。

🔨 4.6版本角色和卡牌,以及平衡性调整实现中,包含牌组顺序相关策略更新。

🚧 AI训练支持实现中,参考AI训练支持小节。

特性

  • 已实现所有截止当前版本的角色和卡牌,包括其历史版本。
  • 支持在同一套卡组中使用不同版本的角色和卡牌。
  • 支持作为一个小型服务器与客户端交互。
  • 提供了一个前端用来与服务器交互。
  • 可以从任意状态加载并继续运行,保持结果不变。
  • 100%代码覆盖率。

🚧 WIP: AI训练支持

使用水皇模拟器LPSim用作AI训练具有如下优势:

  1. 由于内部实现了所有卡牌版本,模拟器更新和官方平衡性改动几乎不会影响到之前训练好的AI策略,随时可以使用旧版本卡牌和策略与新版本卡牌策略进行对局和训练(如果旧版策略不会因为对手用新卡牌而无法工作的话)。
  2. 代码使用Python实现,便于集成至常见深度学习框架如PyTorch、TensorFlow中。
  3. 所有模拟过程由Match类的类函数实现,不包含多线程或网络通信,便于实现环境并行化。
  4. 基于Pydantic,Match可以从任意时刻导入导出且不改变接下来的模拟结果,便于复现和调试纠错。
  5. 已实现部分基本Agent,可以作为对手快速搭建单智能体环境;同时设计拥有交互式Agent,便于训练完Agent以后与与其对战。

目前已基于gymnasiumpettingzoo的环境定义,开发了gymnasium.Env, pettingzoo.AECEnv基本环境。由于如何准确将七圣状态表示为数组本身就是一个难题,基本环境暂未对状态的编码表示进行实现,可以继承该环境进行修改或是Wrapper来对观测和动作空间进行修改。

pettingzoo分支的src/lpsim/env文件夹中包含了上述环境实现,以及在Tianshou多智能体框架下的简单测试代码。目前环境还未经过详细测试,暂时以独立分支的方式存在且具有接口改动可能。AI相关代码目前仅在Python3.10测试,不保证其它版本可用性。

使用方法

该项目需要Python 3.10或更新版本。

使用pip安装

使用pip install lpsim安装最新的发布版本。你可以在PyPI找到最新的发布版本,在CHANGELOG.md找到更新日志。

使用pip install lpsim -i https://test.pypi.org/simple/安装最新的开发版本。当新的提交被推送到master分支并通过所有测试时,新的版本将会被发布到Test PyPI。当新的版本tag被推送到master分支时,新的版本将会被发布到PyPI。

使用源码安装

克隆该仓库并使用pip install .安装。

HTTP服务器

对局服务器

使用FastAPI提供一个HTTP对局服务器,用来与客户端交互。使用以下命令运行服务器:

from lpsim.network import HTTPServer
server = HTTPServer()
server.run()

它将在localhost:8000上开启一个FastAPI服务器,并接受本地连接。在初始化HTTPServer时,你可以设置卡组和对局配置来创建一个带有指定规则的对局。

启动服务器后,打开前端页面,在右上角修改服务器URL(默认为http://localhost:8000),按照页面上的指示设置卡组,并开始对局。

目前异常处理比较混乱,错误可能导致游戏状态变为ERROR,服务器抛出异常,客户端返回空响应,返回404/500,或者前端运行JS失败。请打开前端的控制台,并在前端后后端查看错误信息。

房间服务器

你可以使用房间服务器来提供多个对局。它管理多个HTTP服务器实例,前端可以创建新的房间或加入已有的房间。当一个新的房间被创建时,房间服务器会告诉前端房间名和它运行的端口,然后前端会连接到该端口上的HTTP服务器。当一个房间创建了很长时间并且没有收到POST请求时,它会自动关闭。更多细节请参考lpsim/network/http_room_server.pyhttp_room_serve.py

非交互对局

非交互对局主要用于代码测试和AI训练。你可以按照下述流程进行。

定义卡组

开始对局之前,需要先定义卡组。卡组可以使用文本或JSON格式定义。通常使用Deck.from_str就足够了,它可以定义角色和卡牌,以及控制它们的版本。下面的示例代码中的卡组字符串展示了卡组定义的语法,所有卡牌都使用4.1版本,除了风与自由,它使用4.0版本(因为它在3.7版本之后没有改变,当指定4.0版本时,卡组会自动选择3.7版本)。同时,也支持使用牌组分享码导入牌组。更多细节请参考server/deck.py

开始对局

  1. 初始化一个新的server.Match实例。
  2. 使用set_deck函数为玩家分配卡组。
  3. 如果需要,修改Match.config
  4. 卡组设置完成后,使用Match.start函数开始对局。它会根据配置和卡组初始化对局。如果出现错误(例如卡组不合法),它会返回False和具体错误信息。
  5. 使用Match.step函数推进对局。默认情况下,该函数会持续执行,直到对局结束或者生成需要响应的请求。

为了更方便的响应请求,在agents模块中项目包含了一些简单的代理。这些代理可以响应各种请求。特别的,InteractionAgent可以解析命令行并生成响应,使用命令行交互时较为方便。同时,该代理也是前端和后端交互时使用的代理。

示例代码

from lpsim import Match, Deck
from lpsim.agents import RandomAgent
deck_string = '''
default_version:4.1
character:Fischl
character:Mona
character:Nahida
Gambler's Earrings*2
Wine-Stained Tricorne*2
Vanarana
Timmie*2
Rana*2
Covenant of Rock
Wind and [email protected]
The Bestest Travel Companion!*2
Changing Shifts*2
Toss-Up
Strategize*2
I Haven't Lost Yet!*2
Leave It to Me!
Calx's Arts*2
Adeptus' Temptation*2
Lotus Flower Crisp*2
Mondstadt Hash Brown*2
Tandoori Roast Chicken
'''
deck0 = Deck.from_str(deck_string)
deck1 = Deck.from_str(deck_string)
match = Match()
match.set_deck([deck0, deck1])
match.start()
match.step()

agent_0 = RandomAgent(player_idx = 0)
agent_1 = RandomAgent(player_idx = 1)

while not match.is_game_end():
    if match.need_respond(0):
        match.respond(agent_0.generate_response(match))
    elif match.need_respond(1):
        match.respond(agent_1.generate_response(match))
    match.step()

print(f'winner is {match.winner}')

自定义角色和卡牌

自定义角色和卡牌前,你需要了解actions, event handlers和value modifiers。所有与对局的交互(一个实例需要修改对局中其他实例的状态)都是通过actions完成的,所有的actions都是由events触发的。value modifiers用来修改值,例如骰子消耗和伤害数值/类型。最简单的实现一个新的对象的方法是参考并复制一个已有的卡牌/角色/技能/状态...并修改它。你可以在细节中找到更多信息。

templates/character.py是一个角色的模板。你可以复制它并修改它来实现一个新的角色。你可以定义任何与角色相关的对象,例如技能、天赋、召唤、状态。然后,你需要为这些对象创建描述,描述将会在前端中使用,class registry会拒绝没有描述的对象。最后,使用register_class函数将所有对象以及它们的描述注册到class registry中,就可以在对局中使用它们了。

定义一个新的卡牌相对简单,你可以参考templates/card.py,它定义了一个新的卡牌“大心海”,它消耗2个任意骰子并抽3张牌。作为自定义卡牌的示例,在这个文件里使用了absolute import,因此可以在项目外直接使用。

你可以手动注册新的对象并在对局中使用它们。以“大心海”为例,首先安装lpsim,然后在import lpsim之后输入import templates.card。然后你可以通过a = HTTPServer(); a.run()创建一个HTTP服务器,你会发现修改卡组时一个新的卡牌被添加到了候选卡牌列表中。总代码如下,在项目根目录运行:

import lpsim
import templates.card
a = lpsim.HTTPServer()
a.run()

细节

使用Pydantic保存和加载对局状态,导出的数据可以用来恢复对局到某个状态并继续运行,也可以用来渲染前端的对局状态。

兼容不同版本的角色和卡牌。例如你可以开启一个3.8版本的双岩一斗和3.3版本的双岩剑鬼的对局,或者使用3.3的神宵和3.7的申鹤配合4.3的新行动牌和装备。

通过requestresponse来交互。当request列表不为空时,代理需要响应其中的一个请求。当多个玩家需要响应时(例如在游戏开始时选择角色和卡牌),它们的请求会同时生成。

对局中的所有修改都是通过action来实现的。每个action都会触发一个事件,并且可能会激活后续的action。这些新激活的action会被添加到现有的action列表的顶部,类似于堆栈列表的结构,参考EventFrame类的实现。

对局中所有的对象包含两种触发器:event handlers和value modifiers。事件处理器用来监控事件并产生响应的action列表。值修改器用来修改可变值并在必要时更新内部状态。可修改的值包括初始骰子颜色、伤害和消耗等。

所有的代码都使用pytest进行测试,覆盖率100%(除了防御性代码,它们被标记为# pragma: no cover)。由于完全兼容不同版本,当实现了新的版本时,所有已有测试都应该通过而不需要修改。

贡献

欢迎合作开发项目代码,但是目前没有详细的文档。在贡献代码前,您可以首先阅读CONTRIBUTING.md(英文),它包含了如何安装开发环境和如何运行测试的信息。

如果你想添加新的角色相关的对象(角色、技能、天赋、召唤、状态),请参考server/character/template.py和已经实现的角色。如果你想添加新的卡牌,请参考server/card中已经实现的卡牌。完成代码编写后使用register_class函数注册新的对象到模拟器中即可使用。

你可以通过QQ群945778865联系作者,咨询开发和使用上的问题,进群问题的答案是模拟器的中文名。

开发这个项目花费了大量(本来用来打牌和打模拟宇宙的)时间。如果你觉得这个项目有帮助,您可以通过微信支持作者。

wechat

backend's People

Contributors

zyr17 avatar xqm32 avatar dependabot[bot] avatar jiezichenku avatar

Stargazers

 avatar  avatar 255 avatar  avatar  avatar Perilla leaves avatar Aki avatar  avatar Summer907 avatar  avatar Hazel avatar JuntingSu avatar Yimeng Zeng avatar  avatar 龙之山河 avatar  avatar

Watchers

 avatar

backend's Issues

When calling value modifier, it can return actions

e.g., when damage increase triggered for usage objects, and their usage becomes 0, return remove object action, which will be done before creating objects.

TODO: dvalin's talent now use a more ugly implementation. need to be changed.

refactor value_modifiers

Not to return modified value, but return some other info, e.g. modify success? modified data info?

Improve logic with object trashbin

To perform some logic that may trigger after the object is removed, a trashbin is needed.
Some examples:

  • Dunyarzad will be removed when it is replaced by a companion, but after that a card draw will perform.
  • Riptide will move from defeated charactor to next active charactor.

A trashbin is created to collect all objects that is removed during the EventFrame chain. An object should
explicitly define event handlers that can trigger when it is in the trashbin. If no active eventframe in the queue,
trashbin will be cleared. Objects will keep its original position when moved into trashbin.

Boar Princess bugs

Boar princess will generate die for discarded talents because of charactor defeat; but not for talent replacement. Currently no die will be generated when talent is discarded. Need further check.

Memory consumption decrease

Try to decrease the memory for one match to serve more matchs in low-memory machines.
Main memory cost is on historie record, only record diff? May be an option, because only recording diff will cause lower performance in some actions (e.g. reset match to specific frame)

Add all system hooks by default

Instead of creating hooks when specified card is added (e.g. Ellin, Memento Lens), add all hooks regardless of whether this card exist in deck, to avoid bugs.

remove current desc from class definition, and support desc in backend

do not maintenance desc in object class; instead, give desc when registering the class, and utility to collect descs.

Also support define descs in a global file and pre-load before class registering. When a class is registered, it should contain
descs for its names and versions, or descs already in pre-loaded files. otherwise, raise error.

Performance increase

All methods to increase performance. May try the following methods:

  • use line-profiler to find where cost most time
  • use a registry to handle event_handlers and value_modifiers

Bug in cards printed during game that need prior knowledge

E.g., if Ellin is generated during match, it doesn't know what skill is used before.
Another situation is that when I Haven't Lost Yet is drawn by Liben, it will miss the chance to trigger ROUND_PREPARE event.

To solve above problems, for these cards we need to create a system event handler that will record such messages.

Bug of Fiery Sanctum Field

Damage decrease of Fiery Sanctum Field performs like team status (not always be last), not summon (e.g. frog), so need to generate a team status to perform damage decrease.

chat support

support real-time chat in the match

How crazy it is!

Support register custom cards to LPSim

  • 1. Change current class union structure to class registry structure
    • 1.1. Base classes as classifier, when an object is to register, find its parent classes, and register to corresponding classes
  • #116
  • 3. Support update desc patchs to frontend. When an card is added, its descs will be updated to it
  • 4. Remove descs from objects, or remove it when generating json and dict

Remove the import prefix `src.` from tests

Since we are using src layout in this project, we can use pip install . and then simply import files from lpsim module, rather than import from the src. But there still a problem that some test files import module with tests prefix. They can network properly with the pip install . method, so we should also modify them.

Build system refactor request

Hi @zyr17, I think it's better to use a modern package manager/build system to maintain this project. For python, Poetry or Hatch can be a good choice. I have some experience on Poetry and do some try to refactor build system for LPSim. Here is my refactored code, please help to check if this can work.

I have tested this refactor simply use poetry run python -m pytest and the sample random agent code with Python3.11 and Python3.12 on macOS.

To use poetry, you can follow the Poetry's documentation. I recommend to use official installer curl -sSL https://install.python-poetry.org | python3 -, but you can also use a standalone pipx install it if you prefer.

With poetry installed, run the following commands to install dependencies and create a virtual environment:

poetry install

You can use poetry run <SOME_COMMAND> to run commands in virtual environment. Also you can use poetry shell to activate an interactive virtual environment.

Related Links

when generating objects during making damage, no other actions can interrupt.

E.g., skills creating objects, elemental reactions creating objects. Like switch charactor, they are builtin in make_damage_action, and cannot be interruptted by other actions, e.g. charactor defeated, another make_damage_action, remove_object_action, etc.

Conterexample? Nilou E? Need to check every skills that create object.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.